Django, Ruby on Rails, Node.js, Laravel, Drupal—what do these platforms have that WordPress lacks? A template language.
This is where the “boo”s usually start. I’ve talked to many top people in the WordPress community who believe that the current PHP-based templating system is fine. Hard to disagree with them when WordPress powers nearly 20% of the web.
But I’ve talked to just as many WordPress people who believe that there’s a major opportunity here. Theme code quickly turns to spaghetti because the PHP-based templating doesn’t have the guardrails to enforce structure or patterns.
This makes it hard for most themes to live on past their initial development. A lot of “fix my WordPress theme” work has been offered to me over the years. Once I glance at the theme files and see this:
… my response tends to be “easier to start clean than fix.” This unfortunate pattern contributes to the idea that WordPress is somehow less worthy than Ruby, Django and alike which are for the “real pros.”
The business problem
At my company, Upstatement, we needed an easy way to create lots of WordPress themes for a large book publisher. We had just concluded a JavaScript-heavy project where we had used handlebars.js to make the templating easy. We thought: why can’t the templating be this easy in WordPress?
Good question. So over the next couple months I searched for a templating solution to make theming a WordPress site as easy as it is on other platforms.
First, trying to figure out what templating language to use:
Mustache
The first template language I got familiar with was Mustache. Mustache enjoys a wide user base across tons of platforms. The syntax is very clear:
Hello {{name}} You have just won ${{value}}!
… and provides for some simple control structures, like in this example (from the Mustache manual) that checks for the presence of a value:
{{#in_ca}} Well, ${{taxed_value}}, after taxes. {{/in_ca}}
Great! There’s just one (big) problem. Notice the intro line on the Mustache site: “Logic-less templates”? That means if you want to do a simple conditional:
{{#state == ‘ca’}} Well, ${{taxed_value}}, after taxes. {{/in_ca}}
You can’t. Mustache holds to logic-less in a religious way. I found I was doing more typing in my PHP file in order to set up my object to conform to how Mustache handles data. While I like the idea of removing logic from the templates, I also like the idea that there are some instances where the template should provide some logic or filtering in order to best suit the design.
Smarty
Smarty solves some of the “logic-lite” functionality I was looking for after. It’s got a long tradition, and has been around PHP for many years (I remember using it for a project back in college, which unfortunately confirms “many years”).
However, that legacy is also its downfall. Unfortunately, its website looks like something out of the mid-2000s:
This might seem like just window dressing, but it highlights the way in which the community around Smarty is set up: mailing lists, forum posts, etc. There’s no central GitHub page to watch or fork. It’s a PHP-only language: so no benefits from the lessons/structures of other platforms.
The syntax gets the job done, but it can look a lot like regular PHP:
Hello {$name} You have just won ${$value}, after buying {count($tickets)} lottery tickets!
To both its credit and detraction, it supports using PHP inside of its braces. It seems like a nice feature, but, contrary to Mustache, I think we’re introducing the possibility of too much logic. Smarty basically becomes a second window into PHP. (not to mention there are plenty of WordPress.org posts going back many years that list all the reasons it’s a bad idea). There are also lots of performance costs that have been measured.
Twig
There’s a lot to love about Twig.
Community
Twig is under active development and serves as the template engine for the Symfony Framework (it’s also maintained by Snyfony’s lead) and serves as the new template language for Drupal 8. Before you “boo” just because it’s Drupal, this is actually a major vote of confidence behind Twig. The more platforms it’s integrated in, the more it will be supported for performance, security, features, etc.
Also, its syntax is based on the Django template language. This isn’t something some dude dreamed up in his garage, it’s got lots of thought and history behind it.
These choices are reflected in the excellent documentation put together by Sensio Labs. They provide great reference and walkthroughs for both designers (who might use Twig in a template) and developers (who might add a special filter or function for a plugin or theme).
Syntax
Twig is simple and consistent. The brace syntax is pretty universal, but Twig’s handling is stellar:
{% if in_ca %} Well, ${{taxed_value}}, after taxes. {% endif %}
All variables get the double-brace ({{foo}}) syntax, while control structures (includes, conditionals, loops) get brace-percent ({% if foo %}). For introducing filters (filters and functions), Twig promotes a single clear way for template designers to work using the pipe “|”:
<img alt=”{{post.title|capitalize}}” src=”{{post.thumbnail.src|resize(300, 200}}” />
It’s easy to write new filters for your plugin or theme (but not too easy) in order to match the functionality you need.
Performance
Fabien Potencier has a very detailed article (from 2009) measuring the (minimal) performance costs on compilation. In my tests, Twig had zero performance impacts on a theme. This is because Twig compiles to PHP.
Moving into WordPress
Turns out there are already a handful of projects dedicated to linking WordPress and Twig. None of them have really caught fire. Here’s the rundown:
AP Twig Bridge
Unfortunately abandoned, this project (last updated in 2011) was pretty much a direct porting of Twig into WordPress. I think it failed to catch on because it essentially trades one hat for another. Many of the complaints about WordPress themes survive — just translated into Twig:
<div {{ post_class() }} id="post-{{ the_ID() }}"> <h2><a href="{{ the_permalink() }}" rel="bookmark" title="{{ the_title_attribute() }}">{{ the_title() }}</a></h2> <small>{{ the_time('F jS, Y') }} <!-- by {{ the_author() }} --></small> <div class="entry"> {{ the_content(__('Read the rest of this entry »', 'kubrick')) }} </div> </div>
As you can see, it’s basically just moving WP functions into Twig.
WordPress MTV
This project also got off to a really promising start (written by the awesome Newsapps team at the Chicago Tribune). MTV has been around for a while (since 2011) but has some more recent activity (updated on GitHub just about a week ago).
MTV provides tons of power, which is where I got tripped up a bit. It’s an entire framework to write your theme. This may be exactly what some people are looking for (indeed I can think of at least one project from the past I wished I had used with this). But what scares me a bit is how total this solution is (from the GH page: “This plugin hijacks and takes over how WordPress handles URLs”)
My Solution: Timber
I’ve been working on my own “Goldilocks” solution for the last few months called “Timber.” My goal is to combine the great syntax of Twig (which is also shared in MTV), but make the PHP side as simple as possible. This is how small a theme’s single.php can be with Timber:
<?php $data = Timber::get_context(); $data[‘post’] = new TimberPost(); Timber::render(single.twig’, $data);
… and then the corresponding .twig file (which is just html with Twig variables and components)
{% extends “base.twig” %} {% block content %} <article class=”post post-{{post.post_type}}” id=”post-{{post.ID}}”> <h1>{{post.title}}</h1> <img src=”{{post.thumbnail.src|resize(600)}}” /> <div class=”body”>{{post.content}}</div> </article> {% endblock %}
We put Timber into production on a major project for Random House. Since then, we’ve used it on every single WordPress project to cut down on development time, reduce debugging, and confidently turn over better code to the client for them to manage.
It’s a plugin that enables us to use Twig in themes. “Enables” is the key word: it can be implemented where it makes most sense for the project as opposed to all-or-nothing.
Because Twig clearly exposes the HTML, this has made it much easier to do responsive design (everything we do at Upstatement is now responsive).
A template language won’t work for every scenario. But when you have a mix of people working together on a project in both the HTML/CSS (front-end) and PHP (back-end) worlds; it causes way less conflicts in Git. The template syntax also empowers designers to take ownership of the theme even if they don’t know much PHP.
If democratizing publishing is WordPress’s guiding principle, making it easier for semi-technical people to interact and customize their theme seems like a great next step.
Resources:
Timber Project Page
Timber Screencasts
Twig Project Page
Blog Post on Twig (old, but lots of great background)
Jared Novack is a partner at Upstatement — the company behind the design of The Boston Globe and GlobalNews.ca. He lives in Boston now, but a true St. Louisian at heart. Follow him on Twitter at @jarednova
31 Comments