Themes

Did you create a beautiful theme for forumify and want to share or sell it on the marketplace? Then you'll have to create a theme plugin.

Dissection of a theme:

my-cool-theme
  /public
  /src/MyCoolTheme.php
  /templates
  /composer.json

Just like plugins, themes are also managed by composer to apply versioning and dependency constraints.

Basic theme composer.json (can be partially generated by running composer init in an empty directory):

/composer.json

{
    "name": "acme-corporation/cool-theme",
    "type": "forumify-theme",
    "autoload": {
        "psr-4": {
            "AcmeCorporation\\": "src/"
        }
    },
    "extra": {
        "forumify-plugin-class": "AcmeCorporation\\CoolTheme"
    }
}
  • name: The vendor and name for your theme, in the form of vendor/name.
  • type: Always forumify-theme for themes.
  • autoload.psr-4: Root PHP namespace definition, using the PSR-4 standard, this should be your vendor name in UpperCamelCase.
  • extra.forumify-plugin-class: Themes are an abstraction of a plugin, so we pick the theme configuration class as plugin class.

Version constraints on forumify aren't as necessary on themes as they are on plugins. A lot less can break with a theme. It is recommended to set at least forumify's major version as a requirement. When forumify updates to a new major, you can always loosen the constraint then. For example if your theme requires at least version 1 of forumify:

/composer.json

{
    // ...
    "requires": {
        "forumify/forumify-platform": ">=1.0"
    }
}

The theme class is used to provide more metadata, declare overridable variables and the location of assets that should be loaded by default.

/src/CoolTheme.php

<?php

namespace AcmeCorporation;

use Forumify\Plugin\AbstractForumifyTheme;
use Forumify\Plugin\PluginMetadata;
use Forumify\Plugin\ThemeConfig;
use Forumify\Plugin\ThemeVar;
use Forumify\Plugin\ThemeVarType;

class CoolTheme extends AbstractForumifyTheme
{
    /**
     * Basic information about your theme.
     */
    public function getPluginMetadata(): PluginMetadata
    {
        return new PluginMetadata(
            'My Cool Theme',
            'ACME Corporation',
            'A very stylish theme that allows users to recolor their header.'
        );
    }

    /**
     * An array of stylesheets that have to be loaded on every page.
     * These files must exist in the /public folder.
     */
    public function getStylesheets(): array
    {
        return ['style.css'];
    }

    /**
     * The theme's configuration which will allow users to override theme parameters.
     * You should add as many variables as possible to allow for maximum customization by the user.
     * Keys are injected into the document as CSS variables
     * Value priority is as follows:
     *      In dark mode: User Config > Dark Default > Default
     *      In light mode: User Config > Default
     */
    public function getThemeConfig(): ThemeConfig
    {
        return new ThemeConfig(
            hasDarkVariant: true,
            vars: [
                new ThemeVar(
                    key: 'c-header-color',
                    label: 'Header Color',
                    type: ThemeVarType::Color,
                    defaultValue: 'orange',
                    defaultDarkValue: 'darkorange'
                ),
            ]
        );
    }
}

Themes have the ability to override core templates, as well as plugin templates. The top level directory inside templates must match Forumify for core templates, or the name of the plugin class for plugins, for example AcmePlugin. For example:

templates/Forumify/frontend/base.html.twig

It is good practice to extend the original template, only override the blocks that you wish to customize, and use parent() to keep the original content in place. That way your theme is less likely to break in future updates of the platform or plugin you are customizing. You can extend the original template by using the @! prefix.

For example to add a sidebar to the forum list template: /templates/Forumify/frontend/forum/list.html.twig

{% extends '@!Forumify/frontend/forum/list.html.twig' %}
{% block body %}
    <div class="flex gap-4">
        <div class="w-80">
            {{ parent() }}
        </div>
        <div class="w-20">
            I am a sidebar!
        </div>
    </div>
{% endblock %}

At the time of writing this guide the ability to override templates is still new. This means that until recently all templates have been built without this feature in mind, which results in many old templates not containing any blocks for you to override.

If you need additional blocks inside any template, you can add these to the original template and submit a pull request to the platform repository.

Static resources such as CSS stylesheets, images, fonts,... should be placed in the /public directory. When forumify refreshes your theme, for example during initial installation or when updating, it will copy your public directory into the user's /public/themes/<vendor>/<package> directory.

For example, using the variable we defined in our configuration:

/public/style.css

.header {
    background-color: var(--c-header-color);
}

You can also use asset builders to enable sass/scss, the general convention is to place source assets in the /assets directory. The output of your builder must be set to /public. Just be aware that anything outside of the public directory will not be copied into userland!

To test your theme, we'll symlink it into our development instance of forumify. Assuming the following directory structure:

/forumify
/cool-theme

Modify your instance's (not the theme's!) composer.json:

/forumify/composer.json

{
    // ...
    "repositories": [
        {
            "type": "path",
            "url": "../cool-theme"
        }
    ]
}

Now install your theme using composer:

/forumify

$ composer install acme-corporation/cool-theme

The theme should automatically be added in your instance's admin panel under Settings -> Themes. If you've followed the code samples above, and you activate the theme, you should also be able to change the header menu color straight from the admin panel.

Theme discovery happens during the forumify:plugins:refresh command that is automatically executed after installing or updating dependencies with composer. If it is not automatically added, you can try running the command manually: php bin/console forumify:plugins:refresh.

Right now the only way to share your plugins and themes is by creating a public git repository and exposing it as a composer package through Packagist. In the future this functionality may be dropped in favor of an in-app marketplace where you can privately publish your plugins/themes and optionally monetize them as well.