{# comments #}
{{ output }}
{% tags %}
'single quotes'
"double quotes"~ is the string concatination operator: 'foo'~'bar' => 'foobar'
1, 2.5, -7
true and false
['foo', 23, []]
{key: 'value', anotherKey: [1, 2, 'frogs']}
+, -, and, or, not, ==, <, >, etc.) plus filters and functions.['a', 'b']|join(', ') 'a, b'
['a', 'b']|join(', ')|upper 'A, B'
max(foo, bar, 0)
Filters: currency, datetime, filesize, filter, group, indexOf, intersect, lcfirst, markdown (md), number, parseRefs, percentage, replace, translate (t), ucfirst, ucwords, without
Functions: ceil, floor, getCsrfInput, getFootHtml, getHeadHtml, shuffle, url
Tags: cache, exit, header, includeCss, includeCssFile, includeHiResCss, includeJs, includeJsFile, nav, paginate, redirect, requireLogin, requirePermission, switch
{{ value }}
Convert value to a string
Print that string out inline
{{ 'hello, world'|upper }}
HELLO, WORLD
{{ dump(foo) }}
All the details (var_dump) about foo, printed out.
Need to have devMode enabled for this to work.
{{dump([1, 2, 'fish'])}}
array(3) {
[0]=> int(1)
[1]=> int(2)
[2]=> string(4) "fish"
}
{% set foo = bar %}
foo will have whatever type bar has
{% set foo %}
...bunch of template code...
{% endset %}
foo will be a string
{% if someValue %}
...
{% elseif someOtherValue %}
...
{% else %}
...
{% endif %}
Things that are false: false, 0, '', []
Things that are true: everything else
{% switch matrixBlock.type %}
{% case 'text' %}
... matrixBlock.type is text ...
{% case 'image' %}
... matrixBlock.type is image ...
{% default %}
... all other cases ...
{% endswitch %}
At most one case block is evaluated.
no fall-through, no break
{% for foo in arrayLikeThing %}
... do something with {{foo}} ...
{% endfor %}
foo is only defined inside the for loop.
Traversable interface.
(e.g. ElementCriteriaModel)
['thingOne', 'thingTwo', 3.14159]'a'..'z'{ key: value, key2: value2 }
{% 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 key, value in pets %}
{{key}}: {{value}}
{% endfor %}
cat: Puff
dog: Spot
loop.index and loop.index0loop.first and loop.lastloop.revindex and loop.revindex0loop.lengthloop.parent loop.parent.loop.index)
{% 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 richText(t) %}
{# typogrify filter for smart quotes #}
{{t|smartypants}}
{% endmacro %}
{{ m_utils.richText(entry.body) }}
{{ m_utils.richText() }} {# oops! #}
{% macro richText(t) %}
{% if t|default('') %}
{{t|smartypants}}
{% endif %}
{% endmacro %}
What if we want more classes on that div?
{{ m_utils.richText(entry.body,
['this-class', 'that-class']) }}
{% macro richText(t, classes=[]) %}
{% if t|default('') %}
{{t|smartypants}}
{% endif %}
{% endmacro %}
Moral: deal with possibly missing parameters.
{% macro rNav(pages, depth=0) %}
{% import _self as self %}
<ul>
{% for page in pages|default([]) %}
<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)) }}
In twig, the context is all the values that are currently defined.
{% set foo = 'bar' %}
— adds foo to the context.
_context is a global variable which represents the current context.
{{ dump(_context|keys) }}
array(9) { [0]=> string(5) "craft"
[1]=> string(3) "blx" [2]=> string(3) "now"
[3]=> string(8) "loginUrl"
[4]=> string(9) "logoutUrl"
[5]=> string(8) "siteName" [6]=> string(7) "siteUrl"
[7]=> string(11) "currentUser" [8]=> string(4) "user"
}
_context is not available in macros, but you can pass it in:
{% set meta = {title: 'myTitle',
description: 'some description'} %}
{{ m_meta.output(_context) }}
{% macro output(c) %}
{% import _self as self %}
{% if c.meta is defined %} {# in context? #}
{% set metaData = c.meta %}
{% elseif c.entry is defined %} {# have entry? #}
{% set metaData = {
title: c.entry.mTitle|default(c.entry.title),
description: c.entry.mDescription
} %}
{% else %} {# we got nothing #}
{% set metaData = {title: '', description: ''} %}
{% endif %}
{{self._output(metaData)}}
{% endmacro %}
{% macro _output(m) %}
{{m.title ? m.title~' | '}}{{siteName}}
{% if m.description %}
<meta name="description"
content="{{m.description}}"/>
{% endif %}
{% endmacro %}
{% for matrixBlock in entry.matrixField %}
{% include '_blocks/text' %}
{% endfor %}
The included template has access to the current context. matrixBlock is defined.
We can be more explicit about this:
{% include '_blocks/text'
with {currentBlock: matrixBlock} only %}
currentBlock will be defined... and nothing else
{% for matrixBlock in entry.matrixField %}
{% include '_blocks/'~matrixBlock.type %}
{% endfor %}
Will include the appropriate template for the block type (assuming you have defined it)
{% for matrixBlock in entry.matrixField %}
{% include ['_blocks/'~matrixBlock.type,
'_blocks/_default'] %}
{% endfor %}
Will include the template for the block type if it exists, otherwise _blocks/_default.html
{# this is 'child.html' #}
{% extends '_layouts/base.html' %}
{% set title = entry.title %}
{% block body %}
{{entry.body}}
{% endblock body %}
Since it extends another template, child.html is not allowed to produce any output. It can add things to the context (e.g. title), and define block contents.
{# this is '_layouts/base.html' #}
{{title}}
<body>
{% block body %}hello, world{% endblock body %}
{% block foot %}Copyright 2015{% endblock foot %}
</body>
title will be defined here since it was set in child.html
The body block will be replaced by the body block from child.html
The foot block will be left untouched.
Another layout template
{% include '_macros/_meta' as m_meta %}
<html>
<head>
{{ m_meta.output(_context) }}
</head>
<body>
{% block body %}{% endblock body %}
</body>
</html>
We have abstracted all of the output of the meta data into m_meta.output, which since it has the context, is omniscient.
...
{% embed '_layouts/left_right.html' %}
{% block left %}...left content...{% endblock %}
{% block right %}...right content...{% endblock %}
{% endembed %}
...
embedinclude, the contents of the embed will be replaced by _layouts/left_right.htmlembed, the contents of blocks in left_right.html will be replaced by block content given here.embed provides the same control of the context that include does.
{% embed '_layouts/left_right.html'
with {foo: 'bar'} %}
...
{% endembed %}
{% embed '_layouts/left_right.html'
with {foo: 'bar'} only %}
...
{% endembed %}
with and only)
foo['bar']
foo is an associative array with key barfoo.bar or attribute(foo, 'bar')
foo is an associative array with key barfoo is object with property barfoo is object with method barfoo is object with method getBarfoo is object with method isBar
foo|default('defaultValue')
These are all legal (and will return the default value):
neverHeardOfIt|default('')neverHeardOfIt.someField|default('')someArray[invalidIndex]|default('')null|default('')''|default('')[]|default('')false|default('')0|default('') will not return ''
merge filter merges two arrays (regular or associative)
Use it to add something to an existing array
{% set a = ['this', 'that'] %}
{% set a = a|merge(['theOther']) %}
['this', 'that', 'theOther']
group: Groups the items of an array together based on common properties.
{% set books = [
{ author: 'Brown', t: 'Goodnight Moon' },
{ author: 'Burnett', t: 'The Secret Garden' },
{ author: 'Sendak', t: 'The Nutshell Library' },
{ author: 'Seuss', t: 'The Cat in the Hat' }
] %}
{% set alphaBooks = books|group('author|first') %}
{ B:[{ author: 'Brown', t: 'Goodnight Moon' },
{ author: 'Burnett', t: 'The Secret Garden' } ],
S:[{ author: 'Sendak', t: 'The Nutshell Library' },
{ author: 'Seuss', t: 'The Cat in the Hat' } ]
}
find me at: