There are various types of inheritance and code reuse in Twig:
The main goal is code reuse. Consider using header.html.twig
& footer.html.twig
inside base.html.twig
as an example.
header.html.twig
<nav>
<div>Homepage</div>
<div>About</div>
</nav>
base.html.twig
{% include 'header.html.twig' %}
<main>{% block main %}{% endblock %}</main>
The main goal is vertical inheritance. Consider extending base.html.twig
inside homepage.html.twig
and about.html.twig
as an example.
base.html.twig
{% include 'header.html.twig' %}
<main>{% block main %}{% endblock %}</main>
homepage.html.twig
{% extends 'base.html.twig' %}
{% block main %}
<p>You are at the homepage</p>
{% endblock %}
about.html.twig
{% extends 'base.html.twig' %}
{% block main %}
<p>You are at the about page</p>
{% endblock %}
The main goal is horizontal reuse. Consider using sidebar.product.html.twig
inside single.product.html.twig
(extends product.layout.html.twig
) and single.service.html.twig
(extends 'service.layout.html.page') pages. (it's like macros, but for blocks)
sidebar.html.twig
<aside>{% block sidebar %}{% endblock %}</aside>
single.product.html.twig
{% extends 'product.layout.html.twig' %}
{% use 'sidebar.html.twig' %}
{% block main %}
<p>You are at the product page for product number 123</p>
{% endblock %}
single.service.html.twig
{% extends 'service.layout.html.twig' %}
{% use 'sidebar.html.twig' %}
{% block main %}
<p>You are at the service page for service number 456</p>
{% endblock %}
The main goal is having reusable markup across many templates with variables. Consider a function which gets some variables and outputs some markup.
form.html.twig
{% macro input(name, value, type) %} <input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value|e }}" }}" /> {% endmacro %}
profile.service.html.twig
{% import "forms.html.twig" as forms %}
<div>{{ forms.input('username') }}</div>
The main goal is block overriding. It has functionality of both Use
& Include
together. Consider embedding pagination.html.twig
in product.table.html.twig
& service.table.html.twig
.
pagination.html.twig
<div>
<div>{% block first %}{% endblock %}</div>
{% for i in (min + 1)..(max - 1) %}
<div>{{ i }}</div>
{% endfor %}
<div>{% block last %}{% endblock %}</div>
</div>
product.table.html.twig
{% set min, max = 1, products.itemPerPage %}
{% embed 'pagination.html.twig' %}
{% block first %}First Product Page{% endblock %}
{% block last %}Last Product Page{% endblock %}
{% endembed %}
service.table.html.twig
{% set min, max = 1, services.itemPerPage %}
{% embed 'pagination.html.twig' %}
{% block first %}First Service Page{% endblock %}
{% block last %}Last Service Page{% endblock %}
{% endembed %}
Please note that embedded file (pagination.html.twig
here) has access to the current context (min
, max
variables here). Also you may pass extra variables to the embedded file:
pagination.html.twig
<p>{{ count }} items</p>
<div>
<div>{% block first %}{% endblock %}</div>
{% for i in (min + 1)..(max - 1) %}
<div>{{ i }}</div>
{% endfor %}
<div>{% block last %}{% endblock %}</div>
</div>
product.table.html.twig
{% set min, max = 1, products|length %}
{% embed 'pagination.html.twig' with {'count': products|length } %}
{% block first %}First Product Page{% endblock %}
{% block last %}Last Product Page{% endblock %}
{% endembed %}