What is Twig and how to start using it

Prerequisites: PHP

What is Twig?

Twig is a widely used and popular template engine for PHP. It provides a flexible, efficient, and secure way to separate the presentation (HTML or other markup) from the application logic in PHP-based web applications. Twig was originally developed as a part of the Symfony web framework but has since gained popularity in its own right and is used independently in various PHP projects. If you're coming from the frontend side of things, you may think of the Twig templates as something similar to React components, because the main architectural principles are the same: you compose a web app from building blocks, which display some data and can be conditionally rendered. The main difference though is that Twig is more "basic", has simpler syntax and is based on PHP.

What is Symfony?

Symfony is a high-performance PHP web application framework that facilitates the development of web applications and APIs. It follows the Model-View-Controller (MVC) architectural pattern and provides a wide range of reusable components and tools for building robust, scalable, and maintainable web applications. Symfony is open-source, well-documented, and has a large and active community of developers and contributors. You can learn more about it from this free ebook written by its creator.

What is a template engine anyway?

A template engine is a software component or system that facilitates the separation of data and presentation, also called the separation of concerns. Its primary purpose is to generate dynamic content by combining data (often referred to as the model) with templates that define the structure and layout of the final output (often referred to as the view). Separation of concerns makes the code more maintainable and easier to work with, as changes to the presentation do not require modifications to the underlying logic. Template engines provide many more useful features, such as reusable templates, dynamic content rendering and improved performance. They are commonly used in web development but can be found in other types of software as well and are especially valuable when creating applications that display dynamic data retrieved from databases, APIs, or user input.

And what are Twig templates?

Twig templates are essentially HTML files that include bits of Twig code. When the template is loaded, the placeholders in the Twig code are compiled to HTML and the resulting HTML is rendered in the browser.

Twig syntax

Twig has its own syntax that looks like a mix of PHP and HTML. The delimiters of Twig are curly braces { ... } coupled with other characters that signify what sort of Twig code it is. In brief, three basic types of Twig syntax are as follows:

