{# 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 barfoo['bar']
foo is object with property barfoo is object with method barfoo is object with method getBarfoo 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'
}
iffor
{% if someValue %}
...
{% elseif someOtherValue %}
...
{% else %}
...
{% endif %}
The elseif and else parts are optional.
{% if someValue %} ... {% endif %}
false0''[] 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.index0loop.revindex and loop.revindex0loop.first and loop.lastloop.lengthloop.parent loop.parent.loop.index)macroincludeextendsembed
{% 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.twigextends, the contents of the b block in mini.twig will be replaced by block content given here.embedwith and only)