The Twig implementation for WordPress themes

v0.3.0 2017-09-15 08:39 UTC


An implementation which aims to bring the Twig Template Engine to Wordpress with flexibility and as little hassle as possible.


The recommended way to install Twig-Wordpress is via Composer.
Install composer in your project:

curl -s http://getcomposer.org/installer | php

Create a composer.json file in your project root:

  "require": {
    "hoku/twig-wordpress": "dev-master"

Install via composer.

php composer.phar install

To get started, we create the folder structure that's' necessary inside your theme for Twig-Wordpress to work.
You can change this to whatever you like.


Define your constants and then require the autoloader for composer.
To match the folder structure above, put this inside your functions.php.

define('TWP___TWIG_ROOT', get_template_directory().'/twig/');
define('TWP___TEMPLATE_PATH', TWP___TWIG_ROOT.'templates/'); // This could be omitted because it's the default
require_once '/path/to/vendor/autoload.php';


The Template Hierarchy used is the same as for Wordpress. The file extension is twig though, instead of php.
The bootstrap loads the correct template based on it's hierarchy and if the template file exists. So make sure your template exists in your TWP___TEMPLATE_PATH.

Using The Loop

The Loop is very central for Wordpress. As a result, I've tried to make an implementation for use in Twig.
The loop property is an instance of the TWP_Loop class, which is an iterator with Wordpress flavor.
It's current method will return the current global $post, after the_post has been called.

{% for post in loop %}
  <h1>{{ post.post_title }}</h1>
{% else %}
  <p>Nothing to read.</p>
{% endfor %}

You can also use the_post action to alter the post specific properties.

function my_post($post)
  $post->content = get_the_content();
add_action('the_post', 'my_post');

With that in place, you can now use the altered post properties in Twig.

{% for post in loop %}
  <h1>{{ post.post_title }}</h1>
    {{ post.content|raw }}
{% else %}
  <p>Nothing to read.</p>
{% endfor %}
Custom templates

Every post, regardless of type, can also use Custom Templates. They are configured similarly to Wordpress custom templates in that they have a particular style of Twig comment at the top of them.
You can specify both name and which post types your custom template should be available for. The Template Name is required and the Post Type is optional. If no Post Type is provided, the template will be available for all post types.

Template Name: My Custom Template
Post Type: page, post



Twig-Wordpress admin flag. Use it to activate, when TWP___CACHE_PATH also has been set, an admin menu item which can be used to clear the Twig cache. Defaults to true.


Twig cache path. A writeable folder for your Twig template cache.


Twig-Wordpress custom templates meta name. Defaults to "_wp_twig_template".


Twig-Wordpress custom templates types. Use it to override which post types that should have the custom template options or use false to disable custom templates. The value must be either false or a serialized array with the post types as values. Defaults to a serialized array containing the values page and post.


Twig debug flag. Defaults to WP_DEBUG constant value. Note that enabling TWP___DEBUG disables the Twig template cache, even though TWP___CACHE_PATH is set.


Twig-Wordpress domain used for i18n. Defaults to "default".


Twig root path. Defaults to a folder named "twig", including a trailing slash, within the Twig-Wordpress directory. When requesting your Twig templates, they should be relative to this folder.


Twig-Wordpress template path. Defaulta to a folder named "templates", including a trailing slash, within TWP___TWIG_ROOT. By default, Twig will look in this folder for every template during bootstrap.



This action is triggered just after the TWP_Environment is instantiated. It provides the environment instance and params as it's parameters.
This example adds the Debug Extension to Twig.

function my_init($twig, $params)
  $twig->addExtension(new Twig_Extension_Debug());
add_action('TWP__init', 'my_init', 1, 2);

This example adds an additional param to Twig, which can be used in your templates.

function my_init($twig, $params)
  $params['home'] = get_bloginfo('url');
add_action('TWP__init', 'my_init', 1, 2);

This action is triggered in the constructor of TWP_Environment. It provides the environment instance as it's only parameter.
This example adds the query_posts function to Twig.

function my_environment($environment)
  $environment->addFunction('query_posts', new Twig_Function_Function('query_posts'));
add_action('TWP__environemnt', 'my_environment');



This filter runs just before the TWP_Environment is instantiated. It provides the environment options as it's only parameter.
Remember that this filter is executed after the TWP___DEBUG and TWP___CACHE_PATH constants has been assigned to the options, so changes here will override them.
This example disables auto-escaping for Twig.

function my_options($options)
  $options['autoescape'] = false;
  return $options;
add_filter('TWP__options', 'my_options');

This filter runs when the custom Twig templates has been fetched. This example adds a custom template for pages, which doesn't have a Twig comment at the top.

function my_templates_list($templates, $post_type)
  if ($post_type == 'page') {
    $templates['my-custom-page-template-without-comment.html.twig'] = __('My Custom Page Template Without Comment');
  return $templates;
add_filter('TWP__templates_list', 'my_templates_list', 1, 2);

This filter runs when the Twig template has been found.
It provides the template path, index and a boolean representation for if the template is loaded by index.php or not.
This example loads 'happy-new-year.html.twig' as the template on new years eve.

function my_template($name, $index, $root)
  if (date('m/d', time()) == '12/31') {
    return 'happy-new-year.html.twig';
  return $name;
add_filter('TWP__template', 'my_template', 1, 3);

The template filters runs when the default Twig templates are declared.
This example changes the 404 template name to not-found.html.twig.

function my_404_template($filename)
  return 'not-found.html.twig';
add_filter('TWP__template_404', 'my_404_template');

The following template filters are available.

  • TWP__template_404
  • TWP__template_search
  • TWP__template_taxonomy
  • TWP__template_front-page
  • TWP__template_home
  • TWP__template_attachment
  • TWP__template_single
  • TWP__template_page
  • TWP__template_category
  • TWP__template_tag
  • TWP__template_author
  • TWP__template_date
  • TWP__template_archive
  • TWP__template_comments-popup
  • TWP__template_paged
  • TWP__template_index

The override template filter runs when the Twig templates, wihich override the defaults, are declared.
Note that each overridable template filter need to include "%s", which is a placeholder for the object property.
This example changes the taxonomy override template, which now can be found in the folder "override".

function my_taxonomy_template_override($filename)
  return 'override/'.$filename;
add_filter('TWP__template_taxonomy-override', 'my_taxonomy_template_override');

The following overridable template filters are available.

  • TWP__template_taxonomy-override
  • TWP__template_single-override
  • TWP__template_page-override
  • TWP__template_category-override
  • TWP__template_tag_override
  • TWP__template_author-override
  • TWP__template_archive-override