fromJune 2014
Feature:

Upgrading Your Themes

From PHPTemplate to Twig
0

photo
The rumors are true: pretty much everything has changed in Drupal theming in the latest version.

At first it seems scary, but as you start digging into things, I think you’ll come to realize that the biggest changes are nearly invisible. Yes, there’s a new template engine with a different syntax, but the concept of template files which nest into one another still exists. We still have regions which can be loaded with blocks. We still have display modes. And you’ll still be working with Views. So while almost everything has changed, there’s also a lot that is quickly going to feel quite comfortable.

The biggest change, of course, is the retirement of PHPTemplate in favor of Twig. I have to admit that I’m an old-schooler who didn’t really find PHPTemplate all that difficult. (I will also admit that I’ve been known to throw coding elegance out the window in favor of brute force from time-to-time.) Generally, I don’t buy the argument that Twig, on its own, has reduced the complexity of the themes.

Let me show you what I mean. In PHPTemplate, we might have done something like this:

<?php print render($action_links); ?>

And in Twig, the equivalent statement looks like this:

{{ action_links }}

Yes, the second line is shorter, but it also feels like it has more magic going on. If you’ve been begging to get your code streamlined, I think you’re going to love Twig. Even if you liked the PHPTemplate way of doing things, there are a lot of advantages we’ve gained with the upgrade to Twig.

  1. Twig allows us to simplify themes. You are welcome to embed simple logic statements right into your template files.
  2. Twig makes themes more secure. Even though you can embed logic into your template files, it’s not as powerful as PHPTemplate, as there is no PHP allowed in a Twig file. (Try it! You’ll get errors.)
  3. The team working on Twig has dramatically reduced the complexity of the entire theme system.

I have the utmost respect for those who worked on this process. They didn’t simply duct tape a new templating system onto Drupal. They took the time to carefully comb over Drupal and find the things that were confusing, outdated, or just didn’t belong.

Upgrading an Existing Theme

As an example, let’s take Domicile, an existing theme which has been transformed a few times. With the Drupal 7 cycle it went from using the NineSixty base theme (version 1.x), to using a Sass plugin for the 960 Grid System (version 2.x). I’ll show you how I upgrade version 2.x of the theme to Drupal 8; grab a copy of the theme and work through the article with me.

Note: by design, the theme we're going to upgrade first is not responsive. We'll talk a little more about responsive themes in a future article. For now, let's focus on one thing at a time so there aren't too many moving parts to upgrade all at once.

In order to upgrade my theme, I’ve copied a Drupal 7 version of Domicile. You can get a copy of this theme from GitHub in the folder, domicile.

We'll work directly in the folder you've downloaded as it's an upgrade process. Go ahead and edit the files you've downloaded. If something goes terribly wrong, you can always download a fresh copy!

When upgrading a theme, remember that you are potentially bringing bad or outdated practices with you. It's quite possible that your theme was comprised of entirely good habits when it was first created, but over the years, themes do start to look a little ragged around the edges as technologies change. In a future article I'll address the advantages of taking the time to rebuild your theme from scratch so that it incorporates only modern good practices.

To begin the conversion process, start with the theme’s .info file. This file needs to have the file extension changed from .info to .info.yml.

Once the file name has been changed, you will need to convert the existing variables to the YML data format. For example: name = Theme name becomes name: Theme name.

The required variables are as follows:

  • name: A human readable theme name. This may contain spaces.
  • type: Modules and themes now share the same format for configuration files, so we must specify that this configuration file belongs to a theme.
  • description: A terse description of your theme. The description must be enclosed in quotes.
  • core: The version of core this theme may be applied to.

In the Drupal 8 theme, we'll delete the following variables which were in the Drupal 7 configuration file:

  • screenshot: Instead, add a file named screenshot.png to the root of your theme folder and it will appear automatically. The screenshot should be about 295 pixels wide.
  • engine: It is now assumed that you will be using Twig.

The next part of a theme’s configuration file is outlines which style sheets will be loaded (or removed). In Drupal 7 we added our style sheets with the following:

stylesheets[media_type][] = path/to/stylesheet.css
stylesheets[media_type][] = path/to/stylesheet2.css

In Drupal 8, we add our style sheets as follows:

stylesheets:
media_type:
  - path/to/stylesheet.css
  - path/to/stylesheet2.css

Your style sheets might look something like this:

stylesheets:
all:
  - css/global.css
print:
  - css/print.css

You may also prevent style sheets from loading by using the following syntax:

stylesheets-remove:
  - name-of-core-stylesheet.css

Take a peek at the core theme Seven to see an interesting combination of new variables that can be used to customize which style sheets are loaded for your theme.

Finally, you’ll need to update the list of regions. You may have already guessed the updated format to list your regions. In Drupal 7, you would have used the following format:

region[machine_name] = Human readable name

In Drupal 8, your theme’s regions are listed as follows:

regions:
machine_name: Human readable name
machine_name2: Also a human readable name

With these changes made, the theme can be enabled in Drupal 8.

Enabling a New Theme

As of Drupal 8, themes should now be uploaded to the directory themes in the root folder of your Drupal installation. Once the folder has been uploaded, it can be enabled by completing the following steps:

  1. Using the Admin menu, click on Manage.
  2. Click on Appearance.
  3. Scroll to the bottom of the list of themes, and below your new theme click on the link “Enable and set default”.

