Twig – the Most Popular Stand-Alone PHP Template Engine

Share this article

Twig – the Most Popular Stand-Alone PHP Template Engine

This article was peer reviewed by Wern Ancheta. Thanks to all of SitePoint’s peer reviewers for making SitePoint content the best it can be!


Twig is a template engine for PHP. But isn’t PHP itself a template engine? Yes and no! Even though PHP started as a template engine, it didn’t evolve like one, and while we can still use it as one please tell me which version of “Hello world” you prefer:
<?php echo "<p> Hello " . $name . "</p>"; ?>
or
<p> Hello {{ name }} </p>
PHP is a verbose language, and that verbosity is amplified when trying to output HTML content. Modern template systems will take away some of that verbosity and still add a fair share of functionality on top. Things like security and debug features are mainstays in modern template engines. Today, we’re focusing on Twig. Twig logo Twig is a template engine created by Sensio labs, the company behind Blackfire and Symfony. Let’s take a look at its main strengths and how can we use it in our projects.

Installation

There are two ways of installing Twig. We can use the tar ball available on their website, or we can use Composer, just like we always do and recommend.
composer require twig/twig
We’re assuming you’re running an environment with PHP set up and Composer globally installed. Your best bet is using Homestead Improved – it’ll let you get started in 5 minutes on the exact same machine we’re using, so we’re all on the same page. If you’d like to learn more about PHP Environments, we have an excellent premium book about that available for purchase here. Before we go any further, there’s something we need to clarify first. As a template engine, Twig operates both on the front and on the back end of a project. Because of that, we can look at Twig in two different ways: Twig for template designers and Twig for developers. On one side, we prepare all data we need. On the other side, we render all that data.

Basic Usage

To exemplify the basic usage of Twig, let’s create a simple project. First of all, we need to bootstrap Twig. Let’s create a bootstrap.php file with the following content:
<?php

// Load our autoloader
require_once __DIR__.'/vendor/autoload.php';

// Specify our Twig templates location
$loader = new Twig_Loader_Filesystem(__DIR__.'/templates');

 // Instantiate our Twig
$twig = new Twig_Environment($loader);
Twig uses a central object called Environment. Instances of this class are used to store the configuration, extensions, and to load templates from the file system or other locations. With our Twig instance bootstrapped, we can go on and create an index.php file where we will load some data and pass it to a Twig template.
<?php

require_once __DIR__.'/bootstrap.php';

// Create a product list
$products = [
    [
        'name'          => 'Notebook',
        'description'   => 'Core i7',
        'value'         =>  800.00,
        'date_register' => '2017-06-22',
    ],
    [
        'name'          => 'Mouse',
        'description'   => 'Razer',
        'value'         =>  125.00,
        'date_register' => '2017-10-25',
    ],
    [
        'name'          => 'Keyboard',
        'description'   => 'Mechanical Keyboard',
        'value'         =>  250.00,
        'date_register' => '2017-06-23',
    ],
];

// Render our view
echo $twig->render('index.html', ['products' => $products] );
This is a simple example; we are creating an array containing products, like our mechanical keyboard, that we can use in our template. Then, we use the render() method which accepts a template name (this is a file inside the template folder that we defined earlier) and the data that we want to pass to the template. To complete our example, let’s go inside our /templates folder and create an index.html file. First, let’s take a look at the template itself.
<!DOCTYPE html>
<html lang="pt-BR">
    <head>
        <meta charset="UTF-8">
        <title>Twig Example</title>
    </head>
    <body>
    <table border="1" style="width: 80%;">
        <thead>
            <tr>
                <td>Product</td>
                <td>Description</td>
                <td>Value</td>
                <td>Date</td>
            </tr>
        </thead>
        <tbody>
            {% for product in products %}
                <tr>
                    <td>{{ product.name }}</td>
                    <td>{{ product.description }}</td>
                    <td>{{ product.value }}</td>
                    <td>{{ product.date_register|date("m/d/Y") }}</td>
                </tr>
            {% endfor %}
        </tbody>
    </table>
    </body>
</html>
Opening index.php in the browser (by visiting localhost or homestead.app, depending on how you’ve set up your hosts and server) should produce the following screen now: Rendered table But let’s go back and take a closer look at our template code. There are two types of delimiters: {{ ... }} is used to print the result of an expression or an operation and {% ... %} is used to execute statements like conditionals and loops. These delimiters are Twig’s main language constructs, and are what Twig uses to “inform” the template that it has to render a Twig element.