syntaxmeaningpurpose
{{ ... }}print somethingused to display the content of a variable or the result of evaluating an expression
{% ... %}do somethingused to run some logic
{# ... #}comment somethingused to comment the code

All the Twig's syntax is based on the above principle. Below are some more specific examples.

Comments

Twig supports single-line comments using {# ... #}. The main feature of Twig comments is that they are only visible in Twig files, they do not get parsed to HTML comments.

{# This is a comment #}

Output variables

To output a variable's value in Twig, enclose it in double curly braces {{ ... }}. For example:

<p>{{ username }}</p>

Filters

Filters modify the output of a variable. You can apply filters using the pipe | symbol followed by the filter name.

{{ variableName | filterName }}

Twig filters are functions that allow you to modify or manipulate data within your templates. Conceptually, they are similar to inbuilt functions or methods in other programming languages. For instance, Twig filter upper achieves the same output as JavaScript's string method toUpperCase. Twig filters take an input value, perform an operation on it, and return a modified value. Filters in Twig are used to format, filter, or transform variables or expressions within your templates. You can read more about Twig filters in the docs.

Control Structures

Twig provides control structures like if, else, elseif, for, and block for conditional rendering and looping. They require an opening {% and a closing %} tag, sometimes with a nested tag in between:

{% if condition %}
    Content to display when condition is true
{% else %}
    Content to display when condition is false
{% endif %}

Loops

Twig's for loop is used for iterating over arrays and other iterable objects. It uses the for... in syntax.

{% for item in items %}
    {{ item }}
{% endfor %}

Strings

Strings are classically wrapped in either double or single quotation marks, but not the `...` backtics. Similar to HTML, if your string contains quotation marks, you can either escape the quotation mark with a backslash \ or use the other type of quotation mark.

{% set greeting = "Hello there" %}
{% set heading = 'Try the new 7" folding tablet' %}
{% set subheading = "The original Microsoft Surface was 3.5' long." %}
{% set alt_subheading = "The original Microsoft Surface was 3' 6\" long." %}

To combine strings, you can either use string concatenation with tilde ~ or use string interpolation #{...}. Important! Interpolation only works with double-quoted strings.

{# Concatenation #}
{% set greeting = "Hello, " ~ currentUser.friendlyName %}

{# Interpolation #}
{% set greeting = "Hello, #{currentUser.friendlyName}" %}

Templates

Template inheritance

The most powerful feature of Twig is template inheritance. It allows you to build a base "skeleton" of a page, that contains all the common elements of your site and defines blocks that child templates can override. Imagine a typical page (or open one, e.g. https://www.freecodecamp.org/): it has three main parts (blocks): header/navigation bar, main content, and a footer. The navbar and the footer stay the same for all the subpages, while the main content differs for each page:

To avoid repetition (the DRY principle), Twig allows us to create a 'master' template with those main blocks. Let's call it base.html.twig. Then based on this master template we can write child templates and populate them with content specific for each subpage, using the extends syntax.

{# In base.html.twig #}
<!DOCTYPE html>
<html>
<head>
    <title>{% block title %} Default Title {% endblock %}</title>
</head>
<body>
    <header>
        [header text, main navigation]
    </header>
    <main>
        {% block content %}{% endblock %}
    </main>
    <footer>
        [footer text]
    </footer> 
</body>
</html>
{# In child.html.twig #}
{% extends 'base.html.twig' %}

{% block title %} The title of this page {% endblock %}

{% block content %}
    Content specific to this page
{% endblock %}

As you already noticed, to define a block of content in Twig we specify it's a block and give it a name {% block [name of this block] %} . Similarly to all other Twig code, it needs a closing tag: {% endblock %}. Now to override the content for a particular block, in the child template we need to specify a block element with the same name, so that Twig knows which block are we referring to, and specify the content for this particular page.

Include

It is also possible to render a part of a template using the include syntax. It is used to specify reusable building blocks that can stand on it's own. You can create with it, for example, buttons, form fields, navigation elements, blocks of content or anything else that is a building block of your webpage. Twig templates that are loaded into other templates with the include syntax are independent of other templates. The main difference from the block elements is that the templates loaded with the include syntax have to be specified in separate files. For example, to define a base skeleton template from the previous example, with a navigation, main content and a footer, we can use code like this:

{# In base.html.twig #}
<!DOCTYPE html>
<html>
<head>
    <title>{% block title %} Default Title {% endblock %}</title>
</head>
<body>
    {{ include('nav.twig') }}
    <main>
        {% block content %}{% endblock %}
    </main>
    {{ include('footer.twig') }}
</body>
</html>

then our nav.twig and footer.twig can look like this:

{# In nav.twig #}
<nav>
    <ul>
        <li><a href="/">Home</a></li>
        <li><a href="/variables">Variables</a></li>
        <li><a href="/conditionals">Conditionals</a></li>
        <li><a href="/loops">Loops</a></li>
        <li><a href="/templates">Templates</a></li>
        <li><a href="https://twig.symfony.com/doc/3.x/" target="_blank">Docs</a></li>
    </ul>
</nav>
{# In footer.twig #}
<footer>
    Styled with ❤️ <a href="https://simplecss.org/">simpleCSS</a>
</footer>

`Block, extends, include - what's the difference?

Although at first it may seem confusing what are the differences and similarities between the block, extends and include syntax elements or when each of them should be used, it is rather simple.

  • include is used for reusing templates independently

  • extends establishes template inheritance

  • block defines and overrides content within templates following the inheritance hierarchy

The choice between these syntax elements depends on your specific needs: reuse, layout consistency, and content customization within your Twig templates. In more details, here is an in-depth comparison.

Featureincludeextendsblock
PurposeReusable templates: Include content from another template.Template inheritance: Extend a base template and override specific blocks.Define and override content within templates.
Syntax Example{% include 'template.html.twig' %}{% extends 'base.html.twig' %}{% block block_name %}...{% endblock %}
Template InheritanceNot used for template inheritance.Used to specify the base template for inheritance.Child templates override blocks in the base template.
Base Template StructureNo concept of a base template.Serves as the base template for child templates.Contains placeholders (blocks) for child templates to fill.
Child Template StructureIndependent of other templates.Extends and overrides blocks from the base template.Overrides blocks defined in the base template.
Extending Multiple TemplatesNot applicable.Can extend only one base template.Not applicable.
Nesting TemplatesNot applicable.Can be extended further by other templates.Not applicable.
Default Block ContentNot applicable.Blocks in the base template can have default content.Blocks in child templates can have default content.
Overriding BlocksNot applicable.Child templates can override blocks from the base template.Blocks can be overridden by child templates.
Order of RenderingRenders independently where included.Child templates extend and modify the base template.Blocks in child templates replace corresponding blocks in the base template.
Inclusion of Variables and ContextVariables can be passed when including a template.Child templates share the same context as the base template.Variables can be passed to child templates within blocks.

Installing Twig

To install Twig, you can use Composer, which is the recommended package manager for PHP projects. If you don't have Composer installed, follow the steps here: https://getcomposer.org/doc/00-intro.md. First, make sure you have PHP installed by running:

php -v

in your terminal. If you don't have PHP installed, follow the steps here: https://www.php.net/manual/en/install.php.

Once you have installed both PHP and the Composer package you can install Twig for your project by following the steps here:

  1. Create a New PHP Project (if not already done):

If you don't have an existing PHP project, create a new directory for your project and navigate to it using your terminal or command prompt.

  1. Install Symfony locally. Navigate to your project root directory and add Symfony using Composer:

     composer require symfony/symfony
    

    This will add a folder named vendor to your project, as well as two files: composer.json and composer.lock. Symfony will show up in dev dependencies in your composer.json file.

    composer.json file. { "require-dev": { "symfony/symfony": "^6.3" (v.6.3.5)}}

  2. Install Twig locally:

     composer require twig/twig
    

    This will add Twig to your dependencies in the composer.json file:

    composer.json file. { "require-dev": { "symfony/symfony": "^6.3" (v.6.3.5)}, "require": {"twig/twig": "^3.7"}}

  3. You can now start using Twig in your PHP project. To do this, create Twig templates and use the Twig library to render them in your PHP code.

    Here's an example of how to render a Twig template. First, create an index.php file, then:

     <?php
     require 'vendor/autoload.php'; // Composer's autoloader
    
     // Create a Twig environment
     $loader = new \Twig\Loader\FilesystemLoader('/path/to/templates');
     $twig = new \Twig\Environment($loader);
    
     // Render a template
     echo $twig->render('template.twig', ['variable' => 'Hello, Twig!']);
    

    Replace /path/to/templates with the actual path to your Twig templates directory and template.twig with the name of your Twig template.

  4. Create Twig Templates:

    Create your Twig templates with the .twig file extension and place them in the specified templates directory. You can use these templates to separate your HTML or other markup from your PHP logic.

That's it! You have now successfully installed and can use Twig in your PHP project.

Example

Let's render a simple string with two variables just to demonstrate how to use Twig. In the root directory of your project, create a folder named views. It is not a strict requirement to have a folder with this name, but it's a convention often used to organize Twig templates and is a recommended practice for maintaining a structured and organized project.

In your views folder create an HTML file. Let's call it hello.twig.

In index.php we'll echo two variables: name and age. In the hello.twig we will access those variables using the double curly braces syntax.

index.php
<?php
require 'vendor/autoload.php'; // Composer's autoloader

// Create a Twig environment
$loader = new \Twig\Loader\FilesystemLoader('views');
$twig = new \Twig\Environment($loader);

// Render a template
echo $twig->render('hello.twig', array(
    'name' => 'John Doe',
    'age' => 25
));
views>hello.twig

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Let's learn Twig</title>
</head>
<body>
    <header>
        <h1>Hello, {{ name }}! You are {{ age }} years old.</h1>
    </header>
</body>
</html>

Now to see how it is rendered in the browser you need to run a PHP server.

How to set up a server to run PHP locally

In a terminal, run the command:

php -S localhost:8000

This command opens a local server at port 8000 (PHP command -S : Run with built-in web server). Now you can navigate to your browser at localhost:8000 and see what is being rendered. If you followed the above steps you should see:

In case the PHP server won't run for you for some mysterious reason, there's also this neat VS code extension called PHP server from brapifra.

And that's it! You can find the code I used for the above example in this repo, with more examples in hello.html.twig file.

Happy coding!

Resources

  1. Twig documentation: https://twig.symfony.com/doc/3.x/ (official documentation)

  2. Symfony documentation on templates: https://symfony.com/doc/current/templates.html (official documentation)

  3. Introduction to templating with Twig: https://craftcms.com/docs/4.x/dev/twig-primer.html (article)

  4. Course on templating in Twig for Drupal https://symfonycasts.com/screencast/twig/basics (video course, paid)

  5. Introduction to Twig and its syntax: https://www.youtube.com/watch?v=50RBUmPOYig (YT video)

  6. Intro to Twig and templating: https://www.youtube.com/playlist?list=PLo5h1Mro0GtGoNDhF8KUWsiDdSbpnl7xr (YT playlist)

  7. Twig blocks: https://www.youtube.com/watch?v=1rHvEq3XoRU (YT video)

  8. Twig include, embed, and extends https://www.youtube.com/watch?v=XWhQku4QBD8 (YT video)

  9. Source code with examples: https://github.com/WitchDevelops/Twig-tutorial/tree/main (GitHub repository)

  10. VS code extension for syntax highlighting: https://marketplace.visualstudio.com/items?itemName=Stanislav.vscode-twig (VS code extension)

  11. VS code extension with Twig snippets, auto-completion, emmet and syntax https://marketplace.visualstudio.com/items?itemName=bajdzis.vscode-twig-pack (VS code extension)

0
Subscribe to my newsletter

Read articles from Dominika Wojewska directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Dominika Wojewska
Dominika Wojewska