Symfony: Separating Twig templates into reusable blocks (with examples)

Updated: January 14, 2024 By: Guest Contributor Post a comment

Overview

When building web applications with Symfony and using its default templating engine, Twig, it is important to employ a modular approach to your templates. This not only keeps your templates clean and readable but also promotes reusability and maintainability of your views throughout the application. In this tutorial, we’ll delve into how to separate Twig templates into reusable blocks in Symfony, using examples to illustrate these practices.

Introduction to Twig

Before diving into the specific approach of using reusable blocks, it’s crucial to understand the basics of Twig. Twig is a flexible, fast, and secure template engine for PHP. It allows you to define the structure of your web pages and inject data into them with ease. One of its powerful features is inheritance, which allows one template to extend another and override certain sections or “blocks” of it.

Template Inheritance

Example:

{% extends 'base.html.twig' %}

{% block title %}Page Title{% endblock %}
{% block body %}
    <!-- Page content goes here -->
{% endblock %}

Here, we are declaring that our template is extending a base template called ‘base.html.twig’ and overriding the ‘title’ and ‘body’ blocks. Any HTML markup or other blocks we place within the ‘body’ block will be unique to the current template, while everything else will be inherited from the base template.

Creating Reusable Blocks

To promote reusability, you might want to consider creating blocks that you can reuse across different templates. An example might be a navigation bar or a footer that is consistent across all pages.

{% block navbar %}
    <nav>
        <!-- Navbar content -->
    </nav>
{% endblock %}

{% block footer %}
    <footer>
        <!-- Footer content -->
    </footer>
{% endblock %}

With these defined in your base template, individual pages can opt to override these as needed or rely on the base template’s implementation.

Including Templates

Another way to reuse code is by including smaller, focused templates where needed using the {% include %} statement. This is ideal for components that are not blocks by nature but are reusable segments of your UI. For instance:

<!-- product_card.html.twig -->
<div class="product-card">
    <h3>{{ product.name }}</h3>
    <p>{{ product.description }}</p>
</div>

<!-- In another template -->
{% for product in products %}
    {% include 'product_card.html.twig' with {'product': product} %}
{% endfor %}

Here we’re iterating over a set of products and including the ‘product_card.html.twig’ template for each one, passing the current product in the loop to the included template. This keeps your individual product cards in one place for easy tweaks and maintenance.

Using Macros

Macros, in Twig, are akin to functions in traditional programming languages and are another tool to create reusable and maintainable components in your templates.

{% macro input(name, value, type = 'text', required = false) %}
<label&gt {{ name }}</label>
<input type="{{ type }}" name="{{ name }}" value="{{ value }}" {% if required %}required{% endif %}>
{% endmacro %}

{% import _self as forms %}

<!-- Use the macro like this -->
{{ forms.input('email', '', 'email', true) }}
{{ forms.input('password', '', 'password', true) }}

This example defined an ‘input’ macro, then imported it with a namespace (forms), and used it to create required input fields for email and password.

Blocks and Layouts

For more complex applications, you might have different types of pages that require unique layouts. By using blocks wisely, we can scaffold out these layouts and make them adaptable based on the content needed.

Consider a two-column layout where the second column is optional:

{% extends 'base.html.twig' %}

{% block body %}
    <div class="content">
        {% block main_content %}{% endblock main_content %}
    </div>
    {% block sidebar %}
        <!-- Sidebar content only if required -->
    {% endblock sidebar %}
{% endblock body %}

In a child template:

{% extends 'two_column_layout.html.twig' %}

{% block main_content %}
    <p>Main content goes here.</p>
{% endblock main_content %}

{% block sidebar %}
    <p>Optional sidebar content.</p>
{% endblock sidebar %}

By using Twig’s template inheritance, blocks, includes, and macros, you can create complex web applications with reusable, easy-to-maintain components. Keep experimenting with these elements to find the combination that best suits your application’s needs, and enjoy the streamlined process of constructing your application’s interface.

Final Words

Implementing the mentioned techniques into your Symfony and Twig development workflow can greatly increase the efficiency of the development process. By understanding and utilizing the power of Twig’s templating features, you ensure a flexible and maintainable template architecture that can adapt to the ever-changing demands of web development.