The interface has changed slightly in Drupal 8, but each of those steps should have felt very familiar to you.

If your theme wasn’t visible in the list, try rebuilding the cache. The clear cache button is still available by navigating to Manage » Configuration » Performance » Clear cache. If your theme is still not visible, check the syntax in your .info.yml file. Do you have quotes around the description? Have you missed any colons after the variable names? Fix up any pesky mistakes you find, clear the cache again, and navigate back to the list of Themes on the Appearance page.

Once your new theme has been set as the default, navigate back to the home page (I use the breadcrumbs for this). You should see that the Bartik-themed site has been transformed into a barebones blank slate. It’s unlikely that your CSS matches the default selectors provided by Drupal core, so your next step will be to adjust the markup to match your CSS files.

From tpl.php to html.twig

Converting your PHPTemplate files to Twig is a simple matter of finding anything with <?php and changing it to {. Of course it’s not quite that simple, but it’s pretty darn close. One-by-one you’ll want to go through your template files and convert them to Twig.

The easiest way to do this is to update a single file at a time from the extension .tpl.php to .html.twig. For example, page.tpl.php becomes page.html.twig. Once a file has been renamed to .html.twig, Drupal stops ignoring the file and tries to render it. If your file still contains PHP, it will throw errors.

Go ahead and rename the template file page.tpl.php from the Domicile theme to page.html.twig, and then open it in an editor. You’ll see that this is a very simple template file. There are a few variables, but not many. There are a few PHP if statements, but not many of those either.

Twig Variables

In the first pass through the template file, the only thing you need to know is that a double curly brace prints a variable, and that variables do not have a leading $. It doesn’t matter if the variable is an array, an object, or a string, the Twig output will look like this: {{ var_name }}.

On your first pass through the template file, find all of the regions and convert them to Twig regions. You can easily find a region by searching for $page[. Replace everything wrapping the region from <?php to ?>.
For example:

<?php print render($page['featured']); ?>

is replaced with the following:

{{ page.featured }}

There are four regions. Find and replace each one of them.
On your next pass, replace all of the remaining variables. In your template file, search for the word print. Sometimes there will be a render() function wrapped around it, sometimes it will be plain. It doesn’t matter: locate every single instance of print and swap it out.
The following three examples –

  • <?php print $messages; ?>
  • <?php print $front_page; ?>
  • <?php print render($title_suffix); ?>

– would be transformed as follows:

  • {{ messages }}
  • {{ front_page }}
  • {{ title_suffix }}

The images are a bit tricky, as the variable $directory seems to have been removed. In this case, we’ll do the replacement as follows:

<img alt=" " src="//www.drupalwatchdog.net/%3C?php_print_%24base_path___%24directory%3B_%3F%3E%2Fimages%2Fdomicile-banner_png" />

The variable $base_path has a perfect substitution, but the variable $directory is now hard-coded:

<img alt=" " src="//www.drupalwatchdog.net/%7B%7B%20%24base_path%20%7D%7Dthemes/domicile/images/domicile-banner.png" />

Twig Control Structures

A control structure alters the flow of a program. In Drupal themes, we are most likely to see a control structure in the form of an if-statement. Our Drupal 7 page.tpl.php file had three different PHP if statements which need to be converted to Twig.

For example:

<?php if ($tabs): ?>
<?php print render($tabs); ?>
<?php endif; ?>

You’ve probably already converted the printed variable, so the same line in your Twig file probably looks closer to this:

<?php if ($tabs): ?>
  
{{ tabs }}
<?php endif; ?>

Control structures will always have a beginning and an end. When we want to print something in Twig we use {{ double brackets }}, but when we want to use a control structure, we use {% bracket and percent %}. We also omit the terminating marks that were in PHP. In other words, our converted tabs output looks like this:

{% if tabs %}
  <div class="tabs">{{ tabs }}</div>
{% endif %}

There are three more control structures which need to be updated. Go ahead and make the updates now, I’ll wait.

Twig Filters

Your final Twig concept for this upgrade is a filter. A filter allows you to modify a variable before it is printed to the page. Filters can be chained, allowing you to apply multiple filters to a single variable before it is printed. Filters are added after a variable using the pipe symbol (“|”).

The only filter being used in our template is the translation filter. Whereas we previously used the translate function, t(), you now need to use its Twig equivalent. So –

<?php print t('Home'); ?>

– becomes:

{{ 'Home'|t }}

Final Check

Your page template file should now be devoid of any PHP. All of the <?php markers should be converted into either {{ or {%, and have a corresponding close structure, of course. Do a final search through your revised template file to ensure that you've completed your conversion.

After you've converted each template file, upload it to your server, clear the cache in Drupal, and check to make sure
there are no errors. Then proceed to converting the next template file.

Up to this point, we've just covered the basics. If your theme contains a file template.php, you'll need to convert this file as well. Renaming it to THEMENAME.theme (instead of template.php) will be enough for really basic themes. Take a peek inside the core theme Seven, to get more hints on upgrading this file to Drupal 8, if your theme has one.

Next Issue: Responsive Themes with Breakpoint

This theme was, by design, static. In a future Watchdog article, I'll dive into building responsive themes in Drupal 8 with the responsive module, breakpoint. If you can't wait, I encourage you to jump into the core themes, Bartik and Seven, and use them as an example of how to create your own responsive themes.

Image: ©iStockphoto.com/Rakoskerti