Drupal 8 Theming Fundamentals, Part 2

by John Hannah

In our last post on Drupal 8 theming fundamentals, we learned to set up a theme and add our CSS and JavaScript. This time around we’re talking about the Twig templating engine, how to add regions to our theme, and then finish with a look at the wonderful debugging available in Drupal 8.

If you’ve been following the changes in store with Drupal 8 then you’ve heard about the Twig templating engine. It’s a product of SensioLabs, the company responsible for the Symfony framework, parts of which are being used in Drupal 8.

Before we get started, a brief reminder. When making any changes to your theme you’ll need to clear your cache to get them to take effect. You can either do this in the UI under /admin/config/development/performance or you can use Drush. The Drush command to clear caches in Drupal 8 is drush cache-rebuild or drush cr as a shortcut.

Dissecting a Twig Template

Let’s begin by taking a look at the markup for an actual Drupal 8 template. Templates in Drupal 8 have a common naming pattern:

TEMPLATE_NAME.html.twig.

Below is what we find in the region.html.twig template file:

{%
 set classes = [
   'region',
   'region-' ~ region|clean_class,
 ]
%}
{% if content %}
 <div{{ attributes.addclass(classes) }}>
   {{ content }}

{% endif %}

Let’s go through this file and see what’s going on. The first thing we notice are the two different types of code blocks (also called block delimiters). One type of code block is marked by double curly braces like so:

{{ … }}

and the second is marked by a curly brace and percent sign:

{% … %}

These have been called the “say something” and “do something” types of code blocks, respectively.

At the very top of the file we see this code:

{%
 set classes = [
   'region',
   'region-' ~ region|clean_class,
 ]
%}

The opening delimiter is a “do something” block. In this case, we’re using the set keyword to create a variable named ‘classes’ that has as its value an array—indicated by the [ … ] bracket notation that surrounds the values being defined.

This particular array has two class names stored inside of it. The first is simply ‘region’, but the second is a more specific class name with a syntax that may look a bit unfamiliar. It’s prefixed by ‘region-’ and then followed by a squiggly line with another bit of text.

'region-' ~ region|clean_class

Let’s dissect this piece by piece. Notice the ~ character. This is called a tilde and it is used to concatenate—that is, connect—two strings in Twig. Right after the tilde we see a reference to region. It’s not in quotation marks and that tells us it’s a variable that is available inside of this template rather than a string.

One way to know which variables are available in a template is to simply open up the template file. The variables should be listed in the top comments. For the sake of brevity I’ve excluded the comments in this example, but if you’re following along and want to review them, you can find this file under core/modules/system/templates. We’ll look at another useful way to inspect the variables on a page a bit later when we talk about debugging.

The final thing to note about this variable declaration is the |clean_class part which appears right after the region variable. This is a Twig filter. Filters are indicated by the pipe character | and are followed by the filter name. In this case, we have the clean_class filter which converts a string into an acceptable CSS class name.

Now that we see how this variable has been set, let’s move on to the next part of the template file:

{% if content %}
 <div{{ attributes.addclass(classes) }}>
   {{ content }}

{% endif %}

We see another “do something” block which contains some simple logic to test if the content variable is present. This is a very good practice so that we aren’t printing empty blocks of markup to the page, which is what would happen if we weren’t checking this and the content variable was empty.

Next we see:

<div{{ attributes.addclass(classes) }}>

Because of the {{ … }} format, we know we have a “say something” block. In this case we are printing out the attributes for the content div. We’re passing in the classes variable we created in the previous step to the addClass method so that the classes are printed out.

As we’ll see in the debugging section below, there are tools that we now have that will make it easier for us to see what is inside these variables so that we can change them if needed.

The last bit of code in this file is simply {{ content }} which prints the content variable to the page. If you’re familiar with Drupal 7 theming, this new syntax probably doesn’t seem too bad.

Some advantages of using Twig as a templating engine are that it’s a mature, secure and well-documented system, the latter of which is very helpful if you get stuck.

Defining Page Regions

A common task for theme developers is defining the regions for the page template. These regions include the header, footer and main content areas where we can place blocks of content.

In our current theme ‘Atlas’, we haven’t defined any regions. By default Drupal 8 will assume the regions that are defined in the page.html.twig file located in core/modules/system/templates.

Changing these defaults is pretty straightforward. The first step is to return to our atlas.info.yml file and add the following:

# Define regions
regions:
  header: 'Header'
  content: 'Main content'
  footer: 'Footer'

I’ve added three basic regions, but you could add others as you see fit.

The next step is to copy the page.html.twig file from the core templates folder referenced above and place it in a folder named templates within our own theme.

In the screenshot below is a cleaned up version of page.html.twig that reflects the regions I just defined for my theme. You may not want to remove as much of the default markup as I have, but it’s helpful here for demonstration purposes.

Page template file

Let’s briefly go over this. First of all, notice that I’m checking to see if the header and footer regions exist. This is a good practice if a region will not be appearing on every page. It ensures that empty markup doesn’t get added to the page.

Placing the region on the template is as simple as adding {{ page.region_name }}. Replace region_name with the actual region name you want to add to the template.

What if we wanted to have different versions of this page template? For example, what if we wanted a different page template for the front page?

In that case all that we would have to do is save our page.html.twig file as page--front.html.twig, make our desired markup changes, clear cache and the new template will take over the front page of our site. The documentation on the naming conventions for overriding template files is quite good and should get you a long way in customizing your theme templates.

Twig Debugging

It’s great that we have the ability to override our template files, but we are still left with the question of how we are to know which template file needs to be overridden in any particular case. After all, template files are nested one inside the other—which one contains the markup that we want to change?

This brings us to the killer feature of Drupal 8 theming—Twig debugging. Getting started is very easy. Inside of the sites/default folder is a file named service.yml. Inside that file you will find a setting for Twig debug. This setting will be set to false by default. Simply change it to true as shown in the image below:

Twig debug setting

As usual, clear your cache after making this change. When we return to our page and inspect the markup we will find debugging information added in the form of code comments. Here’s an example of what our home page markup will look like when inspected in DevTools:

Debug info in the page markup

You can see the debug info provides the path to the new template file we have created. This information is repeated for other template files found on the page, providing a fast and easy way of finding the file you need to override or edit.

Important: Do not edit template files in core! Copy the file to your theme and edit that version instead.

Also included are file name suggestions for overriding the currently active templates. If you’ve ever had to track down the correct template file to override in Drupal 7, then you know what a huge improvement this is.

Update: David Rothstein pointed out in the comments that as of Drupal 7.33, this functionality has been backported to Drupal 7!

Finding Variables

Earlier I mentioned that there was a great way to inspect the variables available in a template. The syntax we use to print the variables is simple:

{{ dump() }}

This is placed inside the template where you’d like to see the available variables. In many cases this is going to result in a large number of variables being printed to the page. It may be helpful to narrow it down a bit, for example:

{{ dump(title) }}

This example will only print the title variable to the page. Take a look inside the template file for a list of the available variables—they will be listed in the comments at the top of the file.

Using the Atlas Starter Theme

Before we finish up I’d like to share the Atlas theme we’ve been working on throughout these posts. I’ve included it on GitHub so that if you’d like a quick start on creating a Drupal 8 theme you can simply download it and start hacking away.

In the coming days and weeks I’ll keep adding to Atlas to improve its usefulness. For example, there will be a simple Gulp workflow added for the CSS and JavaScript files as well as a few other commonly used tools and processes.

That’s it for the series! I hope you’ve enjoyed learning about Drupal 8 theming as much as I’ve enjoyed writing about it. Until the next time, happy coding!

newsletter-bot