Add a custom Theme-App to RedKite CMS

This chapter explains how to create a new theme for the RedKite CMS.

What is a Theme?

A RedKite CMS Theme Application could be defined as a collection of twig templates which have their own assets like javascripts, stylesheets and images, packaged into a well-known structure.

How is a Theme-App structured?

A Theme-App is a standalone Symfony2 bundle. Using this approach has several advantages:

  1. It is a Symfony2 Bundle
  2. It is reusable in many web sites
  3. Assets required by the content are packed into a well known structure

Create the FancyThemeBundle

RedKite CMS has two built-in commands which help to manage a theme:

  • redkitecms:generate:app-theme
  • redkitecms:generate:templates

The first command generates a new App-Theme Bundle, the second one generates the templates configuration files.

To start a new theme, you must run the redkitecms:generate:app-theme command from your console.

This command extends the Symfony’s generate:bundle command, so the process should be familiar. Run the following command to start:

php app/rkconsole redkitecms:generate:app-theme --env=rkcms

You’ll get the following response:

Welcome to the Symfony2 bundle generator

[...]

Bundle namespace:

Answer as follows:

Bundle namespace: RedKiteCms/Theme/FancyThemeBundle

The proposed bundle name must be changed to FancyThemeBundle otherwise you could have issues later:

Bundle name [RedKiteCmsThemeFancyThemeBundle]: FancyThemeBundle

The following options could be left as default values, but you can also change them to fit your needs if you want to.

Do not let Symfony2 update the AppKernel for you, because RedKite CMS will autoload the theme for you.

Finally, you must clear the cache to have the theme auto loaded:

php app/rkconsole ca:c --env=rkcms

Sometimes it might not be enough to do this, and the theme might not be correctly displayed inside of the RedKite CMS themes panel. When that happens you must manually remove the app/cache folder.

Note

When you are implementing a new theme, you should work in the rkcms_dev environment due to templates and assets being regenerated by the framework, otherwise you will have to clear the cache and to run assetic:dump commands continuously.

Note

The new theme will only be available after you have configured your templates and executed the redkitecms:generate:templates FancyThemeBundle command. Read on.

Add the twig templates

When the theme is created, you must start to add your twig templates to the theme bundle.

The generate:app-theme command, added a new Theme folder under the Resources/views folder of your App-Theme bundle: your templates must be placed inside that folder.

The Theme folder structure

The Theme folder could be given the following basic structure:

views
    Theme
        home.html.twig
        internal.html.twig

This theme has two templates: the home and the internal. This structure will definitely work, but a real world example would probably look like the following:

Theme
    base
        base.html.twig
    home.html.twig
    internal.html.twig

A base template is added into a sub-folder. This file should contain the common parts of the website’s layout, while the other two templates will inherit from the base.html.twig file.

The themes configuration generated from that structure consists of two templates and three slots configuration files. In fact the files saved into the themes root folder become a template file, while a slot file is generated for all the templates, plus one named base.xml. This last file contains the common slots.

Don’t worry about the generation process for now, because it is explained in greater detail in the next paragraphs.

You might need to add more separations to the templates, so your theme structure could look like the following:

Theme
    base
        base.html.twig
    support
        template_a.html.twig
        template_b.html.twig
    home.html.twig
    internal.html.twig
    internal_1.html.twig

In this case the home template inherits from the template_a.html.twig and the other internal templates from the template_b.html.twig. The templates inside the support folder inherit from the base.html.twig template.

In this case if the support templates contain repeated slots, these are merged with those found into the base.html.twig and all of them are saved into the base.xml configuration file.

The design

RedKite CMS uses twig as its template engine, so when you have converted the templates to html from your design, you must then adapt them to twig.

Clean the template

First of all, the templates do not need the header section since it is inherited by the base twig template provided by the CMS, or from another custom one.

Lets suppose your template looks like this one:

