Timber: the missing component in WordPress development

By Geoff Muskett

A few weeks ago I was fortunate to freelance with the superb dev team at fffunction. Those guys are highly knowledgable developers who care about code quality and doing the right thing for the client. Key ingredients to great work.

I felt very welcome, they’re a super nice crew. Although they didn’t go easy on the new guy with Quake 4 over LAN. Or maybe they did, but I was a sitting duck. Still, over the week I improved my in-game kill count by 300%. From 1 to 3. Oh dear.

Other than 1st person shooter skills (or lack of), my biggest take away from the week has changed the way I develop with WordPress.

They introduced me to Timber, a plugin for WordPress that separates PHP from HTML. And I really like it.

Since then I’ve built geoffmuskett.com with Timber and will be launching another site in the next week or so. I can’t see any going back, except maybe when mentoring rookies. It’s still good to know traditional WordPress, which has a lower barrier to entry than using Timber. And there’s so much info out there online for traditional WordPress development. Less so for Timber.

What is Timber?

As I mentioned, Timber allows you to separate PHP from HTML. Your PHP templates contain all the WordPress logic which is then passed to a view. Much like an MVC (Model-View-Controller) framework.

Benefits of separating logic and views in WordPress

In my opinion these are the two biggies:

1. It gives you full control over the HTML

Standard WordPress templating often doesn’t. For example with menus:

<?php wp_nav_menu( array( ‘theme_location’ , ‘header-menu’ ) ); ?>

You’ve just gotta live with what it outputs. What if you don’t want or need the nav links in list items.

With Timber you can just write your HTML in the view exactly how you want it, then simply add the dynamic content passed from the PHP file. Including the WP classes if for menus if desired.

2. It keeps your HTML super clean

No more ‘if this template’ / ‘if that template’ cluttering up nice markup.

Basically you’re collecting the data in the template, then rendering it in whatever HTML you want in the view.

Liberation from The Loop.

Timber comes bundled with Twig

What’s Twig?

It’s a templating engine for PHP. Which means it’s a nicer, simpler syntax but compiles to PHP. For example those verbose opening and closing PHP tags…

<?php whatever ?>


{{ whatever }}


{% if whatever %}

Much cleaner and quicker, plus, you don’t need to be a backend developer to understand it.

Twig is extensible

You have a base.twig file which has you’re basic HTML page that is consistent across your site. In it there are blocks of content which you’re templates or includes override. This is the base.twig file from the Starter Theme, notice the blocks like {% block content %} for example:

{% block html_head_container %}

{% include ‘html-header.twig’ %}
    {% block head %}
    {% endblock %}
{% endblock %}

<body class=“{{body_class}}” data-template=“base.twig”>
    <header class=“header” >
        {% block header %}
            <div class=“wrapper”>
                <h1 class=“hdr-logo” role=“banner”>
                    <a class=“hdr-logo-link” href=“/“ rel=“home”>{{site.name}}</a>
                <nav id=“nav-main” class=“nav-main” role=“navigation”>
                    <ul class=“nav”>
                    {% for item in menu.get_items %}
                        <li class=“nav-item {{item.classes | join(‘ ‘)}}”>
                            <a class=“nav-link” href=“{{item.get_link}}”>{{item.title}}</a>
                            {% if item.get_children %}
                                <ul class=“nav nav-drop”>
                                {% for child in item.get_children %}
                                    <li class=“nav-drop-item”>
                                        <a class=“nav-link” href=“{{child.get_link}}”>{{child.title}}</a>
                                {% endfor %}
                            {% endif %}
                    {% endfor %}
                </nav><!— #nav —>
        {% endblock %}

    <section id=“content” role=“main” class=“content-wrapper”>
        {% if title %}<h1>{{title}}</h1>{% endif %}
        <div class=“wrapper {{sidebar_class}}”>
            {% block content %}
                Sorry, no content
            {% endblock %}
        {% if sidebar %}
            <aside class=“layout-sidebar”>
        {% endif %}

    {% block footer %}
        <footer id=“footer”>
            {% include ‘footer.twig’ %}
        {{ function(‘wp_footer’) }}
    {% endblock %}