Layouts

In order to avoid the repetition of elements (like headers and footers) in our templates, Twig offers us the ability to nest templates inside of templates. These are called blocks. To exemplify this, let’s separate actual content from the HTML definition in our example. Let’s create a new HTML file and call it layout.html
:
<!DOCTYPE html>
<html lang="pt-BR">
    <head>
        <meta charset="UTF-8">
        <title>Tutorial Example</title>
    </head>
    <body>
        {% block content %}
        {% endblock %}
    </body>
</html>
We created a block called content. What we are saying is that every template that extends from layout.html may implement a content block that will be displayed in that position. This way we can reuse the layout multiple times without having to rewrite it. In our case, the index.html file will now look like this:
{% extends "layout.html" %}

{% block content %}
    <table border="1" style="width: 80%;">
        <thead>
            <tr>
                <td>Product</td>
                <td>Description</td>
                <td>Value</td>
                <td>Date</td>
            </tr>
        </thead>
        <tbody>
            {% for product in products %}
                <tr>
                    <td>{{ product.name }}</td>
                    <td>{{ product.description }}</td>
                    <td>{{ product.value }}</td>
                    <td>{{ product.date_register|date("m/d/Y") }}</td>
                </tr>
            {% endfor %}
        </tbody>
    </table>
{% endblock %}
Twig also allows us to render just a single block. To do that we need to first load a template and then render the block.
$template = $twig->load('index.html');
echo $template->renderBlock('content', array('products' => $products));
At this point, we still have the same page, but we reduced the complexity of it by separating contextual blocks.

Cache

The Environment object can be used for more than just loading templates. If we pass the cache option with a directory associated, Twig will cache the compiled templates so it avoids the template parsing in subsequent requests. The compiled templates will be stored in the directory we provided. Be aware that this is a cache for compiled templates, not evaluated ones. What this mean is that Twig will parse, compile and save the template file. All subsequent requests will still need to evaluate the template, but the first step is already done for you. Let’s cache the templates in our example by editing our bootstrap.php file:
$twig = new Twig_Environment($loader, ['cache' => '/templates/cache']);

Loops

In our example we’ve already seen how a loop is done using Twig. Basically, we use the for tag and assign an alias for each element in the specified array. In our case, we assigned the alias product for our products array. After that, we can access all the attributes in each array element by using the . operator. We use the endfor tag to indicate the end of our loop. We can also loop through numbers or letters using the .. operator. Just like the following:
{% for number in 0..100 %}
     {{ number }}
{% endfor %}
or for letters:
{% for letter in 'a'..'z' %}
     {{ letter }}
{% endfor %}
This operator is just syntactic sugar for the range function which works just like the native PHP range function. Also useful is the option to add a condition to a loop. With a condition, we’re able to filter which elements we want to iterate through. Imagine we want to iterate through all products whose value is less than 250:
<tbody>
    {% for product in products if product.value < 250 %}
        <tr>
            <td>{{ product.name }}</td>
            <td>{{ product.description }}</td>
            <td>{{ product.value }}</td>
            <td>{{ product.date_register|date("m/d/Y") }}</td>
    </tr>
    {% endfor %}
</tbody>

Conditionals

Twig also offers us conditionals in the form of the tags if, elseif, if not, and else. Just like in any programming language, we can use these tags to filter for conditions in our template. Imagine that, in our example, we only want to show products with a value above 500.
<tbody>
    {% for product in products %}
    {% if product.value > 500 %}
                <tr>
                    <td>{{ product.name }}</td>
                    <td>{{ product.description }}</td>
                    <td>{{ product.value }}</td>
                    <td>{{ product.date_register|date("m/d/Y") }}</td>
        </tr>
    {% endif %}
    {% endfor %}
</tbody>

Filters

Filters allow us to filter what information is passed to our template and in which format it is shown. Let’s look at some of the most used and important ones. The full list of Twig filters can be found here.

Date and date_modify

The date filter formats a date to a given format. As we can see in our example:
<td>{{ product.date_register|date("m/d/Y") }}</td>
We are showing our date in a month/day/year format. On top of the date filter, we can change the date with a modifier string using the date_modify filter. For example, if we wanted to add a day to our date we could use the following:
<td>{{ product.date_register|date_modify("+1 day")|date("m/d/Y") }}</td>

Format

Formats a given string by replacing all the placeholders. For example:
<td>{{ "This product description is: %s"|format(product.description) }}</td>

Striptags

