Submitted by chrishu on Fri, 05/29/2015 - 18:16

Introduction

After my initial theming experiment I know that theming Drupal 8 is going to be more flexible than its' predecessors however the path of least resistance for overriding a template is still to make a complete new copy and alter the bits you wish to change or make additions, which may for example in the case of nodes result in a number of node templates for different content types, all repeating large chunks of template code. Swift theme-wide changes become increasingly difficult or error prone.

One solution in the past has been the provision of base themes that have a lot of theme settings, providing a level of flexibility via the theme configuration around a grid system or underlying html framework. This approach requires the themer to learn how to work with the theme. Another solution is to get a level of flexibility from various contrib. modules that radically alter content layout in Drupal (Panels being a major example) again shifting layout flexibility to configuration and UI.

I had a brief love-hate relationship with the Omega theme whilst still based around a 960 grid, but have not experienced it since version 4 when apparently it moves to "configuration through code rather than user interface". I have recently be working on a bunch of highly related sites relying heavily on Panels and a customised version of Panels Bootstrap Layouts. There are many approaches and philosophies to themeing Drupal, and 'Drupal Themer' is a job description in some organisations that have "Front-end Developer" as a job title for people doing front-end and themeing work that is not Drupal (a recurring theme) .

The beauty of Drupal 8 is that Twig template engine is provided in its' full glory, so we are free to use it as we see fit, it is possible to create base themes that provide a huge amount of flexibility almost entirely via working with the templates. Perhaps even base themes that allow themers to use similar working practices across other CMS or Frameworks using Twig or Twig like theme engines.

Twig Blocks

I am only going to briefly examine one Twig technique that I have been playing with here, Twig Blocks which are used via extends. The best way to learn about Twig blocks is to read the documentation that I have just linked to, if you carry on reading here though a couple of example I will give wil provide a general overview, particularly where they apply to Drupal.

Crucially Twig blocks are defined in a parent template to be populated and/or overriden in a child template and at the time of writing only one Twig template in Drupal 8 core defines a Twig block and that is block.html.twigNOTE: the name clash here is entirely coincidental Twig blocks are not related to Drupal blocks in any direct way.

In Drupal at the moment

The current (at time of writing) core block.html.twig:

<div{{ attributes }}>
  {{ title_prefix }}
  {% if label %}
    <h2{{ title_attributes }}>{{ label }}</h2>
  {% endif %}
  {{ title_suffix }}
  {% block content %}
    {{ content }}
  {% endblock %}
</div>

Notice the block content element highlighted in orange, in this template it does nothing to final output, but it serves to mark a section (block) that may be overridden by a child template. For the last time a reminder despite the unfortunate name clash and the only core template where they are used Twig Blocks are not Drupal Blocks.

And to see why a Twig Block made it into Drupal core take a look at block--system-branding-block.html.twig:

{% extends "block.html.twig" %}

{% block content %}
  {% if site_logo %}
    <a href="{{ url('<front>') }}" title="{{ 'Home'|t }}" rel="home">
      <img src="{{ site_logo }}" alt="{{ 'Home'|t }}" />
    </a>
  {% endif %}
  {% if site_name %}
    <div>
      <a href="{{ url('<front>') }}" title="{{ 'Home'|t }}" rel="home">{{ site_name }}</a>
    </div>
  {% endif %}
  {% if site_slogan %}
    <div>{{ site_slogan }}</div>
  {% endif %}
{% endblock %}

In Drupal 8 a lot more page elements are displayed in blocks which give Site Builders more flexibility but also would normally result in a lot of repeated code in the various block templates. In this case all this extra code in the branding block replaces the single content section in the original block template without repeating any of the rest of the block.html.twig template.

Taking it further

If you want to use Twig Blocks based on the Drupal 8 core templates you are currently restricted to just replacing the content section of the block template.  To really play with Twig blocks and develop a block based frontend workflow you are going to need to override core templates with versions that contain Twig blocks and then extend these further.

My play theme for this at the moment is Sinatra, and currently this is the base theme for the theme I am using for this site. Note that both Sinatra and bootrun (the theme for this site) are play and experimentation, Sinatra may develop into a more serious attempt at a blockified, stripped base theme though, the branches are liitle carzy at the moment also whilst I figure out what works with head D8 and the beta 7 version I am running here.

In Sinatra the version of block.twig.html is as follows:

{% block block_full %}
<div{{ attributes }}>

  {% block full_title %}
    {{ title_prefix }}
      {% block label %}
        {% if label %}
          <h2{{ title_attributes }}>{{ label }}</h2>
        {% endif %}
      {% endblock label %}
    {{ title_suffix }}
  {% endblock full_title %}
  
  {% block content %}
    {{ content }}
  {% endblock content %}
  
</div>
{% endblock block_full %}

Which means that I can now override a whole selection of elements in templates that extend this one rather than just the content block.

After 'blockifying' the node.html.twig template in this way the node.html.template in this site can just be implemented as follows:

{% extends "@sinatra/node.html.twig" %}
  
{% block label %}  
  {% if not page %}
    <h3{{ title_attributes }}>
      <a href="{{ url }}" rel="bookmark">{{ label }}</a>
    </h3>
  {% endif %}
{% endblock label %}

Note that via extension I can just surgically replace the mark-up for the title, all the rest of the markup remains the same and in one place.

Some pointers

You really need to read the links to Twig documentation that I gave earlier because there are few things that you will need to get used to. In an extending template for example you can only rewrite block/s that have been defined in the parent, you cannot add markup outside of block/s that you extend (will result in an error). There is also a very useful parent() function provided by Twig that spits out the parent template markup for the block.

For example an example of Twig include that I have seen a few times:

<div class="foo">
  {% include 'core/modules/node/templates/node.html.twig' %}
</div>

Allows you to wrap the node template with custom content using include functionality

I could do the same in a child of Sinatra as follows:

{% extends "@sinatra/node.html.twig" %}
  
{% block node_full %} 
<div class="foo"> 
   {{ parent() }}
</div>
{% endblock node_full %}

Block node_full wraps everything in the parent template and parent() pulls in the markup from the parent template.

Just a start

Extension can use variables or conditionals to define which template is extend and alongside includes and embeds some really interesting front-end workflows are possible, perhaps a clever base theme can allow similar workflows across other frameworks or cms using Twig. 

The future is bright, the future is Drupal 8. 

Add new comment

Restricted HTML

  • Allowed HTML tags: <a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • Lines and paragraphs break automatically.
  • Web page addresses and email addresses turn into links automatically.