How to override component partials with October CMS

How to override component partials with October CMS

Within October CMS it is easy to override partials twig content within a component of a plugin. In this article I will show you how that is done including the tricky parts and how to avoid them.

Within October CMS it is easy to override partial, page or layout twig files that are within a component of a plugin. In this article I will show you how to do that and also show the tricky parts and how to avoid them.

Services plugin

We assume a plugin with a component that presents cards with services (see also the frontpage of this website).

In the sample above we have 3 blocks with services. In the backend this looks like this:

With corresponding:

<div class="col-12 col-sm-4 pl-2 pr-2">
    {% component 'apps' %}
</div> 
<div class="col-12 col-sm-4 pl-2 pr-2">
    {% component 'frameworks' %}
</div> 
<div class="col-12 col-sm-4 pl-2 pr-2">
    {% component 'plugins' %}
</div>  

All three have the same base component Service Single, but all have an unique alias ('plugins', 'frameworks', 'apps').

Definition of component within the plugin

Let's assume that the plugin can be found in plugins\enovision\services and that the component contents are:

  • components\Single.php
  • components\single\default.htm

In the plugin the component is defined as following:

public function registerComponents()
{
    return [
        'Enovision\Services\Components\Single' => 'serviceSingle'
    ];
}

This means as much that the default unique alias for this component is: serviceSingle and that it relates to the Single.php component class.

The override (when only one unique alias)

First let's start easy. Assume you have defined a single instance of a component with an alias of 'serviceSingle' in our partial, page or layout.

Original (in the plugins folder under \components\single\default.htm)

{% set service = __SELF__.service %}

<div class="card text-center super-charger">
    <div id="block-card-apps" class="card-block p-3">
        <div class="icon sencha-color-dark pb-3">
            <i class="{{ service.icon }}  fa-3x"></i>
        </div>
        <h3 class="card-title">{{ service.title }}</h3>
        <p class="card-text">{{ service.slogan }}</p>
        <a href="{{ service.url|staticPage }}{% if service.anchor|length %}#{{ service.anchor }}{% endif %}" title="Read more" class="read-more">
            {{ __SELF__.lang.read_more }}
            <i class="fas fa-angle-double-right ml-2"></i>
        </a>
    </div>
</div>

Required override (in the folder \themes\\partials\serviceSinge\default.htm)

{% set service = _service.service %}
{% set pattern = _service.pattern|default(false) %}

<div class="card text-center {% if pattern %}card-pattern{% endif %}">
    <div id="block-card-apps" class="card-block p-3">
        <div class="icon sencha-color-dark pb-3">
            <i class="{{ service.icon }}  fa-3x"></i>
        </div>
        <h3 class="card-title">{{ service.title }}</h3>
        <p class="card-text">{{ service.slogan }}</p>
        <a href="{{ service.url|staticPage }}{% if service.anchor|length %}#{{ service.anchor }}{% endif %}" title="Read more" class="read-more">
            {{ _service.lang.read_more }}
            <i class="fas fa-angle-double-right ml-2"></i>
        </a>
    </div>
</div>

They are almost the same, only the original has a class 'supercharger' and we need a conditional class 'card-pattern'.

Important
We don't make the changes in the plugin itself, for it would be possible that with the next update it will have an overwrite by the developer of the plugin.

Now the tricky part

In our situation we have the same component 3 times in the same twig file and since a component must have an unique identifier (alias) within a partial, page or layout, we end up with 3 different aliases for 3 presentations of the same component.

[serviceSingle plugins]
key = "plugin"
pattern = 1

[serviceSingle frameworks]
key = "frameworks"

[serviceSingle apps]
key = "applications"

If we don't do anything and have just the \themes\<yourtheme>\partials\serviceSinge\default.htm it will not do any override. The override is only done on the actual alias used (apps, plugins, frameworks).

That's another fine mess you have gotten me into, how to make that work?

Keep the files as described earlier and add for every alias the following file named \themes\<yourtheme>\partials\plugins\default.htm: (do this for frameworks and apps as well)

{% partial 'serviceSingle/default.htm' %}

Now that becomes a real mess, doesn't it?

Some good advice
Avoid having the same component with different aliases within the same partial, page or layout. Instead make a seperate partial to isolate the component from the partial where it has more occurences.

This is the better way to avoid trouble

Make a small adjustment in the \themes\<yourtheme>\partials\serviceSinge\default.htm file:

{% set service = __SELF__.service %}

becomes:

{% set service = _service.service %}

The layout where the component was present 3 times we change to:

<div class="col-12 col-sm-4 pl-2 pr-2">
    {% partial 'serviceSingle/default.htm' _service=apps %}
</div> 
<div class="col-12 col-sm-4 pl-2 pr-2">
    {% partial 'serviceSingle/default.htm' _service=frameworks %}
</div> 
<div class="col-12 col-sm-4 pl-2 pr-2">
    {% partial 'serviceSingle/default.htm' _service=plugins %}
</div>

As you can see we have removed the component reference, although the components are still added to this page as it was before. What we do instead is passing the result as a variable to a partial.

End result

More from same category