| ``extends`` |
| =========== |
| |
| The ``extends`` tag can be used to extend a template from another one. |
| |
| .. note:: |
| |
| Like PHP, Twig does not support multiple inheritance. So you can only have |
| one extends tag called per rendering. However, Twig supports horizontal |
| :doc:`reuse<use>`. |
| |
| Let's define a base template, ``base.html``, which defines a simple HTML |
| skeleton document: |
| |
| .. code-block:: html+twig |
| |
| <!DOCTYPE html> |
| <html> |
| <head> |
| {% block head %} |
| <link rel="stylesheet" href="style.css"/> |
| <title>{% block title %}{% endblock %} - My Webpage</title> |
| {% endblock %} |
| </head> |
| <body> |
| <div id="content">{% block content %}{% endblock %}</div> |
| <div id="footer"> |
| {% block footer %} |
| © Copyright 2011 by <a href="http://domain.invalid/">you</a>. |
| {% endblock %} |
| </div> |
| </body> |
| </html> |
| |
| In this example, the :doc:`block<block>` tags define four blocks that child |
| templates can fill in. |
| |
| All the ``block`` tag does is to tell the template engine that a child |
| template may override those portions of the template. |
| |
| Child Template |
| -------------- |
| |
| A child template might look like this: |
| |
| .. code-block:: html+twig |
| |
| {% extends "base.html" %} |
| |
| {% block title %}Index{% endblock %} |
| {% block head %} |
| {{ parent() }} |
| <style type="text/css"> |
| .important { color: #336699; } |
| </style> |
| {% endblock %} |
| {% block content %} |
| <h1>Index</h1> |
| <p class="important"> |
| Welcome on my awesome homepage. |
| </p> |
| {% endblock %} |
| |
| The ``extends`` tag is the key here. It tells the template engine that this |
| template "extends" another template. When the template system evaluates this |
| template, first it locates the parent. The extends tag should be the first tag |
| in the template. |
| |
| Note that since the child template doesn't define the ``footer`` block, the |
| value from the parent template is used instead. |
| |
| You can't define multiple ``block`` tags with the same name in the same |
| template. This limitation exists because a block tag works in "both" |
| directions. That is, a block tag doesn't just provide a hole to fill - it also |
| defines the content that fills the hole in the *parent*. If there were two |
| similarly-named ``block`` tags in a template, that template's parent wouldn't |
| know which one of the blocks' content to use. |
| |
| If you want to print a block multiple times you can however use the |
| ``block`` function: |
| |
| .. code-block:: html+twig |
| |
| <title>{% block title %}{% endblock %}</title> |
| <h1>{{ block('title') }}</h1> |
| {% block body %}{% endblock %} |
| |
| Parent Blocks |
| ------------- |
| |
| It's possible to render the contents of the parent block by using the |
| :doc:`parent<../functions/parent>` function. This gives back the results of |
| the parent block: |
| |
| .. code-block:: html+twig |
| |
| {% block sidebar %} |
| <h3>Table Of Contents</h3> |
| ... |
| {{ parent() }} |
| {% endblock %} |
| |
| Named Block End-Tags |
| -------------------- |
| |
| Twig allows you to put the name of the block after the end tag for better |
| readability (the name after the ``endblock`` word must match the block name): |
| |
| .. code-block:: twig |
| |
| {% block sidebar %} |
| {% block inner_sidebar %} |
| ... |
| {% endblock inner_sidebar %} |
| {% endblock sidebar %} |
| |
| Block Nesting and Scope |
| ----------------------- |
| |
| Blocks can be nested for more complex layouts. Per default, blocks have access |
| to variables from outer scopes: |
| |
| .. code-block:: html+twig |
| |
| {% for item in seq %} |
| <li>{% block loop_item %}{{ item }}{% endblock %}</li> |
| {% endfor %} |
| |
| Block Shortcuts |
| --------------- |
| |
| For blocks with little content, it's possible to use a shortcut syntax. The |
| following constructs do the same thing: |
| |
| .. code-block:: twig |
| |
| {% block title %} |
| {{ page_title|title }} |
| {% endblock %} |
| |
| .. code-block:: twig |
| |
| {% block title page_title|title %} |
| |
| Dynamic Inheritance |
| ------------------- |
| |
| Twig supports dynamic inheritance by using a variable as the base template: |
| |
| .. code-block:: twig |
| |
| {% extends some_var %} |
| |
| If the variable evaluates to a ``\Twig\Template`` or a ``\Twig\TemplateWrapper`` |
| instance, Twig will use it as the parent template:: |
| |
| // {% extends layout %} |
| |
| $layout = $twig->load('some_layout_template.twig'); |
| |
| $twig->display('template.twig', ['layout' => $layout]); |
| |
| You can also provide a list of templates that are checked for existence. The |
| first template that exists will be used as a parent: |
| |
| .. code-block:: twig |
| |
| {% extends ['layout.html', 'base_layout.html'] %} |
| |
| Conditional Inheritance |
| ----------------------- |
| |
| As the template name for the parent can be any valid Twig expression, it's |
| possible to make the inheritance mechanism conditional: |
| |
| .. code-block:: twig |
| |
| {% extends standalone ? "minimum.html" : "base.html" %} |
| |
| In this example, the template will extend the "minimum.html" layout template |
| if the ``standalone`` variable evaluates to ``true``, and "base.html" |
| otherwise. |
| |
| How do blocks 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: |
| |
| .. code-block:: html+twig |
| |
| {# 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: |
| |
| .. code-block:: html+twig |
| |
| {# child.twig #} |
| {% extends "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: |
| |
| .. code-block:: html+twig |
| |
| {% for post in posts %} |
| <article> |
| <header>{{ post.title }}</header> |
| <section>{{ post.text }}</section> |
| </article> |
| {% endfor %} |
| |
| Let's take another example: a block included within an ``if`` statement: |
| |
| .. code-block:: html+twig |
| |
| {% if posts is empty %} |
| {% block head %} |
| {{ parent() }} |
| |
| <meta name="robots" content="noindex, follow"> |
| {% endblock head %} |
| {% endif %} |
| |
| Contrary to what you might think, this template does not define a block |
| conditionally; it just makes overridable by a child template the output of |
| what will be rendered when the condition is ``true``. |
| |
| If you want the output to be displayed conditionally, use the following |
| instead: |
| |
| .. code-block:: html+twig |
| |
| {% block head %} |
| {{ parent() }} |
| |
| {% if posts is empty %} |
| <meta name="robots" content="noindex, follow"> |
| {% endif %} |
| {% endblock head %} |
| |
| .. seealso:: |
| |
| :doc:`block<../functions/block>`, :doc:`block<../tags/block>`, :doc:`parent<../functions/parent>`, :doc:`use<../tags/use>` |