Mastering Twig (DrupalCon Barcelona 2015)
-
Upload
javier-eguiluz -
Category
Technology
-
view
5.107 -
download
2
Transcript of Mastering Twig (DrupalCon Barcelona 2015)
![Page 1: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/1.jpg)
Javier EguiluzSeptember 22, 2015
TwigTRACK ROOM DATE SPEAKERSymfony 115
Mastering
![Page 2: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/2.jpg)
License of this presentation
creativecommons.org/licenses/by-nc-sa/3.0
![Page 3: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/3.jpg)
ABOUT ME
![Page 4: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/4.jpg)
Javier EguiluzSymfony Evangelist
![Page 5: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/5.jpg)
ABOUT THIS TALK
![Page 6: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/6.jpg)
We won't talk about Twig basics.
We won't provide all the low-level details.
How can I create a theme? Which is
the syntax of Twig?
Read the excellent Twig documentation to get
those details.
![Page 7: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/7.jpg)
DRUPAL & TWIG
![Page 8: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/8.jpg)
Fast Easy to learn
Documented Concise Full featured
Extensible Tested Useful errors
Secure
Main Twig features
![Page 9: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/9.jpg)
My favorite feature
Consistent
![Page 10: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/10.jpg)
My favorite feature
Twig defines a very small set of features…
… which are enough to create any template
Consistent
same syntax and behavior since day one!
easy to learn!
![Page 11: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/11.jpg)
«Using Twig templatesis the best decisionDrupal ever made»
![Page 12: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/12.jpg)
DRUPAL 8
TWIG
Built-in Drupal templates use ~30% of the
available Twig features.
![Page 13: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/13.jpg)
AGENDA
![Page 14: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/14.jpg)
Defensive programming White spaces
Debug Escaping Reusing templates
Dates Dynamic templates
Cool features
Variables
Agenda
![Page 15: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/15.jpg)
ACCESSING VARIABLES
![Page 16: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/16.jpg)
WHY IS THIS IMPORTANT??
Because you can easily improve the performance of your site/app.
![Page 17: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/17.jpg)
Accessing simple variables!
<p class="comment__author">{{ author }}</p>
<p class="comment__time">{{ created }}</p>
<p class="comment__permalink">{{ permalink }}</p>
core/themes/bartik/templates/comment.html.twig
![Page 18: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/18.jpg)
Accessing complex variables!
<nav>{{ content.links }}</nav>
core/themes/bartik/templates/comment.html.twig
![Page 19: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/19.jpg)
Accessing complex variables!
<nav>{{ content.links }}</nav>
core/themes/bartik/templates/comment.html.twig
![Page 20: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/20.jpg)
This is how Twig resolves complex variables
<nav>{{ content.links }}</nav> !
$content['links']
$content->links
$content->links()
$content->getLinks()
$content->isLinks()
null
Twig tries all these alternatives and uses the first one that exists.
![Page 21: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/21.jpg)
And what about performance?
![Page 22: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/22.jpg)
Resolving variables is quite expensive
<nav>{{ content.links }}</nav> !
$content['links']
$content->links
$content->links()
$content->getLinks()
$content->isLinks()
null
Resolving a variable is the most expensive Twig task, specially for very complex templates.
![Page 23: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/23.jpg)
Improving Twig performance• Twig provides a PHP extension. • This extension only implements
the variable resolving logic. • See twig.sensiolabs.org/doc/
installation.html#installing-the-c-extension
EXPECTEDPERFORMANCE
INCREASE
15%
![Page 24: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/24.jpg)
Some Drupal variables names are special
!
$variables['site_slogan']['#markup'] = ... !
{{ site_slogan.#markup }}
core/themes/bartik/bartik.theme
This doesn't work because of the # character
![Page 25: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/25.jpg)
Some Drupal variables names are special
!
$variables['site_slogan']['#markup'] = ... !
{{ site_slogan.#markup }}
core/themes/bartik/bartik.theme
This doesn't work because of the # character
{{ site_slogan['#markup'] }}
{{ attribute(site_slogan, '#markup') }}
![Page 26: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/26.jpg)
DEFENSIVE PROGRAMMING
![Page 27: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/27.jpg)
WHY IS THIS IMPORTANT??
Because sooner or later errors will happen. What matters is how you deal with them.
![Page 28: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/28.jpg)
Dealing with undefined/empty variables
is empty defaultis defined
is null {% if %}
![Page 29: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/29.jpg)
The two recommended safeguards
{% if variable %} ... {% endif %} !
!
Hi {{ variable|default('user') }}
![Page 30: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/30.jpg)
The two recommended safeguards
{% if variable %} ... {% endif %} !
!
Hi {{ variable|default('user') }}
It checks that variable is not null or empty or zero !
ONLY works if variable is defined
![Page 31: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/31.jpg)
The two recommended safeguards
{% if variable %} ... {% endif %} !
!
Hi {{ variable|default('user') }}
It checks that variable is not null or empty or zero !
ONLY works if variable is defined
It checks that variable is not null, empty or undefined !
It ALWAYS works as expected
![Page 32: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/32.jpg)
Combining both safeguards
{% if variable|default('user') %} ... {% endif %} It doesn't matter if the variable is not
defined, because the expression will always have a default value.
![Page 33: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/33.jpg)
Checking that the variable is defined
{% if variable is defined %} ... {% endif %} A good practice when the rendered
template cannot be sure about the variables passed from the code. !
In Drupal 8 this problem should not happen (the variable list is strict).
![Page 34: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/34.jpg)
Other safeguards available
{% if variable is null %} ... {% endif %} !
!
{% if variable is empty %} ... {% endif %} {% if variable is not empty %} ... {% endif %}
![Page 35: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/35.jpg)
Be ready when iterating empty collections
{% for item in collection %}
...
{% else %}
There are no items.
{% endfor %}
![Page 36: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/36.jpg)
Filter values before using them in the loop
{% for item in collection if item.published %}
...
{% else %}
There are no items.
{% endfor %}
![Page 37: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/37.jpg)
Avoid missing templates
{{ include('menu.twig') }}
This will always work because our theme will provide this template.
![Page 38: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/38.jpg)
Avoid missing templates
{{ include('menu.twig') }}
This will always work because our theme will provide this template.
Templates with dynamic paths are very prone to error
{{ include('users/' ~ user.name ~ '/bio.twig') }}
![Page 39: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/39.jpg)
Define fallback templates
{{ include([
'users/' ~ user.name ~ '/bio.twig',
'users/' ~ user.name ~ '/default.twig',
'common/user_bio.twig'
]) }}Twig includes the first template that exists
![Page 40: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/40.jpg)
Avoid missing templates• Sometimes it's not possible to provide fallback
templates. • Moreover, in some cases, it's better to ignore the
missing template instead of displaying an error to the user.
![Page 41: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/41.jpg)
Ignore missing templates{{ include('template.twig', ignore_missing = true) }} !
{{ source('template.twig', ignore_missing = true) }} !
{% embed 'template.twig' ignore missing %} ... {% endembed %}
![Page 42: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/42.jpg)
Ignore missing templates{{ include('template.twig', ignore_missing = true) }} !
{{ source('template.twig', ignore_missing = true) }} !
{% embed 'template.twig' ignore missing %} ... {% endembed %} NOTE
no underscore here
![Page 43: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/43.jpg)
Twig filters defined by Drupal 8{{ value|t }} {{ value|trans }} {{ value|passthrough }} {{ value|placeholder }} {{ value|drupal_escape }} {{ value|safe_join }} {{ value|without }} {{ value|clean_class }} {{ value|clean_id }} {{ value|render }}
It's common for a long-standing and complex project to add and remove filters. !
If Drupal removes a filter used by your templates, your site/app will break.
![Page 44: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/44.jpg)
Declare filters as deprecatednew Twig_SimpleFilter('old_filter', ..., array(
'deprecated' => true,
'alternative' => 'new_filter'
));
![Page 45: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/45.jpg)
Declare filters as deprecatednew Twig_SimpleFilter('old_filter', ..., array(
'deprecated' => true,
'alternative' => 'new_filter'
));
These deprecations notices are not displayed or logged anywhere on Drupal yet.
NOTE
![Page 46: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/46.jpg)
Avoid missing blocks
{% if 'title' is block %}
<title>{{ block('title') }}<title>
{% endif %}
![Page 47: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/47.jpg)
This feature is not available yet. It will be included in the upcoming 1.23 version of Twig.
NOTE
Avoid missing blocks
{% if 'title' is block %}
<title>{{ block('title') }}<title>
{% endif %}
![Page 48: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/48.jpg)
WHITE SPACES
![Page 49: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/49.jpg)
WHY IS THIS IMPORTANT??
Because it will make your templates more readable and it will save you time.
![Page 50: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/50.jpg)
<ul> <li>1</li> <li>2</li> <li>3</li> </ul>
<ul> <li>1</li> <li>2</li> <li>3</li> </ul>
The "problem" of white spaces
Twig template HTML page
![Page 51: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/51.jpg)
<ul> {% for i in 1..3 %} <li>{{ i }}</li> {% endfor %} </ul>
<ul> <li>1</li> <li>2</li> <li>3</li> </ul>
The "problem" of white spaces
Twig template HTML page
![Page 52: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/52.jpg)
<ul> {% for i in 1..3 %} <li>{{ i }}</li> {% endfor %} </ul>
<ul> <li>1</li> <li>2</li> <li>3</li> </ul>
The "problem" of white spaces
Twig template HTML page
![Page 53: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/53.jpg)
<ul> {% for i in 1..3 %} <li>{{ i }}</li> {% endfor %} </ul>
<ul> <li>1</li> <li>2</li> <li>3</li> </ul>
The "problem" of white spaces
Twig template HTML page
![Page 54: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/54.jpg)
<ul> {% for i in 1..3 %} <li>{{ i }}</li> {% endfor %} </ul>
<ul> <li>1</li> <li>2</li> <li>3</li> </ul>
The "problem" of white spaces
Twig template HTML page
![Page 55: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/55.jpg)
<ul> {% for i in 1..3 %} <li>{{ i }}</li> {% endfor %} </ul>
<ul> <li>1</li> <li>2</li> <li>3</li> </ul>
The "problem" of white spaces
Twig template HTML page
![Page 56: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/56.jpg)
Removing white spaces
<ul> {%- for i in 1..3 -%} <li>{{ i }}</li> {%- endfor -%} </ul>
<ul> {% spaceless %} {% for i in 1..3 %} <li>{{ i }}</li> {% endfor %} {% endspaceless %} </ul>
![Page 57: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/57.jpg)
Please, don't waste your time dealing with
white spaces.
![Page 58: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/58.jpg)
!
Twig templates should be readable
HTML pages should not!
![Page 59: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/59.jpg)
!
Twig templates should be readable
HTML pages should not
this is where you work everyday
!
browsers get a minimized and compressed HTML mess
![Page 60: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/60.jpg)
Sometimes you should add white spaces…
![Page 61: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/61.jpg)
White spaces around HTML attributes
<h2{{ title_attributes }}>{{ label }}</h2> core/modules/block/templates/block.html.twig
![Page 62: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/62.jpg)
White spaces around HTML attributes
<h2{{ title_attributes }}>{{ label }}</h2> core/modules/block/templates/block.html.twig
![Page 63: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/63.jpg)
White spaces around HTML attributes
<h2{{ title_attributes }}>{{ label }}</h2> core/modules/block/templates/block.html.twig
no white space when the attributes are empty
<h2 class="..."> ... </h2>
<h2> ... </h2>
![Page 64: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/64.jpg)
Add white spaces to separate Twig & HTML
<h2 {{ title_attributes }}>{{ label }}</h2> !
!
<h2 class="..."> ... </h2>
<h2 > ... </h2>
![Page 65: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/65.jpg)
Add white spaces to separate Twig & HTML
<h2 {{ title_attributes }}>{{ label }}</h2> !
!
<h2 class="..."> ... </h2>
<h2 > ... </h2>
white space when the attributes are empty
![Page 66: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/66.jpg)
Add white spaces to separate Twig & HTML
<h2 {{ title_attributes }}>{{ label }}</h2> !
!
<h2 class="..."> ... </h2>
<h2 > ... </h2>
white space when the attributes are empty
IT DOES NOT MATTER
Twig template is more readable
HTML code with white spaces is still valid
![Page 67: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/67.jpg)
Hiding HTML code inside Twig strings<div id="site-name"{{ hide_name ? ' class="hidden"' }}> !
!
!
!
!
<div id="site-name">
<div id="site-name" class="hidden">
core/themes/bartik/templates/maintenance-page.html.twig
![Page 68: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/68.jpg)
Hiding HTML code inside Twig strings<div id="site-name"{{ hide_name ? ' class="hidden"' }}> !
!
!
!
!
<div id="site-name">
<div id="site-name" class="hidden">
core/themes/bartik/templates/maintenance-page.html.twig
![Page 69: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/69.jpg)
Hiding HTML code inside Twig strings<div id="site-name"{{ hide_name ? ' class="hidden"' }}> !
!
!
!
!
<div id="site-name">
<div id="site-name" class="hidden">
WARNINGHTML attributes
defined in Twig strings are easy to overlook
core/themes/bartik/templates/maintenance-page.html.twig
![Page 70: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/70.jpg)
Hiding HTML code inside Twig strings<div id="site-name"{{ hide_name ? ' class="hidden"' }}> !
!
!
!
!
<div id="site-name">
<div id="site-name" class="hidden">
WARNINGHTML attributes
defined in Twig strings are easy to overlook
core/themes/bartik/templates/maintenance-page.html.twig
DANGERIf you miss this single white space, the page
design breaks
![Page 71: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/71.jpg)
Don't hide HTML code inside Twig strings<div id="site-name" class="{{ hide_name ? 'hidden' }}"> !
!
!
!
!
<div id="site-name" class="">
<div id="site-name" class="hidden">
HTML & Twig are decoupled
A single white space won't break the page
![Page 72: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/72.jpg)
Don't hide HTML code inside Twig strings<div id="site-name" class="{{ hide_name ? 'hidden' }}"> !
!
!
!
!
<div id="site-name" class="">
<div id="site-name" class="hidden">Valid HTML code
(tested with the W3C validator)
HTML & Twig are decoupled
A single white space won't break the page
![Page 73: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/73.jpg)
DEBUG
![Page 74: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/74.jpg)
WHY IS THIS IMPORTANT??
Because it will save you a lot of time while developing your templates.
![Page 75: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/75.jpg)
Configure Twig behavior
# sites/default/services.yml parameters: twig.config: debug: true auto_reload: null cache: true
![Page 76: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/76.jpg)
Configure Twig behavior
# sites/default/services.yml parameters: twig.config: debug: true auto_reload: null cache: true
Include debug information in the rendered HTML contents
In production server, always set it to false
![Page 77: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/77.jpg)
HTML content of a rendered Drupal template
<div id="block-bartik-login" class="contextual-region block block-user block-user-login-block" role="form"> <h2>User login</h2> <div data-contextual-id="block:block=bartik_login:langcode=en"></div> <div class="content"> !<form class="user-login-form" data-drupal-selector="user-login-form" action="/node?destination=/node" method="post" id="user-login-form" accept-charset="UTF-8"> !<!-- ... -->
![Page 78: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/78.jpg)
HTML content when Twig debug is enabled
<!-- THEME DEBUG --> <!-- THEME HOOK: 'block' --> <!-- FILE NAME SUGGESTIONS: * block--bartik-login.html.twig * block--user-login-block.html.twig * block--user.html.twig x block.html.twig --> <!-- BEGIN OUTPUT from 'core/themes/bartik/templates/block.html.twig' --> <div id="block-bartik-login" class="contextual-region block block-user block-user-login-block" role="form"> <h2>User login</h2> <div data-contextual-id="block:block=bartik_login:langcode=en"></div> <div class="content"> !<!-- THEME DEBUG --> <!-- THEME HOOK: 'form' --> <!-- BEGIN OUTPUT from 'core/themes/classy/templates/form/form.html.twig' --> <form class="user-login-form" data-drupal-selector="user-login-form" action="/node?destination=/node" method="post" id="user-login-form" accept-charset="UTF-8">
![Page 79: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/79.jpg)
How to override the current template<!-- THEME DEBUG -->
<!-- THEME HOOK: 'block' -->
<!-- FILE NAME SUGGESTIONS:
* block--bartik-login.html.twig
* block--user-login-block.html.twig
* block--user.html.twig
x block.html.twig
-->
<!-- BEGIN OUTPUT from 'core/themes/bartik/templates/block.html.twig' -->
![Page 80: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/80.jpg)
How to override the current template<!-- THEME DEBUG -->
<!-- THEME HOOK: 'block' -->
<!-- FILE NAME SUGGESTIONS:
* block--bartik-login.html.twig
* block--user-login-block.html.twig
* block--user.html.twig
x block.html.twig
-->
<!-- BEGIN OUTPUT from 'core/themes/bartik/templates/block.html.twig' -->
Drupal tried to use all these templates…
![Page 81: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/81.jpg)
How to override the current template<!-- THEME DEBUG -->
<!-- THEME HOOK: 'block' -->
<!-- FILE NAME SUGGESTIONS:
* block--bartik-login.html.twig
* block--user-login-block.html.twig
* block--user.html.twig
x block.html.twig
-->
<!-- BEGIN OUTPUT from 'core/themes/bartik/templates/block.html.twig' -->
…before deciding to use this template.
Drupal tried to use all these templates…
![Page 82: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/82.jpg)
Which variables are passed to the template?
Built-in templates include comments with the full list of variables passed to the Twig template.
![Page 83: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/83.jpg)
Easier way to introspect all variables
<pre>
{{ dump() }}
</pre>
![Page 84: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/84.jpg)
Easier way to introspect all variables
<pre>
{{ dump() }}
</pre>
It dumps the contents of all the variables
defined in the template.
![Page 85: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/85.jpg)
It's better to dump just the variables you need
<pre> {{ dump(label, title_attributes) }}
</pre>
![Page 86: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/86.jpg)
It's better to dump just the variables you need
<pre> {{ dump(label, title_attributes) }}
</pre>
It dumps only the given variables
![Page 87: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/87.jpg)
CAUTION!
Don't forget to rebuild your cache after changing the config files and templates.
![Page 88: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/88.jpg)
drupalconsole.com
![Page 89: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/89.jpg)
drupalconsole.com
$ drupal cache:rebuild $ drupal c:r
![Page 90: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/90.jpg)
ESCAPING
![Page 91: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/91.jpg)
WHY IS THIS IMPORTANT??
Because it can prevent you a lot of security-related problems.
![Page 92: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/92.jpg)
CAUTION!
Drupal has replaced the default Twig escaping filter by their own.
![Page 93: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/93.jpg)
By default, contents are escaped for HTML
Hi {{ content }}!
$content = '<strong>John</strong>';
![Page 94: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/94.jpg)
By default, contents are escaped for HTML
Hi {{ content }}!
$content = '<strong>John</strong>';
What you expect…
Hi John!
What you get…
Hi <strong>John </strong>!
![Page 95: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/95.jpg)
The "raw" filter prevents the escaping
Hi {{ content|raw }}!
$content = '<strong>John</strong>';
![Page 96: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/96.jpg)
The "raw" filter prevents the escaping
Hi {{ content|raw }}!
$content = '<strong>John</strong>';
What you expect…
Hi John!
What you get…
Hi John!
![Page 97: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/97.jpg)
What if contents are used in URLs or JS?
<a href="...?param={{ value }}"></a> !
!
!
<script> var variable = "{{ content }}"; </script>
![Page 98: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/98.jpg)
What if contents are used in URLs or JS?
<a href="...?param={{ value }}"></a> !
!
!
<script> var variable = "{{ content }}"; </script>
WRONG HTML ESCAPING
![Page 99: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/99.jpg)
Applying different escaping strategies
<a href="...?param={{ value|e('url') }}"></a> !
!
!
<script> var variable = "{{ content|e('js') }}"; </script>
![Page 100: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/100.jpg)
Escaping strategies available in Twig
{{ content|e('html') }}
{{ content|e('js') }}
{{ content|e('css') }}
{{ content|e('url') }}
{{ content|e('html_attr') }}
![Page 101: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/101.jpg)
REUSING TEMPLATES
![Page 102: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/102.jpg)
WHY IS THIS IMPORTANT??
Because it allows you to avoid repeating code and it makes your themes easier to maintain.
![Page 103: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/103.jpg)
Lots of different ways to reuse templates
{% embed %} {% extends %}include()
{% set %} {% use %}macro()
![Page 104: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/104.jpg)
How often are these alternatives used
{% embed %}
{% extends %} include( )
{% set %} {% use %}
macro( )
Always
Sometimes
Rarely
![Page 105: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/105.jpg)
Lots of different ways to reuse templates
{% embed %} {% extends %}include()
{% set %} {% use %}macro()
![Page 106: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/106.jpg)
Use {% extends %} to share layouts
![Page 107: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/107.jpg)
Use {% extends %} to share layouts
1 layout with the common design elements
![Page 108: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/108.jpg)
Use {% extends %} to share layouts
1 layout with the common design elements
+
4 simple pages which only define their contents
![Page 109: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/109.jpg)
layout.twig<!DOCTYPE html> <html> <head> <title> {% block title %}ACME website{% endblock %} </title> </head> <body> <div class="container"> {% block content %}{% endblock %} </div> </body> </html>
![Page 110: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/110.jpg)
layout.twig<!DOCTYPE html> <html> <head> <title> {% block title %}ACME website{% endblock %} </title> </head> <body> <div class="container"> {% block content %}{% endblock %} </div> </body> </html>
![Page 111: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/111.jpg)
Other templates can reuse this layout{% extends 'layout.twig' %}
!
{% block title %}Community{% endblock %}
{% block content %}
<div> ... </div>
{% endblock %}
![Page 112: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/112.jpg)
When should you use {% extends %}• To create the layout of your theme. • If your site/app is very complex, create two
inheritance levels (base layout and section layouts).
layout.twig schedule.twig training.twigextends layout.twig extends schedule.twig
![Page 113: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/113.jpg)
Lots of different ways to reuse templates
{% embed %} {% extends %}include()
{% set %} {% use %}macro()
![Page 114: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/114.jpg)
Reusing templates with include( )!
{{ include('listing.twig') }} !
!
<div> {% for item in items %} <h2>{{ item.title }}</h2> <p>{{ item.content }}</p> {% endfor %} </div>
blog/index.twig
blog/listing.twig
![Page 115: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/115.jpg)
When should you use include( )• To reuse large fragments of code, such as sidebars,
navigation menus, etc.
![Page 116: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/116.jpg)
Lots of different ways to reuse templates
{% embed %} {% extends %}include()
{% set %} {% use %}macro()
![Page 117: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/117.jpg)
Repetitive HTML fragments
<div class="form-group">
<label for="{{ id }}">{{ label }}</label>
<input type="{{ type }}" class="form-control"
id="{{ id }}">
</div> Repeating the same HTML code for all the form fields
is cumbersome
![Page 118: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/118.jpg)
Reusing fragments with macro( )
{% macro form_field(id, label, type="text") %}
<div class="form-group">
<label for="{{ id }}">{{ label }}</label>
<input type="{{ type }}" class="form-control"
id="{{ id }}">
</div>
{% endmacro %}
![Page 119: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/119.jpg)
Using "macros" inside templates{% import _self as macro %}
!
<form>
{{ macro.form_field('first_name', 'First Name') }}
{{ macro.form_field('last_name', 'Last Name') }}
{{ macro.form_field('email', 'Email', 'email') }}
...
</form>
![Page 120: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/120.jpg)
Using "macros" inside templates{% import _self as macro %}
!
<form>
{{ macro.form_field('first_name', 'First Name') }}
{{ macro.form_field('last_name', 'Last Name') }}
{{ macro.form_field('email', 'Email', 'email') }}
...
</form>
Before using a macro, you must "import" them (they can be
defined in a different template)
![Page 121: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/121.jpg)
When should you use macro( )• To reuse short fragments of code, usually in the
same template (e.g. listings, grids, forms, etc.) • If your site/app is very complex, store all the macros
in a single file and reuse it from any other template.
![Page 122: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/122.jpg)
Lots of different ways to reuse templates
{% embed %} {% extends %}include()
{% set %} {% use %}macro()
![Page 123: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/123.jpg)
Grid-based design
embed allows to reuse inner page structures (e.g. the 3-column grid)
![Page 124: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/124.jpg)
Grid-based design
embed allows to reuse inner page structures (e.g. the 3-column grid)
![Page 125: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/125.jpg)
You can't use "include" to solve this problem
{{ include('common/grid_3.twig') }}
![Page 126: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/126.jpg)
You can't use "include" to solve this problem
{{ include('common/grid_3.twig') }}
you can't change the included contents (you include both the
structure and the content)
![Page 127: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/127.jpg)
You can't use "extends" to solve this problem
{% extends 'common/grid_3.twig' %}
!
{% block column1 %} ... {% endblock %}
{% block column2 %} ... {% endblock %}
{% block column3 %} ... {% endblock %}
![Page 128: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/128.jpg)
You can't use "extends" to solve this problem
{% extends 'common/grid_3.twig' %}
!
{% block column1 %} ... {% endblock %}
{% block column2 %} ... {% endblock %}
{% block column3 %} ... {% endblock %}you can't make the whole structure
of the page (grid 2, grid 3, etc.) because you can't extend from
multiple templates at the same time
![Page 129: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/129.jpg)
Define a three-column grid template<div class="row"> <div class="col-md-4"> {% block column1 %}{% endblock %} </div> !
<div class="col-md-4"> {% block column2 %}{% endblock %} </div> !
<div class="col-md-4"> {% block column3 %}{% endblock %} </div> </div>
![Page 130: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/130.jpg)
Reuse the three-column grid template{% embed 'common/grid_3.twig' %} {% block column1 %} ... contents ... {% endblock %} !
{% block column2 %} ... contents ... {% endblock %} !
{% block column3 %} ... contents ... {% endblock %} {% endembed %}
![Page 131: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/131.jpg)
When should you use {% embed %}• To reuse page structures across different templates
(e.g. grids)
![Page 132: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/132.jpg)
Lots of different ways to reuse templates
{% embed %} {% extends %}include()
{% set %} {% use %}macro()
![Page 133: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/133.jpg)
Reusing fragments with {% set %}
{% set navigation %} <a href="...">Previous</a> ... ... <a href="...">Next</a> {% endset %}
![Page 134: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/134.jpg)
Reusing fragments with {% set %}
{% set navigation %} <a href="...">Previous</a> ... ... <a href="...">Next</a> {% endset %} {{ navigation }}
{{ navigation }}
![Page 135: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/135.jpg)
When should you use {% set %}• To reuse short fragments of code inside a template
(if those fragments are configurable, use a macro). • It's like an internal include() made from inside the
template itself.
![Page 136: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/136.jpg)
Lots of different ways to reuse templates
{% embed %} {% extends %}include()
{% set %} {% use %}macro()
![Page 137: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/137.jpg)
When should you use {% use %}• This is too advanced and for very specific use
cases. • You should probably never use it when creating
themes.
![Page 138: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/138.jpg)
DYNAMIC TEMPLATES
![Page 139: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/139.jpg)
WHY IS THIS IMPORTANT??
Because Drupal allows to create sites with very advanced needs.
![Page 140: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/140.jpg)
Templates created on-the-fly
{% set code = 'Hi {{ name }}' %}
{% set template = template_from_string(code) %}
!
{{ include(template) }}
![Page 141: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/141.jpg)
Templates created on-the-fly
{% set code = 'Hi {{ name }}' %}
{% set template = template_from_string(code) %}
!
{{ include(template) }}
{% extends template %}
{% embed template %} It works here too
![Page 142: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/142.jpg)
Templates created on-the-fly
{{ include(template_from_string(
'Hi {{ name }}'
)) }}
![Page 143: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/143.jpg)
Templates created and modified on-the-fly
{% set code = 'Hi {{ name }}' %}
{% set code = code|replace({ 'Hi': 'Bye' }) %}
!
{% set template = template_from_string(code) %}
!
{{ include(template) }}
![Page 144: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/144.jpg)
Getting the source of any template
{{ source('core/modules/block/templates/block.html.twig') }}
It gets the source of the given template without actually rendering it.
![Page 145: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/145.jpg)
Imagine a site which allows this customization
Section 1
Section 2
Default design
![Page 146: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/146.jpg)
Customizable site• Users can provide their own Twig snippets to
customize the design and content of some sections. • Problem: even if customization is restricted to a
group of controlled users (e.g. "editors") you can't trust those templates.
![Page 147: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/147.jpg)
Twig Sandbox• It's used to render "untrusted templates". • It restricts the Twig features that can be used by the
template. • Useful for letting users create their own templates
and maintain the application safe.
![Page 148: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/148.jpg)
Twig Sandbox in practice{% sandbox %}
{{ include(section.name ~ '/sidebar.twig') }}
{% endsandbox %}
!
!
{{ include(section.name ~ '/sidebar.twig', sandboxed = true) }}
![Page 149: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/149.jpg)
Twig Sandbox in practice$policy = new Twig_Sandbox_SecurityPolicy( $tags, $filters, $methods, $properties, $functions ); !
$sandbox = new Twig_Extension_Sandbox($policy); $twig->addExtension($sandbox);
Policy is defined as a white-list of allowed tags, filters, etc.
![Page 150: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/150.jpg)
Twig Sandbox policy sample$properties = array( 'label', 'configuration' => array('label', 'module'), 'block' => array('module'), 'attributes', ); !
$policy = new Twig_Sandbox_SecurityPolicy( $tags, $filters, $methods, $properties, $functions );
![Page 151: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/151.jpg)
DATES
![Page 152: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/152.jpg)
WHY IS THIS IMPORTANT??
Because dealing with dates is not easy and Twig can perform a lot of operations on dates.
![Page 153: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/153.jpg)
Timezones support
{{ 'now'|date(timezone='Asia/Tokyo') }} !
{{ 'now'|date(timezone=user.timezone) }}
![Page 154: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/154.jpg)
Comparing dates
{% if event.startsAt > date('now') %}
Buy tickets
{% endif %}
![Page 155: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/155.jpg)
Comparing dates
{% if event.startsAt > date('now') %}
Buy tickets
{% endif %} NOTE This is the date( )
function, not the date filter
![Page 156: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/156.jpg)
Modifying dates semantically
Early Bird ends at {{ event.startsAt|date_modify('-15 days')|date }} !
Confirm your sign up before {{ user.createdAt|date_modify('+48 hours')|date }}
![Page 157: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/157.jpg)
COOL FEATURES
![Page 158: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/158.jpg)
These are some of the features that put Twig years ahead of PHP
![Page 159: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/159.jpg)
Useful filters for collections
{{ user.friends|first }}
{{ event.sessions|last }}
![Page 160: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/160.jpg)
Useful tests for strings
{% if url starts with 'https://' %}
{% endif %}
!
{% if file_path ends with '.pdf' %}
{% endif %}
!
{% if phone matches '/^[\\d\\.]+$/' %}
{% endif %}
![Page 161: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/161.jpg)
REJECTED BY
PHPUseful tests for strings
{% if url starts with 'https://' %}
{% endif %}
!
{% if file_path ends with '.pdf' %}
{% endif %}
!
{% if phone matches '/^[\\d\\.]+$/' %}
{% endif %}
![Page 162: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/162.jpg)
The "in" operator
{% if password in username %}
BAD PASSWORD
{% endif %}
!
{% if method in ['GET', 'POST'] %}
...
{% endif %}
![Page 163: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/163.jpg)
The "in" operator
{% if password in username %}
BAD PASSWORD
{% endif %}
!
{% if method in ['GET', 'POST'] %}
...
{% endif %}
REJECTED BY
PHP
![Page 164: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/164.jpg)
Named parameters{{ content|convert_encoding('UTF-8', 'iso-2022-jp') }}
![Page 165: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/165.jpg)
Named parameters{{ content|convert_encoding('UTF-8', 'iso-2022-jp') }}
which is the original charset and which one the target charset?
![Page 166: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/166.jpg)
Named parameters{{ content|convert_encoding('UTF-8', 'iso-2022-jp') }}
which is the original charset and which one the target charset?
{{ content|convert_encoding( from = 'UTF-8', to = 'iso-2022-jp' ) }}
![Page 167: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/167.jpg)
Named parameters{{ content|convert_encoding('UTF-8', 'iso-2022-jp') }}
which is the original charset and which one the target charset?
{{ content|convert_encoding( from = 'UTF-8', to = 'iso-2022-jp' ) }}
{{ content|convert_encoding( to = 'UTF-8', from = 'iso-2022-jp' ) }}
![Page 168: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/168.jpg)
Named parameters{{ content|convert_encoding('UTF-8', 'iso-2022-jp') }}
PROPOSED FOR
PHP
which is the original charset and which one the target charset?
{{ content|convert_encoding( from = 'UTF-8', to = 'iso-2022-jp' ) }}
{{ content|convert_encoding( to = 'UTF-8', from = 'iso-2022-jp' ) }}
![Page 169: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/169.jpg)
Named parameters{{ include('template.html', {}, true, true) }} !
!
!
{{ include('template.html', ignore_missing = true) }}
template variables
with_context
ignore_missing
![Page 170: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/170.jpg)
It's common to do things in batches
1
Image gallery
2 3
4 5 6
![Page 171: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/171.jpg)
The HTML of the image gallery<div class="row">
<div class="image"> ... </div>
<div class="image"> ... </div>
<div class="image"> ... </div>
</div>
!
<div class="row">
<div class="image"> ... </div>
<div class="image"> ... </div>
<div class="image"> ... </div>
</div>
![Page 172: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/172.jpg)
The template without the "batch" filter{% for i, image in images %}
{% if i is divisible by(3) %} <div class="row"> {% endif %}
!
<div class="image">
<img src="" alt="" >
<p>...</p>
</div>
!
{% if i is divisible by(3) %} </div> {% endif %}
{% endfor %}
![Page 173: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/173.jpg)
The template without the "batch" filter{% for i, image in images %}
{% if i is divisible by(3) %} <div class="row"> {% endif %}
!
<div class="image">
<img src="" alt="" >
<p>...</p>
</div>
!
{% if i is divisible by(3) %} </div> {% endif %}
{% endfor %}
UGLY CODE
![Page 174: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/174.jpg)
The template with the "batch" filter{% for row in images|batch(3) %} <div class="row"> !
{% for image in row %} <div class="image"> <img src="" alt="" > <p>...</p> </div> {% endfor %} !
</div> {% endfor %}
![Page 175: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/175.jpg)
The template with the "batch" filter{% for row in images|batch(3) %} <div class="row"> !
{% for image in row %} <div class="image"> <img src="" alt="" > <p>...</p> </div> {% endfor %} !
</div> {% endfor %}
![Page 176: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/176.jpg)
Short ternary operator
$result = $condition ? 'is true';
![Page 177: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/177.jpg)
Short ternary operator
$result = $condition ? 'is true';
ERROR Parse error: syntax error, unexpected ';' on line 1
![Page 178: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/178.jpg)
Short ternary operator
$result = $condition ? 'is true';
ERROR Parse error: syntax error, unexpected ';' on line 1
{{ condition ? 'is true' }}
![Page 179: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/179.jpg)
Short ternary operator
$result = $condition ? 'is true';
ERROR Parse error: syntax error, unexpected ';' on line 1
OK This works perfectly on Twig
{{ condition ? 'is true' }}
![Page 180: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/180.jpg)
Short ternary operator
<li class="{{ condition ? 'selected' }}">
...
</li>
!
<li class="{{ condition ? 'selected' : '' }}"> ...
</li>
![Page 181: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/181.jpg)
Short ternary operator
<li class="{{ condition ? 'selected' }}">
...
</li>
!
<li class="{{ condition ? 'selected' : '' }}"> ...
</li>
always use this
![Page 182: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/182.jpg)
Short slice syntax
!
!
!
{{ user.friends[0:3] }}
{{ user.friends[:-3] }}
It combines array_slice, mb_substr and substr PHP functions.
get first three friends
get last three friends
![Page 183: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/183.jpg)
Short slice syntax
{{ '0123456789'[0:] }} {# 0123456789 #}
{{ '0123456789'[1:] }} {# 123456789 #}
{{ '0123456789'[20:] }} {# (empty) #}
{{ '0123456789'[-5:] }} {# 56789 #}
{{ '0123456789'[-1:] }} {# 9 #}
{{ '0123456789'[1:5] }} {# 12345 #}
{{ '0123456789'[1:-5] }} {# 1234 #}
OUTPUT
![Page 184: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/184.jpg)
The "loop" magic variable
Everyone needs an $i variable inside the for loop. So Twig provides you this and other useful variables.
![Page 185: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/185.jpg)
The "loop" variable exists only inside the "for"
{% for ... in collection %}
{{ loop.index }}
{{ loop.index0 }}
{{ loop.first }}
{{ loop.last }}
{{ loop.length }}
{% endfor %}
![Page 186: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/186.jpg)
The "loop" variable exists only inside the "for"
{% for ... in collection %}
{{ loop.index }}
{{ loop.index0 }}
{{ loop.first }}
{{ loop.last }}
{{ loop.length }}
{% endfor %}
1, 2, 3, 4, 5, ...
0, 1, 2, 3, 4, ...
true, false, false, ...
..., false, false, true
5
![Page 187: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/187.jpg)
{{ product.photo|image(400, 150, 0.9) }}
The problem with filter arguments
![Page 188: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/188.jpg)
{{ product.photo|image(400, 150, 0.9) }}
The problem with filter arguments
What if I need to define more arguments?
![Page 189: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/189.jpg)
{{ product.photo|image(400, 150, 0.9) }}
{{ product.photo|image( width = 400, height = 150, opacity = 0.9 ) }}
The problem with filter arguments
What if I need to define more arguments?
![Page 190: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/190.jpg)
{{ product.photo|image(400, 150, 0.9) }}
{{ product.photo|image( width = 400, height = 150, opacity = 0.9 ) }}
The problem with filter arguments
What if I need to define more arguments?
this is a valid solution for Twig, but the underlying PHP code is still very complex
![Page 191: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/191.jpg)
Defining a filter with lots or arguments$filter = new Twig_SimpleFilter('image', function (
$path, $width, $height, $opacity
) {
$path = ...
$width = ...
$height = ...
$opacity = ...
});
![Page 192: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/192.jpg)
$filter = new Twig_SimpleFilter('image', function (
$path, $options = array()
) {
$path = ...
$width = $options['width'];
$height = $options['height'];
$opacity = $options['opacity'];
}, array('is_variadic' => true));
Defining a variadic filter
![Page 193: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/193.jpg)
$filter = new Twig_SimpleFilter('image', function (
$path, $options = array()
) {
$path = ...
$width = $options['width'];
$height = $options['height'];
$opacity = $options['opacity'];
}, array('is_variadic' => true));
Defining a variadic filter
a single variadic parameter holds any number of passed parameters (unlimited)
![Page 194: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/194.jpg)
$filter = new Twig_SimpleFilter('image', function (
$path, $options = array()
) {
$path = ...
$width = $options['width'];
$height = $options['height'];
$opacity = $options['opacity'];
}, array('is_variadic' => true));
ACCEPTED BY
PHP
Defining a variadic filter
a single variadic parameter holds any number of passed parameters (unlimited)
![Page 195: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/195.jpg)
TO SUM UP
![Page 196: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/196.jpg)
«Using Twig templates is the best decision Drupal ever made»
![Page 197: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/197.jpg)
Drupal 8 templates are safe, concise, modern
and consistent.
Twig
![Page 198: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/198.jpg)
Drupal 8 templates are safe, concise, modern
and consistent.
![Page 199: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/199.jpg)
Drupal 8 themes
![Page 200: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/200.jpg)
REFERENCES
![Page 201: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/201.jpg)
References• Official Twig documentation
twig.sensiolabs.org/documentation
• Twig in Drupal 8drupal.org/theme-guide/8/twig
![Page 202: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/202.jpg)
CONTACT
![Page 204: Mastering Twig (DrupalCon Barcelona 2015)](https://reader034.fdocuments.net/reader034/viewer/2022052116/587ca5231a28ab356c8b57cf/html5/thumbnails/204.jpg)