The striptags filter strips SGML/XML tags and replaces adjacent white space with one space:
{{ <p>Hello World</p>|striptags }}`

Escape

Escape is one of the most important filters. It filters a string for safe insertion in the final output. By default, it uses the HTML escaping strategy, so
{{ products.description|escape }}
is equivalent to
{{ products.description|escape('html') }}
The js, CSS, URL and html_attr escaping strategies are also available. They escape the string for the Javascript, CSS, URI and HTML attribute contexts respectively.

Debug

Lastly, let’s take a look at debugging. Sometimes we need to access all the information on a template variable. For that effect Twig has the dump() function. This function is not available by default. We must add the Twig_Extension_Debug extension when creating our Twig environment:
$twig = new Twig_Environment($loader, array('debug' => true));
$twig->addExtension(new Twig_Extension_Debug());
This step is needed so we don’t accidentally leak debug information on a production server. After configuring it, we can just use the dump() function to dump all the information about a template variable.
{{ dump(products) }}

Conclusion

Hopefully, this article can give you a solid base on the fundamentals of Twig, and get your projects started right away! If you want to go deeper into Twig, the official website offers a very good documentation and reference that you can consult. Do you use a template engine? What do you think of Twig? Would you compare it with popular alternatives like Blade, or even Smarty?

What are the key features of Twig that make it a popular PHP template engine?

Twig is a flexible, fast, and secure template engine for PHP. It compiles templates down to plain optimized PHP code, so the overhead compared to regular PHP code is reduced to the very minimum. Twig has a sandbox mode to evaluate untrusted template code, making it a safe choice when you need to allow end-users to modify templates. It also supports multiple template inheritance, which allows you to build complex layouts with ease. Twig is also extensible, meaning you can write your own custom tags and filters.

How does Twig compare to other PHP template engines?

Twig stands out from other PHP template engines due to its simplicity, flexibility, and security. It’s designed to be easy to learn and use, yet powerful enough to handle complex tasks. Twig’s syntax is concise and expressive, making your templates easier to read and maintain. It also has built-in security features to prevent common web vulnerabilities.

How can I install and set up Twig?

Twig can be installed via Composer, a dependency management tool for PHP. You can create a new project and require Twig as a dependency. Once installed, you can set up Twig by creating a new instance of the Twig environment and loading your templates.

How can I create and render a Twig template?

To create a Twig template, you simply create a new file with the .twig extension and write your template code. You can use Twig’s syntax to insert variables, control structures, and other dynamic content. To render a Twig template, you use the render method of the Twig environment, passing in the name of the template and any variables you want to use in the template.

What are Twig filters and how do I use them?

Twig filters are functions that you can apply to variables in your templates. They allow you to manipulate the variable’s value in various ways, such as formatting a date, translating a string, or escaping HTML. You use a Twig filter by appending the pipe character (|) and the filter name to the variable.

How can I extend Twig with custom functions, filters, and tags?

Twig is highly extensible, allowing you to add your own functions, filters, and tags. You can create a new class that defines your custom functionality and then add it to the Twig environment using the addFunction, addFilter, or addTokenParser method.

How does Twig handle errors and exceptions?

Twig has a robust error handling system. If an error occurs while rendering a template, Twig will throw a Twig_Error_Runtime exception. You can catch this exception and handle it in your application code. Twig also provides detailed error messages to help you debug your templates.

How can I use Twig with Symfony?

Twig is the default template engine for Symfony, a popular PHP framework. You can use Twig to create views in your Symfony application. Symfony provides a Twig bundle that integrates Twig with the framework and adds some additional features, such as template inheritance and automatic escaping.

Can I use Twig with other PHP frameworks?

Yes, Twig can be used with any PHP framework that supports it. This includes popular frameworks like Laravel, CodeIgniter, and Zend Framework. You can also use Twig with CMS platforms like Drupal and WordPress.

Where can I find more resources to learn about Twig?

The official Twig documentation is a great place to start. It provides a comprehensive guide to Twig’s features and syntax. There are also many tutorials, blog posts, and online courses available that cover Twig in more depth.

Claudio RibeiroClaudio Ribeiro
View Author

Cláudio Ribeiro is a software developer, traveler, and writer from Lisbon. He's the author of the book An IDE Called Vim. When he is not developing some cool feature at Kununu he is probably backpacking somewhere in the world or messing with some obscure framework.

BrunoSOOPHPPHPsymfonyTemplate enginetemplate stringstwig
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week