Festi Theme
The Festi Framework Theme package is designed for projects that have a frontend component. It allows developers to structure and manage their project's themes efficiently, offering flexibility and modularity in how layouts, styles, and UI components are handled.
The following sections will provide details on the structure, available events, UI components, and how to test the theme functionality.
Theme Structure
The theme is typically stored in the following directory: project_directory/themes/[ThemeName]
.
main.phtml
- The main layout file. The scope of this file is a class that implements theITheme
interface. By default, the class used isDefaultTheme
. You can extendDefaultTheme
by creating a custom theme class and placing it in the main theme folder asTheme.php
:class Theme extends DefaultTheme { }
head.phtml
- This file defines the content that will be included in the<head>
section. Here are some common variables:jsVersion
-js_version
from the settings tablesiteCaption
-site_caption
from the settings tablehost
-host
from the settings tablecss
- A directory where all the theme-specific CSS files are stored.js
- A directory where all JavaScript files for the theme are stored.templates
- A directory containing the PHTML templates used by the theme.Theme.php
- (Optional) This file allows you to extend the default theme class. You can implement custom logic or override the default behavior of theDefaultTheme
class.tests
- A directory for unit tests related to the theme. This is where you can write automated tests to ensure the functionality of the theme works as expected.
Theme Class
By default, the DefaultTheme
class is used for theme functionality. If you want to add custom logic or override the existing behavior, you need to create a Theme.php
file in the root of your theme directory. Inside this file, you will define a Theme
class that either implements the ITheme
interface or extends the DefaultTheme
class.
If you want to create a theme class with a different name (e.g.,
YourThemeClass
), you must return that class at the end of theTheme.php
file:
class YourThemeClass extends DefaultTheme
{
public const EVENT_THEME_HEADER_CONTENT_RIGHT = 'ThemeHeaderContentRight';
public function fetchRightHeaderContent(): string
{
$list = $this->doThemeEvent(static::EVENT_THEME_HEADER_CONTENT_RIGHT);
return join('', $list);
}
}
return YourThemeClass::class;
Theme-Triggered Events
The theme triggers several events that allow for dynamic content injection in specific areas, such as the header or sidebar. You can listen for these events and use them to customize various parts of the theme.
ThemeHeaderUserActivity
This event is triggered when rendering the user activity block in the header, right next to the logo.
Example of attaching an event listener:
$core->addEventListener(
"ThemeHeaderUserActivity",
array(&$core->getPluginInstance('Notifications'), 'onFetchUserActivity')
);
In the NotificationsPlugin
, you can handle this event and return a fetched template:
<?php
class NotificationsPlugin extends DisplayPlugin
{
public function onFetchUserActivity(FestiEvent &$event)
{
$search = array(
'id_user' => $this->getUserID(),
'status' => 'new'
);
$this->notifications = $this->object->get($search);
return $this->fetch('notifications.phtml');
}
}
The results returned by all event listeners are concatenated and rendered in the appropriate location.
ThemeHeaderProjectsList
Triggered when rendering the project list block in the header, right next to ThemeHeaderUserActivity
.
Example of attaching an event listener:
$core->addEventListener(
"ThemeHeaderProjectsList",
array(&$systemPlugin, 'onThemeHeaderProjectsList')
);
ThemeFetchMenu
This event is triggered before rendering the left menu. If a value is returned by the event listener, the default menu will not be displayed.
$core->addEventListener(
"ThemeFetchMenu",
array(&$systemPlugin, 'onThemeFetchMenu')
);
ThemeFetchGoogleAnalytics
This event is triggered before rendering the Google Analytics code. If a value is returned by the event listener, the default Google Analytics code will not be displayed.
$core->addEventListener(
"ThemeFetchGoogleAnalytics",
array(&$systemPlugin, 'onThemeFetchGoogleAnalytics')
);
ThemeHeadBottom
Triggered before the </head>
tag is closed. You can use this event to inject additional code into the head section.
$core->addEventListener(
'ThemeHeadBottom',
array(&$chatraPlugin, 'onThemeHeadAddChat')
);
Example of adding a Google Snippet Tag in the head section:
$this->core->addEventListener(
ITheme::EVENT_THEME_HEAD_BOTTOM,
function (ThemeEvent &$event) {
return $this->fetch('snippet_code_submit.phtml');
}
);
Custom Theme Events
You can also trigger your own custom theme events:
echo $this->doThemeEvent('ThemeHeaderProjectsList');
ISystemPlugin::EVENT_ON_PREPARE_MENU_ITEMS
The ISystemPlugin::EVENT_ON_PREPARE_MENU_ITEMS
allow you to override menu items. You could subscribe to the event
throw the core or the system plugin.
Target Items:
currentItem
- current urlname
- menu nameitems
- array of menu itemsactiveItem
- name of current active item
ISEODataProvider::EVENT_TITLE
The ISEODataProvider::EVENT_TITLE event allows you to override the title of a page dynamically within your theme or project. This event can be subscribed to in order to modify the default title that would otherwise be displayed.
Target Items:
title
- the title of the page
Example:
use core\theme\seo\ISEODataProvider;
$this->core->addEventListener(ISEODataProvider::EVENT_TITLE, function(ThemeEvent &$event) use ($data) {
$event->target['title'] = $data['meta_title'];
});
ISEODataProvider::EVENT_DESCRIPTION
See ISEODataProvider::EVENT_TITLE
ISEODataProvider::EVENT_KEYWORDS
See ISEODataProvider::EVENT_TITLE
Unit Test for a Theme
Unit testing a theme helps ensure that the theme behaves as expected when interacting with events, rendering content, and applying custom logic. Below is a sample unit test that verifies if content is correctly injected into the right section of the header using the Theme::EVENT_THEME_HEADER_CONTENT_RIGHT
event.
class HeaderThemeTest extends ThemeTestCase
{
public function testAddContentRight(): void
{
$testContent = 'testAddContentRight';
$this->core->addEventListener(
Theme::EVENT_THEME_HEADER_CONTENT_RIGHT,
function (FestiEvent &$event) use ($testContent) {
return $testContent;
}
);
$content = '';
$displayPlugin = new DisplayPlugin();
$result = $displayPlugin->fetchMain($content);
$this->assertTrue(is_int(strpos($result, $testContent)));
}
}
How to Work with SEO
In the Festi Framework, you have multiple ways to manage and modify SEO data such as titles, descriptions, and keywords. This can be done through the core's seo
array, by using events, or by extending the DisplayPlugin
class to handle SEO data more dynamically.
Here’s how you can work with SEO data:
- Set SEO Data in Core: You can define SEO attributes like title, description, keywords, og:type, and og:image by assigning them to the core's seo array:
$this->core->seo = array( 'title' => $data['meta_title'], // Meta title of the page 'description' => $data['meta_description'], // Meta description of the page 'keywords' => $data['meta_keywords'], // Meta keywords for SEO 'type' => $data['og_type'], // Open Graph type (e.g., article, website) 'image' => $data['og_image'] // Open Graph image (for social media sharing) );
- Override SEO Title Using Event: If you need to dynamically change the title (or any other SEO attributes) based on certain conditions or logic, you can listen to the
ISEODataProvider::EVENT_TITLE
event and modify the title:$this->core->addEventListener(ISEODataProvider::EVENT_TITLE, function(ThemeEvent &$event) use ($data) { // Overriding the page title $event->target['title'] = $data['meta_title']; });
- Override
onMeta()
in DisplayPlugin: If your plugin extends theDisplayPlugin
, you can override theonMeta()
method to further customize or extend SEO functionality. This method allows you to modify the seo data and merge it with other fields if needed.protected function onMeta(array &$seo): void { // If SEO data exists in core, use it if (isset($this->core->seo)) { $seo = $this->core->seo; } // Define additional meta fields $metaFields = array( 'title' => Entity::FIELD_TYPE_STRING_NULL, 'description' => Entity::FIELD_TYPE_STRING_NULL, 'keywords' => Entity::FIELD_TYPE_STRING_NULL, 'image_src' => Entity::FIELD_TYPE_STRING_NULL ); // Merge and extend existing SEO data with additional fields $seo = $this->getExtendData($seo, $metaFields); }