block construct

A block construct plays two different roles depending on where it is placed. It can work as a placeholder with default content in parent templates or it can work as a content overrider in child templates.

Parent Template is an extendable template, meaning that other templates can extend it. This templates do not contain the extends construct (as shown previously).

Child Templates extend parent templates redefining its blocks. This templates contain the extends construct.

A block has an associated identifier, used as the way to reference it within child templates.

{% block blockId %}
  ... content here ...
{% endblock %}

From the previous example, the given block is identified with blockId, this mandatory identifier is also the only argument available for the block construct.

block as content placeholder

The block construct, as mentioned before, can be used as a content placeholder to define content that could be then replaced. A block is a content placeholder when used inside a parent template.

block as content overrider

The block construct, can also be used as a content overrider. This happens when the block is used underneath a child template.

How does it work

A block provides a way to change how a certain part of a template is rendered but it does not interfere in any way with the logic around it. Let’s take the following example to illustrate how a block works and more importantly, how it does not work:

{# block-base.twig #}

{% for post in posts %}
    {% block post %}
        <h1>{{ post.title }}</h1>
        <p>{{ post.body }}</p>
    {% endblock %}
{% endfor %}

If you render this template, the result would be exactly the same with or without the block tag. The block inside the for loop is just a way to make it overridable by a child template:

{# block-child.twig #}

{% extends "block-base.twig" %}

{% block post %}
    <article>
        <header>{{ post.title }}</header>
        <section>{{ post.text }}</section>
    </article>
{% endblock %}

Now, when rendering the child template, the loop is going to use the block defined in the child template instead of the one defined in the base one; the executed template is then equivalent to the following one:

{% for post in posts %}
    <article>
        <header>{{ post.title }}</header>
        <section>{{ post.text }}</section>
    </article>
{% endfor %}