Extending Twig Templates: Inheritance, Filters, and Functions

Rakhitha Nimesh
Share

When working within an MVC architecture, it’s common to use a template library to populate the dynamic content of our views. There are dozens of such libraries available for PHP, but Twig is one of the standouts because of the ability to extend core features with custom implementations. In this article we’ll explore how Twig templates can be extended using template inheritance, filters, and functions.

Limitations in Template Libraries

The most common limitation that many template libraries have is the inability to extend template features. For example, it’s common to include all of the references to CSS and JavaScript files in the header or footer section of a page, and so we create a header template and include that file in all of our pages. But what if we have a page which needs to initialize a Google map on page load? The JavaScript for the map should be only called from this one page, but many developers would needlessly include all of the JavaScript and CSS files in the one header.

Another workaround is to include the common shared files in the header and include the other specific files inside the page templates as necessary. The header file might look like this:

<!DOCTYPE html>
<html>
 <head>
  <link rel="stylesheet" href="style.css">
  <script src="jQuery.js" type="text/javascript"></script>
 </head>

… and the map template might look like this:

<script src="googlemaps.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function(){
    $("#google_map").google_map();
});
</script>
<div id="google_map"></div>

The common CSS and JavaScript are referenced in the header, and map-specific code is inside the page template. While this works, ideally we should keep all of these references in one place for consistency and cleaner code instead of split across files like this.

With most template libraries, we have no option other than to go with the techniques above. But now let’s see what Twig offers to cope with this situation.

Extending Twig Templates

Twig gives us the ability to extend child templates from parent templates using inheritance. Probably the easiest way to see how inheritance works is with an example. The following code is a parent template:

<!DOCTYPE html>
<html>
 <head>
  {% block head %} Sample Content {% endblock %}
 </head>
 <body>
 </body>
</html>

We define blocks inside the parent template which have a name and some content inside it. Then we can extend the defined blocks inside child templates like so:

{% extends "parent.html" %}
{% block head %} Head 1 {% endblock %}

In the child, we extend the parent template by using the extend keyword followed by the template file name. We then redefine the head block to contain dynamically extended content. Omitting the head block in child template will cause the parent to use the content it already has defined as a default.

Now that we have a basic idea of how inheritance works in Twig, let’s create a more complete page layout.

<!DOCTYPE html>
<html>
 <head>
  {% block head %}
  <link rel="stylesheet" href="style.css">
  <script src="jQuery.js" type="text/javascript"></script>
  {% endblock %}
 </head>
 <body>
  <div id="grid">{% block content %} {% endblock %}</div>
  <div id="info">{% block sidebar %} {% endblock %}</div>
  <div id="footer">
   {% block widget1 %} {% endblock %}
   {% block widget2 %} {% endblock %}
   {% block widget3 %} {% endblock %}
   {% block footer %}
   &copy; 2013 example.com
   {% endblock %}
  </div>
 </body>
</html>

I’ve created a main template which contains all of the components of a standard web page. There’s a header block where we can include files dynamically, a dynamic main content area, and an information sidebar. In the footer there’s three dynamic widgets followed by the copyright message.

With other templating systems we might have to create headers, footers, content, and sidebars separately to reuse across multiple templates. But with Twig’s support of inheritance, we can create the one main template to use across all of the pages in our site.

Let’s say we want a use the template for a page which relies on a specific jQuery plugin. Basically we need to include the plugin’ files which depend on the jQuery library we’ve already provided, so we would extend the template this way:

{% block head %}
{{ parent() }}
<script src="jquery.plugin.js"></script>
{% endblock %}

The head block is redefined to reference the custom plugin files, but also while preserving the contents of original head section. The parent() function is used to retrieve the original head content.

Indeed, Twig templates are highly flexible and are able to cater any type of requirement. Blocks can be placed anywhere, and block content can be changed in various ways to suit our needs.

Up until now we’ve only discussed how we can use template inheritance to extend our templates. Twig comes with a number of features to further extend templates; let’s look now at how filters and functions fit into the process.

Role of Twig Filters

Filters are used to modify variables inside a template. You can find a list of built-in filters in the Twig documentation, but to illustrate the concept I’ll show you the basic usage of a filter to remove leading and trailing whitespace from a value.

{{ "Varible content" | trim() }}

Built in filters are very useful, but the real power of filters come with the implementation of custom filters. Twig provides a well-defined method for creating our own filters. Since data grids are a common means of presenting data in a web app, let’s assume we have a grid that displays a product table with different categories. We’ve been asked to display the data with each category highlighted with a specific color. We can use a custom filter to implement this feature.

New filters are created by using anonymous PHP functions and the Twig_SimpleFilter class.

<?php
$filter = new Twig_SimpleFilter("highlight", function ($key) {
    switch (trim($key)) {
        case "book_category":
            echo '<span class="books_color">';
            break;
        case "cd_category":
            echo '<span class="cd_color">';
            break;
        case "ebook_category":
            echo '<span class="ebook_color">';
            break;
        default:
            // nothing
    }
});
$twig->addFilter($filter);

I’ve created a new filter named “highlight”, and then added it to the Twig environment using the addFilter() method. A category will passed to the filter as a variable, and inside the function we switch the category and output an element with specific CSS class to generate the dynamic highlighting in the grid.

We can use this filter inside our templates like so, with products as an array which consists of our product names and categories:

{% block content %}
 {% for product in products %}
  <div>
   {% filter highlight %}
   {{ product.category }}
   {% endfilter %}
   {{ product.product }}
   </span>
  </div>
 {% endfor %}  
{% endblock %}

Role of Twig Functions

Twig functions are used to add dynamic content to our templates. There’s a selection of built-in functions, but as with filters, the real power of function comes with the ability to create our own implementations.

<?php
$function = new Twig_SimpleFunction("function_name", function ($arg1, $arg2) {
    // implementation
});
$twig->addFunction($function);

Again we can use anonymous functions to create dynamic Twig functions. The first parameter to the Twig_SimpleFunction class is the name of the function, and the second is the function definition. The function is added to the Twig environment using addFunction().

Let’s assume that we are using a library for working with form fields like textboxes, checkboxes, etc. Usually we just write the required HTML directly in the templates like so:

<input type="text" name="fname" class="chosen">

But if the library requires certain attributes to work it can be difficult to include the necessary HTML for every form without making any mistakes. We can create a Twig function to insert each of the field instead.

<?php
$function = new Twig_SimpleFunction("form_text", function ($name, $id, $value = "", $class = "form_text") {
    echo '<input type="text" name="'.$name.'" id="'.$id.'" value="'.$value.'" class="'.$class.'">";
});
$twig->addFunction($function);

This technique makes sure that we include the correct attributes without making mistakes. We would call this function from within our templates using the following:

{{ form_text("fname", "fname", "", "chosen") }}

Inheritance, filters, and functions are a powerful combination when it comes to extending Twig templates. We can use these in different ways to easily deal with the advanced requirements of our application.

Summary

The ability to create extensible templates allows us to reuse templates and features in multiple places throughout our applications when necessary, and Twig is one of best templating libraries when it comes to support for for extending the core library’s functionality. Twig also comes with extensive documentation explaining every aspect of the template creation process, which makes extending things easy.

Let me know your experiences with Twig and your thoughts on its template extending process. I’m looking forward to hearing from you.

Image via Fotolia