<!DOCTYPE html>
<html>
    <head>
        <title></title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <link href="stylesheets/screen.css" media="screen, projection" rel="stylesheet" type="text/css" />
        <link rel="stylesheet" href="stylesheets/960.css" />
    </head>
    <body>
        <div id="header">
            <div id="logo"><img src="" /></div>
        </div>
        <div id="contents">
            <h1>My title</h1>
            <p>Lorem ipsum...</p>
        </div>
        <div id="footer">
            <p>Lorem ipsum...</p>
        </div>
    </body>
</html>

you must only save the following code:

<div id="header">
    <div id="logo">
        <a href="#"><img src="images/logo.png" title="Download RedKite CMS" alt="" /></a>
    </div>
</div>
<div id="contents">
    <h1>My title</h1>
    <p>Lorem ipsum...</p>
</div>
<div id="footer">
    <p>Lorem ipsum...</p>
</div>

and save it into a twig template.

The twig template

Create a new twig template file called home.html.twig under the Resources/views/Theme folder. Open it and add the following code:

{% extends base_template %}

{% block body %}
{% endblock %}

The template must extend the template defined by the ThemeEngineBundle’s base_template parameter. This template must have a body block where the contents saved from the html template you are creating must be placed:

{% block body %}
    <div id="header">
        <div id="logo">
            <a href="#"><img src="images/logo.png" title="Download RedKite CMS" alt="" /></a>
        </div>
    </div>
    <div id="contents">
        <h1>My title</h1>
        <p>Lorem ipsum...</p>
    </div>
    <div id="footer">
        <p>Lorem ipsum...</p>
    </div>
{% endblock %}

You can easily change this template just by defining a new parameter in both config.yml and config_rkcms.yml:

red_kite_labs_theme_engine:
    # ...
    base_template: MyAwesomeBundle:Theme:my-base.html.twig

this because RedKite CMS does not inherit its configuration from Symfony2 configuration.

Note

When you redefine the base template, be sure to redefine all the sections defined into the one that comes with RedKite CMS.

The slots

Now you must identify the slots on the template. A slot is an html tag that contains the content you want to edit. Each content contained inside a slot is saved into a Block. Look at the following code taken from the original template:

<div id="header">
    <div id="logo">
        <a href="#"><img src="images/logo.png" title="Download RedKite CMS" alt="" /></a>
    </div>
</div>
[...]

The content we will edit with RedKite CMS is the one contained inside the logo div. This content must be replaced as follows:

<div id="header">
    <div id="logo">
        {{ block('logo') }}
    </div>
</div>
[...]

Here we have declared a new block called logo

This block must be declared inside a file which contains all the template’s slots.

The html id attribute assigned to the slot is not mandatory. So you can call it if you wish. But it is the best practice to name the slots id and the slot name in the same way.

Another best practice to follow is to use the renderSlot function inside a div tag. So avoid to write something like this:

<p id="logo">
    {{ renderSlot('logo') }}
</p>

The slot file

Add a new Slots folder under the Resources/views folder and create a new slots.html.twig template inside it. Open that file and add the following code inside of it:

{% block logo %}
    {{ renderSlot('logo') }}
{% endblock %}

We have defined the logo block called in the template. This block contains a RedKite CMS built-in twig function called renderSlot, which renders all the blocks contained into a slot.

This function requires the name of the slot passed as a string as argument. While it is not mandatory, the slot name should be the same as that of the block.

That instruction in not enough to correctly define your slot. You must also define some attributes for the slot.

Define the slot attributes

You must define some attributes for the slot, simply adding a twig comment just below the renderSlot statement:

