Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Templating a WordPress theme with Twig

DZone's Guide to

Templating a WordPress theme with Twig

· Web Dev Zone ·
Free Resource

Deploying code to production can be filled with uncertainty. Reduce the risks, and deploy earlier and more often. Download this free guide to learn more. Brought to you in partnership with Rollbar.

Well, that wasn’t as painful as I thought it would be. Some googling and a couple of experiments went a long way, and now I have a partial, unstyled, Twig-based theme happily running on WordPress.

Twig is a templating engine for php. It has more than enough features to get me going, setting it up is as easy as falling off a tree, and I haven’t used it much, which makes it a good candidate for me.

Making WordPress call Twig

Once we’ve downloaded Twig and put it somewhere convenient (in my case, in my theme folder – I’d like to move it out eventually, but it can stay there while I work it out), we need to tell WordPress to initialize the Twig engine. Darko Goles’ blog post, TWIG with WordPress part 1, covers this admirably. In his post, he’s initializing the engine through a plugin, which I wanted to avoid as I didn’t want a theme to depend on a plugin. Luckily the mechanism is the same, since the hooking mechanism in WordPress papers over these issues – we can initialize from a theme exactly like we do from a plugin, by specifying the actions in a functions.php file:

<?php 
    // theme functions.php
    require_once dirname(__FILE__).'/twig.helper.php';
?>

<?php
    // twig.helper.php
    require_once dirname(__FILE__).'/lib/Twig/Autoloader.php';

    class Twig_Helper {
	public static function register() {
	    ini_set('unserialize_callback_func', 
                'spl_autoload_call');
            spl_autoload_register(array(new self, 'autoload'));
	}

	public static function autoload($class) {

            if (0 !== strpos($class, 'Wp_TwigEngine'))
	        return;

            if (file_exists($file = dirname(__FILE__) . '/../' 
                . str_replace(array('_', "\0"), array('/', ''), 
                $class) . '.php')) {
		     echo($file);
		     exit;
                     require $file;
	    }
	}

	...
	...
    }

    ...

    function autoload_twig() {
        Twig_Autoloader::register();
	Twig_Helper::register();
    }

    add_action('init', 'autoload_twig');
?>

The above is copied nearly verbatim from the post I mentioned above, and works fine. It registers twig and loads all the classes it needs to work. I put this in a separate file and referenced it from functions.php so it wouldn’t get mixed in with any theming functions I might need to add later.

Getting to the data

Now we’re able to load templates, but we still need to be able to pass data to them. The solution came, again, from Mr. Goles’ blog, this time from TWIG with WordPress part 2 – we pass a proxy object to the template, which it can then use to call functions on. Again, I used the code from this post almost as provided, except that I used the same TwigHelper class to provide this proxy. I also added another method, text, to wrap the __(string, key) function used for localization.

Writing templates

The template file looks like this:

{% extends "master.html.twig" %}
{% block pageContent %}
	<section id="content" role="main">
		{% for post in posts %}
			{% set format = site.get_post_format() %}
			{% include format 
                               ? "content-" ~ format ~ ".html.twig" 
                               : "content.html.twig" %}
		{% else %} 
			{% include "content-none.html.twig" %}
		{% endfor %>	
	</section>
{% endblock %}

Not much of it, is there? In reality, that’s because most of the layout is defined in master.html.twig, which we’re extending in the first line. This file has placeholders for the pageContent block which is being filled up here, and the rest of the page around it. I’ve also delegated the no-content section to its own file. The snippet above is the equivalent of:

	<div id="content" role="main">
	    <?php if ( have_posts() ) : ?>	
	        <?php while ( have_posts() ) : the_post(); ?>
	            <?php get_template_part('content', 
                                 get_post_format() ); ?>
	        <?php endwhile; ?>
	<?php else : ?>
		<?!-- stuff to show if there's no content -->
	<?php endif; ?>
	</div>

It may not be significantly shorter, but it’s a damn sight easier to read. The readability and size gains are much greater when you have more markup, but I don’t want this to be a templating post.

While… hang on, where’s while?

As I was working on the loop, I realized that Twig doesn’t have a “while” control. This was a problem as WordPress is heavily dependent on The Loop. This can be worked around, as demonstrated in this blog post by Luis Cordova, by making an iterator and using it in a for loop. It’s a good enough solution and the template doesn’t look bad.

Current status

At this point I have a barely functional them (still need to port over a lot of stuff) but getting here took a lot less time than I thought it would. My next step will probably be to port over as much of the old theme as I can, and then work from there.



Deploying code to production can be filled with uncertainty. Reduce the risks, and deploy earlier and more often. Download this free guide to learn more. Brought to you in partnership with Rollbar.

Topics:

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}