If you are not interested in using Devflow as a headless CMS, you have the option of creating a theme. When creating a
theme, you can extend the abstract class Theme and implement the two abstract methods meta and handle.
The meta method returns an array of info about your theme, and the handle method is called by the system to load
assets, views, etc. The following 4 steps will walk you through creating your first theme.
Best Practices in Theme Development
Using Coding Standards
Devflow uses specific coding standards to help maintain consistency, quality, and clean code. The coding standard that Devflow uses and promotes is PSR-12 along with the Qubus Coding Standards.
Namespaces
Classes as well as function should be namespaced, unless there is a strong reason to not namespace a function.
Namespacing functions is recommended and highly encouraged in order to keep the global namespace clean and
available for native PHP functions.
Security
You must always validate and sanitize data on output. Never trust user data that was inputted. If you use the
native Devflow functions that output data, that data is already sanitized or purified. Keep these things in mind
when outputting data outside the native functions:
- Sanitize data on output by using helpers
Qubus\Security\Helpers\esc_html,Qubus\Security\Helpers\esc_html__,Qubus\Security\Helpers\esc_url,Qubus\Security\Helpers\esc_js, andQubus\Security\Helpers\purify_html. - Check user permission before executing or saving data to prevent unauthorized operations or access.
- Whenever possible, use (
Qubus\Expressive\Database) as a dependency and prepared statements to avoid SQL injection vulnerabilities.
Step #1: Create A Native Theme
The first step is to create a folder for your theme in the public/themes directory. Your directory must meet
PSR-4 autoload standards. For this example, we are going to create a My Site theme. The name of the new folder
will be MySite and the name of the main class will be the same followed by the suffix Theme.php: MySiteTheme.php.
MySiteTheme.php will extend the abstract class App\Infrastructure\Services\Theme. We should now have a new class:
<?php
declare(strict_types=1);
namespace Theme\MySite;
use App\Infrastructure\Services\Theme;
class MySiteTheme extends Theme
{
/**
* @inheritDoc
*/
public function meta(): array
{
// TODO: Implement meta() method.
}
/**
* @inheritDoc
*/
public function handle(): void
{
// TODO: Implement handle() method.
}
}
We need to fill out the meta method to include our theme's info:
name- The name of the theme.slug- The proper name of your theme with no spaces (PascalCase).id- Theme's unique identifier. This is also used for your route if you need to register a submenu.author- Person or company who authored the theme.version- Current version of the theme.description- A short description of the theme's purpose.basename- Filename of the theme.path- File path of the theme.url- Theme's directory url.themeUri- Where the theme is hosted and updates found.authorUri- Website of the theme author.className- Name of the class.screenshot- Preview image of the theme.
With the meta details filled out, this is now the state of our theme class:
<?php
declare(strict_types=1);
namespace Theme\MySite;
use App\Infrastructure\Services\Theme;
use App\Shared\Services\Registry;
use function App\Shared\Helpers\theme_root;
use function App\Shared\Helpers\theme_url;
use function basename;
use function dirname;
use function get_class;
use function Qubus\Security\Helpers\t__;
class MySiteTheme extends Theme
{
/**
* @inheritDoc
*/
public function meta(): array
{
$theme = [
'name' => t__(msgid: 'My Site Theme', domain: 'mysite'),
'id' => 'mysite',
'slug' => 'MySite',
'author' => 'Joshua Parker',
'version' => '1.0.0',
'description' => 'My Site theme.',
'basename' => basename(dirname(__FILE__)),
'path' => theme_root(__FILE__),
'url' => theme_url('', __CLASS__),
'themeUri' => 'https://github.com/getdevflow/mysite-theme',
'authorUri' => 'https://nomadicjosh.com/',
'className' => get_class($this),
'screenshot' => theme_url('MySite/screenshot.png'),
];
Registry::getInstance()->set('mysite', $theme;
return $theme;
}
/**
* @inheritDoc
*/
public function handle(): void
{
// TODO: Implement handle() method.
}
}
Now that the meta method is implemented, our theme should now be registered on our themes page.
Step #2: Create Other Methods (if needed)
You can create other methods as needed such as rendor for views. To get an idea, check out the Plugin guide
Step #3: The Loop
For your main view, you can use the loop to load all content or content by content type:
Check out theme functions that can be used in the loop:content_* or product_*.
Step #4: Share Your Theme
If you wanted to share your theme to allow others in the community to install it via composer, you need to
add a composer.json file to the root of your theme's directory:
{
"name": "getdevflow/mysite",
"description": "My Site theme.",
"type": "devflow-thee",
"keywords": ["devflow-theme","themes"],
"license": "GPL-2.0-only",
"authors": [
{
"name": "Joshua Parker",
"email": "joshua@joshuaparker.dev"
}
],
"require": {
"php": ">=8.4",
"oomphinc/composer-installers-extender": "^2.0"
},
"extra": {
"installer-name": "MySite",
"installer-types": ["devflow-theme"]
},
"minimum-stability": "stable",
"prefer-stable": true,
"config": {
"allow-plugins": {
"composer/installers": true,
"oomphinc/composer-installers-extender": true
}
}
}
There are several important key points to point out in the JSON data above:
- Make sure to change the second part of vendor name to match your theme
- Make sure to add the type
devflow-theme - Make sure to include
installer-nameand make it PSR-4 compatible. It will install the theme asMySiteinstead of asmysite. - Make sure the
installer-typesincludesdevflow-theme
When someone runs composer require getdevflow/mysite, the theme will be installed with the correct folder name
to meet PSR-4 standards: public/themes/MySite/.
There you go. These are the steps you can take to create a theme as well as how to share your new theme with the Devflow community.
Any theme added to Packagist with the above composer.json information, will appear on the Devflow extensions page of the main website.
Child Themes
If you need or want to customize a theme, you can create a child theme. If we were to create a child theme of the sample theme made previously,
we would create another directory named MySiteChild, and the main class will be named MySiteChildTheme, which will extend the class
of the main theme:
<?php
declare(strict_types=1);
namespace Theme\MySiteChild;
use Theme\MySite\MySiteTheme;
final class MySiteChildTheme extends MySiteTheme {
}
Create a Page Builder Theme
As stated above, you can create a regular theme for your site or your client's site, but you can also create a theme that is integrated with the page builder.
Note
You cannot create child themes from page builder themes. You must duplicate the theme and change its name if you want to add your own edits without it being destroyed by an update.
By integrating the page builder into your theme, it allows you to create custom page layouts using a drag-and-drop interface. By following the steps above, page builder themes will also appear on the themes screen where you can activate the theme.
The Bootstrap Business theme is a page builder theme that you can install via composer. Once you install the theme, duplicate and rename it so that you can edit it if the need arises. For more information check out the Vihzhuo documentation and video demonstration.
Dynamic Themes
A demo theme is included when you install Devflow CMF. If you plan to create multiple subdomain sites,
open ./config/vihzhuo.php and replace the active_theme value with \App\Infrastructure\Services\Vihzhuo\VihzhuoTheme::activeTheme(themeName: 'Demo').