{% block logo %}
    {# BEGIN-SLOT
        name: logo
        repeated: site
        htmlContent: |
            <a href="#"><img src="images/logo.png" title="Download RedKite CMS" alt="" /></a>
    END-SLOT #}
    {{ renderSlot('logo') }}
{% endblock %}

This section requires a careful explanation. Each attribute section must start with the BEGIN-SLOT directive and it must be closed by the END-SLOT directive.

Attributes must be written in valid yml syntax. Yml requires a perfect indentation, so the first line defines the indentation for the other attributes:

{# BEGIN-SLOT
    name: logo
      repeated: site
    htmlContent: |
        <a href="#"><img src="images/logo.png" title="Download RedKite CMS" alt="" /></a>
END-SLOT #}

The code above will return an error because the second attribute has a wrong indentation. When this happens, the section is skipped and the service is not instantiated.

The name option is mandatory and if it is omitted, RedKite CMS will skip the slot.

Additional optional arguments

You can define some other attributes in addition to name option:

  1. blockType
  2. htmlContent
  3. repeated
  4. blockDefinition

The blockType option

It defines the block type that the RedKite CMS must add for that slot when a new page is added. By default, the block type added is Text.

The htmlContent option

The htmlContent option overrides the default content added by the block, so when you want to use the default value, simply don’t declare this option.

The blockDefinition option (Since RedKite CMS 1.1.2)

The blockDefinition option overrides the values of the Block’s properties. For example an Image block is defined by the following json structure;

{
    "0" : {
        "src": "",
        "data_src": "holder.js/260x180",
        "title" : "%s",
        "alt" : "%s".
        "class" : ""
    }
}

To change the value of some properties, you can define the blockDefinition attribute as follows:

blockDefinition:
    0:
        data_src: holder.js/700x250
        class: img-responsive img-home-portfolio

You can change the definition for a more complex Block, defining how included blocks must be initialized. Here’s a definition for a BootstrapNavbarBlock:

blockDefinition:
    inverted: navbar-inverse
    items:
        0:
            blockType: BootstrapNavbarMenuBlock
            alignment: navbar-right
            items:
                0:
                    blockType: Link
                    0:
                        value: About
                1:
                    blockType: Link
                    0:
                        value: Services
                2:
                    blockType: Link
                    0:
                        value: Contact

The repeated option

Most of the contents displayed on a web page are repeated through the website pages. For example the site logo is usually the same for all the site’s pages, while a navigation menu can be the same for a specific language.

The repeated option manages this behaviour and repeats the content for the blocks that live on a slot. The possible values for this option are:

  1. page (default)
  2. language
  3. site

When this argument is not declared, a block repeated at page level is added.

None of them is required, but when you don’t need to specify any attribute however, you must be sure to define this section:

{# BEGIN-SLOT
    name: logo
END-SLOT #}

Use the slots file

You need to include the slots file inside your template to have the slots available. This operation is achieved adding a use statement just under the extend statement:

{% extends base_template %}

{% use 'FancyThemeBundle:Slots:slots.html.twig' %}

{% block body %}
    <div id="header">
        <div id="logo">
            {{ block('logo') }}
        </div>
    </div>
    [...]
{% endblock %}

Define the template assets

Each template comes with one or more external assets, like javascript and stylesheet files, which must be added to the template adapted to work with RedKite CMS.

The base layout used to render each page provides several sections which can be extended in a template to add extra assets to the page.

There is a cookbook entry which covers this topic in detail.

Create the templates

When your templates are ready, you may run the command which creates the services in the Dependency Injector Container:

redkitecms:generate:templates FancyThemeBundle --env=rkcms

This command will generate the config files that define the theme’s templates and their slots. If something goes wrong, a notice is displayed.

Overriding a template

To override the template of an existing theme, you must create a new folder named with the theme you want to use, for example AwesomeThemeBundle, under the app/Resources/views folder of your application, than add a new template under that folder, called as the one you want to override, for example home.twig.html.

Open that template and add the following code:

// app/Resources/views/AwesomeThemeBundle/home.html.twig
{% extends 'AwesomeThemeBundle:Theme:home.html.twig' %}

{% block logo %}
    {{ block('new_logo') }}
{% endblock %}

This code overrides the AwesomeThemeBundle’s home.html.twig template, replacing the logo slot with the contents saved in the new_logo slot.

Found a typo ? Something is wrong in this documentation ? Just fork and edit it !

Fork me on GitHub