Difference between Include, Extends, Use, Macro, Embed in Twig

17,597

Solution 1

After months, I am posting an answer for any further reference to this question. I also added some description for extends & import & macro & embed for more clearance:

There are various types of inheritance and code reuse in Twig:


Include

Main Goal: Code Reuse

Use Case: Using header.html.twig & footer.html.twig inside base.html.twig.

header.html.twig

<nav>
   <div>Homepage</div>
   <div>About</div>
</nav>

footer.html.twig

<footer>
   <div>Copyright</div>
</footer>

base.html.twig

{% include 'header.html.twig' %}
<main>{% block main %}{% endblock %}</main>
{% include 'footer.html.twig' %}

Extends

Main Goal: Vertical Reuse

Use Case: Extending base.html.twig inside homepage.html.twig & about.html.twig.

base.html.twig

{% include 'header.html.twig' %}
<main>{% block main %}{% endblock %}</main>
{% include 'footer.html.twig' %}

homepage.html.twig

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

{% block main %}
<p>Homepage</p>
{% endblock %}

about.html.twig

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

{% block main %}
<p>About page</p>
{% endblock %}

Use

Main Goal: Horizontal Reuse

Use Case: sidebar.html.twig in single.product.html.twig & single.service.html.twig.

sidebar.html.twig

{% block sidebar %}<aside>This is sidebar</aside>{% endblock %}

single.product.html.twig

{% extends 'product.layout.html.twig' %}

{% use 'sidebar.html.twig' %}

{% block main %}<main>Product page</main>{% endblock %}

single.service.html.twig

{% extends 'service.layout.html.twig' %}

{% use 'sidebar.html.twig' %}

{% block main %}<main>Service page</main>{% endblock %}

Notes:

  1. It's like macros, but for blocks.
  2. The use tag only imports a template if it does not extend another template, if it does not define macros, and if the body is empty.

Macro

Main Goal: Reusable Markup with Variables

Use Case: 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 "form.html.twig" as form %}

<form action="/login" method="post">
    <div>{{ form.input('username') }}</div>
    <div>{{ form.input('password') }}</div>
    <div>{{ form.input('submit', 'Submit', 'submit') }}</div>
</form>

Embed

Main Goal: Block Overriding

Use Case: Embedding pagination.html.twig in product.table.html.twig & service.table.html.twig.

pagination.html.twig

<div id="pagination">
    <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) has access to the current context (min, max variables).

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 %}

Note:

It has functionality of both Use & Include together.

Solution 2

Twig performance is spectacular, so chances are you will never care, but be aware that there is a significant difference between using embeds, includes, or macros.

I set up a little test project to demonstrate it: https://github.com/janklan/twig-benchmark

The readme has all the information you need if you're interested to know more, but the general result is, that for the same task executed in a loop of 100k iterations, the times between individual methods on my computer were as follows (lower is better)

  • embed: 4253ms
  • include: 3428ms
  • macro: 2695ms

By the way, the project I shared via Github up generates separate cache directories for each approach (embed/include/macro). If you want to see how different methods in Twig map to the complied PHP, I recommend you check it out. If you wish to see the cache without having to run the project, check out a branch called with-cache

Share:
17,597
Peyman Mohamadpour
Author by

Peyman Mohamadpour

Software Development Consultant, Advanced in Web-based software

Updated on June 16, 2022

Comments

  • Peyman Mohamadpour
    Peyman Mohamadpour almost 2 years

    What is the difference between use and include in Twig?

    Documentation:

    include

    The include statement includes a template and returns the rendered content of that template into the current one:

    {% include 'header.html' %}
    Body here...
    {% include 'footer.html' %}
    

    use

    The use statement tells Twig to import the blocks defined in blocks.html into the current template (it's like macros, but for blocks):

    blocks.html

    {% block sidebar %}{% endblock %}
    

    main.html

    {% extends "base.html" %}
    {% use "blocks.html" %}
    {% block title %}{% endblock %}
    {% block content %}{% endblock %}
    

    Possible answer:

    I think this should explain the difference:

    include is to get all the code from an external file and import it into your actual file at the right location of the call.

    use is completely different as it parses the linked file to find a particular section of code and then overwrites the blocks with the same name, in your current file, with the one found in this external file.

    include is like "go find this file and render it with my page here".

    use is "parse this other file to find block definitions to use instead of my owns defined here".

    If use command finds nothing matching the task, nothing is displayed at all from this file.


    Question

    is the explanation correct? are there any other explanations to this difference?