And here’s the page.twig file, it’s saying ‘base this page on base.twig, then replace the block content with this block content:

{% extends “base.twig” %}

{% block content %}
<div class=“content-wrapper”>
    <article class=“post-type-{{post.post_type}}” id=“post-{{post.ID}}”>
        <section class=“article-content”>
            <h1 class=“article-h1”>{{post.title}}</h1>
            <div class=“article-body”>
</div><!— /content-wrapper —>

{% endblock %}

You can pass variables across twig templates

This sends the variable ‘varName’ to the gallery.twig template:

{% include ‘partials/gallery.twig’ with {‘varName’: true } %}

This is super useful when using partials that are similar but slightly different. You can check for the variable in the partial and output the thing that is different. Like adding a different class. This is in our gallery.twig file, checking for the variable:

<div class=“{% if varName %} className {% endif %}”</div>

My highlights with WordPress + Timber + Twig

I’ve already talked about being extensible, separating data and design, and full control of markup. Here are a handful of other little wins:

Controlling images

Anyone working with clients will know that it can be difficult to educate them to resize images to match your perfect layout. And it’s not their fault, they’re experts in their own field not web stuff or photo editing.

You’re CMS and set up should catch as much as possible, and Timber makes it easy to catch incorrectly sized images. This snippet gets the image source, then resizes it to 1050 x 525px, then gets the image alt tag:

<img src=“{{ TimberImage(lifestyleImage).src|resize(1050,525) }}” alt=“{{ TimberImage(lifestyleImage).alt }}”>

This can be great for responsive background images as there is no need to create multiple versions of the same image.

It works great with Advanced Custom Fields

When you bring in the content of the post (or page – same thing) in the template it brings in the basic custom fields. If you’re using a repeater, or relationship field then thats easy too.

$context[‘post’] = $timber_post; // gets the content of the post including basic custom fields

$context[‘repeaterName’] = get_field(‘repeater_name’); // gets the repeater field

In the twig view, this outputs the repeater field:

{% for thisRepeater in repeater_name %}
    {{ thisRepeater.field_name }}
{% endfor %}

Excerpts but not excerpts

It’s easy to forget to add an excerpt to post or add a ‘more’ breaker to the content. The better way to handle teasers in my opinion is showing the first 30 or so words from the post content.

You can do this in normal wordpress:

<?php $trimmed = wp_trim_words( $text, $num_words = 30, $more = null ); ?>

Here’s the Timber/Twig version:

{{ post.content|exerpt(30) }}

Easy thumbnails

<img src=“{{post.thumbnail.src|resize(600,300)}}” alt=“{{post.thumbnail.alt}}”>

And if you wanted to check if there’s a thumbnail:

{% if post.thumbnail %}
<img src=“{{post.thumbnail.src|resize(600,300)}}” alt=“{{post.thumbnail.alt}}”>
{% endif %}

The general niceness

OK, niceness is not descriptive. And this is a bit of a cop out because there’s lots of great features, many I haven’t used yet.

By ‘general niceness’ I mean things like this. Here’s how I’ve marked up the microformats for posts on geoffmuskett.com.

<div class=“blog-author vcard”>
        By <span class=“fn {{ post.author.name }}” </span>   <span>&bull;</span>
        <time datetime=“{{ post.post_date }}”>{{ post.post_date|date}}</time>

Super clean, super easy, super fast.

Where to start

I recommend the Timber Starter Theme for getting going. Thats the foundation for this site and the next one I have in the pipeline.

You can dig into it and see how the template files send data to the views. And how the views use includes to modularise code. For example tease.twig is a partial used for the blog post ‘teasers’ in the main loop.

I think it’s great, and for me, it’s exactly what I didn’t know I was missing in WordPress development. I highly recommend you give it a whirl.


Leave a Reply

Your email address will not be published.

Join my newsletter

If you’re looking for insights into web design and development, and crafting a successful presence online, then you should join the smart folk on on my newsletter. I discuss my thoughts on an issue relating to the web, then provide and teach effective solutions.