Craft CMS Twig Filter Extension

Craft is an awesome CMS that if you haven't heard of, you should. It's built on the Yii framework (which I haven't really used beyond dabbling with Craft, but I've heard good things) and uses Twig for templates.

Anyway, this post isn't about how awesome Craft is (which it is), it's about a piece of auspiciously missing documents: how to create your own Twig filter inside of craft!

Word It Up

For demonstration purposes, we're going to create a simple "Word It Up" filter that takes a number and converts each letter into its corresponding words (just on a per-digit basis).

For example, if we were to put this in our template:

<p>{{ 123 | wordItUp }}</p>  

it would output:

<p>one two three</p>  

Building the Twig Extension

This guide will assume you're familiar with building Craft Plugins. (The full code used in this example is up on GitHub as a template.)

Your Twig Extension files will go within a your plugin directory in a directory called twigextensions. So assuming our plugin is named Word It Up (which is it is in this example), our directory structure would look like this:

craft  
└── plugins
    └── worditup
        ├── WordItUpPlugin.php
        └── twigextensions
            └── WordItUpTwigExtension.php

(As an aside, you should definitely checkout the tree command line tool (i.e. brew install tree).)

In our WordItUpPlugin.php file, the only thing special we need to do is add an addTwigExtension function and return an instance of our Twig Extension:

public function addTwigExtension()  
{
    Craft::import('plugins.worditup.twigextensions.WordItUpTwigExtension');

    return new WordItUpTwigExtension();
}

Now we go into the WordItUpTwigExtension.php file itself. We need to include use some Twig stuff at the top of our file (along with the Craft namespace):

namespace Craft;

use Twig_Extension;  
use Twig_Filter_Method;

class WordItUpTwigExtension extends \Twig_Extension  
{
    ...

The only other "special" stuff we'd need is a getFilters function that returns Twig-wrappered methods referenced in your class:

public function getFilters()  
{
    return array(
        'wordItUp' => new Twig_Filter_Method($this, 'wordItUp'),
    );
}

All this says is that if we use a wordItUp filter in the Twig template, it will pass the input to your wordItUp function in from the current ($this) class.

Extra Parameters

For completeness sake, the way filter parameters get mapped from Twig template to filter function is like so:

{% set red = 'red' %}
{% set blue = 'blue' %}
{% set green = 'green' %}
{{ red | someFilter(blue, green) }}

maps to

public function someFilter($one, $two, $three)  
{
    echo $one; // 'red'
    echo $two; // 'blue'
    echo $three; // 'green'
}

so you can pass in as many extra parameters as you need.

Full Example

Here's the full WordItUpTwigExtension.php file:

<?php  
namespace Craft;

use Twig_Extension;  
use Twig_Filter_Method;

class WordItUpTwigExtension extends \Twig_Extension  
{
    private $digitToWord = array(
        0 => 'zero',
        1 => 'one',
        2 => 'two',
        3 => 'three',
        4 => 'four',
        5 => 'five',
        6 => 'six',
        7 => 'seven',
        8 => 'eight',
        9 => 'nine',
    );

    public function getName()
    {
        return 'WordItUp';
    }

    public function getFilters()
    {
        return array(
            'wordItUp' => new Twig_Filter_Method($this, 'wordItUp'),
        );
    }

    public function wordItUp($number)
    {
        $output = array();

        foreach (str_split(intval($number)) as $digit) {
            $output[] = $this->digitToWord[$digit];
        }

        return implode(' ', $output);
    }
}

Conclusion

Now you can go and install your plugin via the Craft dashboard and use your new filter in a plugin, and voila! You "Worded It Up!"

You can now turn

<p>{{ 123 | wordItUp }}</p>  

into:

<p>one two three</p>  

View full plugin on GitHub.