Skip to content

Theme

Namespace: App\Infrastructure\Services\Theme

Method Description Type Parameters Return
__construct throws ContainerExceptionInterface
throws ReflectionException
throws NotFoundExceptionInterface|Exception
public
id Theme's id protected
name Theme's name protected
path The theme's directory path
protected string
route Theme's route for submenu protected
url Theme's url protected

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.

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, and Qubus\Security\Helpers\purify_html.
  • Check user permission before executing or saving data to prevent unauthorized operations or access.
  • Use the Devflow database helper (App\Shared\Helpers\dfdb) and prepared statements to avoid SQL injection vulnerabilities.

Step #1: Create Your Theme File

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 NewsWidget 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.
  • 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',
            '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 you main view, you can use the loop to load all content or content by content type:

    if(has_content()):
        while(the_content()) :
            //
            // Content here
            //
        endwhile;
    endif;
Check out theme functions that can be used in the loop: content_* or product_*.

Step #4: Share Your Theme

If we wanted to share your theme to allow others in the community to install it via composer, we would add a composer.json file to the root of our 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.3",
    "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:

  1. Make sure to change the vendor name
  2. Make sure to add the type devflow-theme
  3. Make sure to include installer-name and make it PSR-4 compatible. It will install the theme as MySite instead of as mysite.
  4. Make sure the installer-types includes devflow-theme

When someone runs composer require getdevflow/mysite, the theme will be installed with the correct folder name 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 {

    }
As an example, you can download the VaporChild Theme which is a child theme of Vapor.