Twig
01 / 02

Twig: Template Inheritance, Macros & Best Practices

Twig: Template Inheritance, Macros & Best Practices

Template Inheritance

{# base.html.twig #}
<html>
<body>
  <header>{% include 'partials/nav.html.twig' %}</header>
  {% block content %}{% endblock %}
  <footer>...</footer>
</body>
</html>

{# page.html.twig -- fills in just the content block, shared
   header/footer never need to be duplicated #}
{% extends 'base.html.twig' %}
{% block content %}
  <p>Page-specific content here.</p>
{% endblock %}

include vs. extends

{# include: reusable fragment embedded at a specific point #}
{% include 'partials/product-card.html.twig' with {product: item} %}

{# extends: overall page LAYOUT relationship -- one parent, many
   child pages customizing specific named blocks #}

Macros: Reusable Parameterized Markup

{% macro input(name, value, type = 'text') %}
  <input type="{{ type }}" name="{{ name }}" value="{{ value }}">
{% endmacro %}

{# usage -- avoids repeated markup across many form templates #}
{{ forms.input('email', user.email) }}

set, Concatenation & verbatim

{% set fullName = user.firstName ~ ' ' ~ user.lastName %}
{{ fullName }}

{# ~ concatenates -- Twig uses . for property/method access #}

{% verbatim %}
  Documentation showing literal {{ variable }} syntax as example text
{% endverbatim %}

Keeping Logic Out of Templates

Compute business logic in PHP controllers/services and pass the result into the template, rather than embedding it directly. Twig's deliberately restricted syntax keeps templates focused on presentation -- easier to test and safer for designers to edit without breaking application behavior. Sandbox mode further restricts available functions/filters when template content comes from a less-trusted source.

Keep your own version of these notes — editable, searchable, and organised by your stack.

Start free