{# comments #}
{{ output }}
{% tags %}
{% extends '_layouts/standard' %}
{% import '_macros/product' as m_product %}
{% block content %}
<section id="portfolio-items">
{# loop over the featured products #}
{% for product in g_specials.featuredProducts %}
<div class="eight columns">
{{ m_product.thumb(product,
{style: 'specials'}) }}
</div>
{% endfor %}
</section>
{% endblock content %}
'single quotes'
"double quotes"
1, 2.5, -7
true
and false
[1, 2, 3]
['foo', 0.5]
[]
['foo', 'bar', 0, []]
{ key: value, key2: value2 }
{
cat: 'Puff',
dogs: ['Fido', 'Rover']
}
Twig can't create complex php objects, but it can manipulate them.
Common examples: EntryModel
ElementCriteriaModel
foo[0]
— the first element in foo
foo[1]
— the second element in foo
foo['bar']
— the value associated with the key bar
foo.bar
foo
is an associative array with key bar
foo['bar']
foo
is object with property bar
foo
is object with method bar
foo
is object with method getBar
foo
is object with method isBar
{% set foo = ['Fido', 'Rover'] %}
{% set foo %}
...bunch of template code...
{% endset %}
{{ value }}
Convert value
to a string
Print that string out inline
{% set greeting = 'hello, world' %}
{{ greeting }}
hello, world
+, -, *, /, %,
etc.)and, or, not
)==, !=, <, >, <=, >=
)(~)
'foo'~'bar'
is 'foobar'
starts with, ends with, matches
) 'foobar' starts with 'foo'
'foobar' matches '/^f.*r$/'
in
)1 in [1, 2, 3]
'foo' in 'foobar'
?:
)
(foo ? 'yes' : 'no')
(foo ?: 'no')
(foo ? foo : 'no')
(foo ? 'yes')
(foo ? 'yes' : '')
??
)
this ?? that.thing ?? theOther ?? 23
The usual syntax: functionName(param, param)
{{ dump(thing) }}
displays all the gory details of thing
(assuming you have Craft's devMode
turned on.)
value | filterName
value | filterName(param)
{{ 'hello, world' | upper }}
HELLO, WORLD
length
is a filter which returns the number of items in an array, or the length of a string:
{{ [1, 2, 3] | length }}
3
{{ 'foobar' | length }}
6
keys
is a filter which returns the keys of an associative array:
{% set pets = {
cat: 'Puff',
dog: 'Spot'
} %}
{{ dump(pets | keys) }}
array (size=2)
0 => string 'cat' (length=3)
1 => string 'dog' (length=3)
join
is a filter which concatinates the elements of an array and returns a string:
{{ pets | keys | join(', ') }}
cat, dog
{{ pets | join(', ') }}
Puff, Spot
merge
filter merges two arrays (regular or associative)
{% set a = ['Fido', 'Rover'] | merge(['Spot']) %}
['Fido', 'Rover', 'Spot']
Use it to add something to an existing array
{% set a = a | merge(['Rex']) %}
['Fido', 'Rover', 'Spot', 'Rex']
merge
operates on keys. If the key doesn't exist, it is added. If it does exist, its value is overridden:
{% set defaultPets = {cat: 'Puff', dog: 'Spot'} %}
{% set myPets = {fish: 'Wanda', cat: 'Fang'} %}
{% set pets = defaultPets | merge(myPets) %}
{
cat: 'Fang',
dog: 'Spot',
fish: 'Wanda'
}
if
for
{% if someValue %}
...
{% elseif someOtherValue %}
...
{% else %}
...
{% endif %}
The elseif
and else
parts are optional.
{% if someValue %} ... {% endif %}
false
0
''
[]
or {}
null
{% for foo in arrayLikeThing %}
... do something with {{foo}} ...
{% endfor %}
foo
is only defined inside the for
loop.
['thingOne', 'thingTwo', 3.14159]
'a'..'z'
{ key: value, key2: value2 }
Traversable
interface.
(e.g. ElementCriteriaModel
)
{% for animal in ['cat', 'dog', 'fish'] %}
all about the {{animal}}
{% endfor %}
all about the cat
all about the dog
all about the fish
{% set pets = {
cat: 'Puff',
dog: 'Spot'
} %}
{% for animal in pets %}
{{loop.index}}: {{animal}}
{% endfor %}
1: Puff
2: Spot
{% for animal in pets|keys %}
{{loop.index0}}: {{animal}}
{% endfor %}
0: cat
1: dog
{% for species, name in pets %}
{{species}}: {{name}}
{% endfor %}
cat: Puff
dog: Spot
loop.index
and loop.index0
loop.revindex
and loop.revindex0
loop.first
and loop.last
loop.length
loop.parent
loop.parent.loop.index
)macro
include
extends
embed
{% macro foo() %}
...
{% endmacro %}
defined in the same file
{% import _self as self %}
defined in a different file
{% import '_macros/utils' as m_utils %}
{{ m_utils.foo() }}
{% set ourFoo = m_utils.foo() %}
{% macro img(asset) %}
<img src="{{asset.url}}"/>
{% endmacro %}
{{ m_utils.img(entry.thumbnail.first) }}
{{ m_utils.img(null) }} {# oops! #}
{{ m_utils.img() }} {# oops! #}
{% macro img(asset=null) %}
{% if asset %}
<img src="{{asset.url}}"/>
{% endif %}
{% endmacro %}
What if we have more information about that asset?
{{ m_utils.img(entry.thumbnail.first,
{class: 'thumb'}) }}
{% macro img(asset=null, options={}) %}
{% set options = {
class: 'default'
} | merge(options)
%}
{% if asset %}
<img class="{{options.class}}"
src="{{asset.url}}"/>
{% endif %}
{% endmacro %}
{% macro rNav(pages=[], depth=0) %}
{% import _self as self %}
<ul data-depth="{{ depth }}">
{% for page in pages %}
<li>
{{ page.link }}
{% if page.hasDescendents() %}
{{ self.rNav(page.children, depth+1) }}
{% endif %}
</li>
{% endfor %}
</ul>
{% endmacro %}
{{ m_utils.rNav(craft.entries
.section('sitePages').level(1)) }}
{% for b in entry.matrixField %}
{% include '_blocks/text' %}
{% endfor %}
Everything that is available in the including template is also available in the included template. b
is available.
We can tighten this up:
{% include '_blocks/text'
with {currentBlock: b} only %}
currentBlock
will be available... and nothing else
{% for b in entry.matrixField %}
{% include '_blocks/'~b.type
with {currentBlock: b} only %}
{% endfor %}
Will include the appropriate template for the block type (assuming you have defined it)
{% include ['_blocks/'~b.type, '_blocks/_default']
with {currentBlock: b} only %}
Will include the template for the block type if it exists, otherwise _blocks/_default.twig
{% extends '_layouts/standard' %}
{% set title = entry.title %}
{% block body %}
{{entry.body}}
{% endblock body %}
Since it extends another template, child.twig
is not allowed to produce any output. It can assign values to variables (e.g. title
), and define block contents.
<title>{{title}}</title>
<body>
{% block body %}hello, world{% endblock body %}
{% block foot %}Peers - © 2016{% endblock foot %}
</body>
title
will be defined here since it was set in child.twig
The body
block will be replaced by the body
block from child.twig
The foot
block will be left untouched.
...
{% embed '_layouts/mini' with {foo: bar} only %}
{% block b %}... content...{% endblock b %}
{% endembed %}
...
include
, the contents of the embed
will be replaced by _layouts/mini.twig
extends
, the contents of the b
block in mini.twig
will be replaced by block content given here.embed
with
and only
)