Latte Tags
An overview and description of all the tags available by default in the Latte templating system.
{$var} , {...} or {=...} |
prints an escaped variable or expression |
{$var|filter} |
prints with filters applied |
{l} or {r} |
prints the { or } character |
{if} … {elseif} … {else} … {/if} |
if condition |
{ifset} … {elseifset} … {/ifset} |
ifset condition |
{ifchanged} … {/ifchanged} |
tests if a value has changed |
{switch} {case} {default} {/switch} |
switch condition |
n:else |
alternative content for conditions |
{foreach} … {/foreach} |
foreach |
{for} … {/for} |
for |
{while} … {/while} |
while |
{continueIf $cond} |
continue to the next iteration |
{skipIf $cond} |
skip the current loop iteration |
{breakIf $cond} |
break the loop |
{exitIf $cond} |
early exit |
{first} … {/first} |
is it the first iteration? |
{last} … {/last} |
is it the last iteration? |
{sep} … {/sep} |
will the next iteration follow? |
{iterateWhile} … {/iterateWhile} |
structured foreach |
$iterator |
special variable inside the foreach loop |
{include 'file.latte'} |
includes a template from another file |
{sandbox 'file.latte'} |
includes a template in sandbox mode |
{block} |
anonymous block |
{block blockname} |
defines a block |
{define blockname} |
defines a block for later use |
{include blockname} |
renders a block |
{include blockname from 'file.latte'} |
renders a block from a file |
{import 'file.latte'} |
imports blocks from a template |
{layout 'file.latte'} / {extends} |
specifies a layout file |
{embed} … {/embed} |
embeds a template or block and allows overriding blocks |
{ifset blockname} … {/ifset} |
condition checking if a block exists |
{try} … {else} … {/try} |
catching exceptions |
{rollback} |
discards the try block |
{var $foo = value} |
variable creation |
{default $foo = value} |
creates a variable if it doesn't exist |
{parameters} |
declares variables, types, and default values |
{capture} … {/capture} |
captures output into a variable |
{varType} |
declares the type of a variable |
{varPrint} |
suggests variable types |
{templateType} |
declares variable types based on a class |
{templatePrint} |
suggests a class with variable types |
{_...} |
prints translation |
{translate} … {/translate} |
translates the content |
{contentType} |
switches escaping and sends HTTP header |
{debugbreak} |
places a breakpoint in the code |
{do} |
executes code without printing anything |
{dump} |
dumps variables to the Tracy Bar |
{php} |
executes any PHP code |
{spaceless} … {/spaceless} |
removes unnecessary whitespace |
{syntax} |
changes syntax at runtime |
{trace} |
displays stack trace |
n:class |
dynamic HTML class attribute |
n:attr |
dynamic HTML attributes |
n:tag |
dynamic HTML element name |
n:ifcontent |
omits empty HTML tag |
n:href |
link used in
<a> HTML elements |
{link} |
prints a link |
{plink} |
prints a link to a presenter |
{control} |
renders a component |
{snippet} … {/snippet} |
a template snippet that can be sent via AJAX |
{snippetArea} |
snippet wrapper |
{cache} … {/cache} |
caches a part of the template |
{form} … {/form} |
renders form tags |
{label} … {/label} |
renders a form control label |
{input} |
renders a form control |
{inputError} |
prints the error message of a form control |
n:name |
activates a form control |
{formContainer} … {/formContainer} |
renders a form container |
Printing
{$var}
{...}
{=...}
In Latte, the {=...}
tag is used to print any expression to the output. Latte cares about your comfort, so if the
expression starts with a variable or a function call, there's no need to write the equals sign. Which in practice means it almost
never needs to be written:
Name: {$name} {$surname}<br>
Age: {date('Y') - $birth}<br>
You can write anything you know from PHP as an expression. You simply don't have to learn a new language. For example:
{='0' . ($num ?? $num * 3) . ', ' . PHP_VERSION}
Please don't look for any meaning in the previous example, but if you find one, let us know :-)
Output Escaping
What is the most important task of a templating system? To prevent security vulnerabilities. And that's exactly what Latte does whenever you print something. It automatically escapes it:
<p>{='one < two'}</p> {* prints: '<p>one < two</p>' *}
To be precise, Latte uses context-aware escaping, which is such an important and unique feature that we've dedicated a separate chapter to it.
And what if you're printing HTML-encoded content from a trusted source? Then you can easily disable escaping:
{$trustedHtmlString|noescape}
Misuse of the noescape
filter can lead to an XSS vulnerability! Never use it unless you are
absolutely sure what you are doing and that the string you are printing comes from a trusted source.
Printing in JavaScript
Thanks to context-aware escaping, it's wonderfully easy to print variables inside JavaScript, and Latte will handle the proper escaping.
The variable doesn't have to be a string; any data type is supported, which is then encoded as JSON:
{var $foo = ['hello', true, 1]}
<script>
alert({$foo});
</script>
Generates:
<script>
alert(["hello", true, 1]);
</script>
This is also why you should not write quotes around the variable: Latte adds them for strings automatically. And if you want to insert a string variable into another string, simply concatenate them:
<script>
alert('Hello ' + {$name} + '!'); // OK
alert({="Hello $name!"}); // OK
alert('Hello {$name} !'); // ERROR!
</script>
Filters
The printed expression can be modified by filters. For example, this converts the string to uppercase and shortens it to a maximum of 30 characters:
{$string|upper|truncate:30}
You can also apply filters to parts of an expression like this:
{$left . ($middle|upper) . $right}
Conditions
{if}
{elseif}
{else}
Conditions behave the same way as their PHP counterparts. You can use the same expressions you know from PHP; you don't have to learn a new language.
{if $product->inStock > Stock::Minimum}
In stock
{elseif $product->isOnWay()}
On the way
{else}
Not available
{/if}
Like any pair tag, the {if} ... {/if}
pair can also be written using an n:attribute, for example:
<p n:if="$count > 0">In stock {$count} items</p>
Did you know you can add the tag-
prefix to n:attributes? Then the condition will only affect the printing of HTML
tags, and the content between them will always be printed:
<a href="..." n:tag-if="$clickable">Hello</a>
{* prints 'Hello' when $clickable is falsey *}
{* prints '<a href="...">Hello</a>' when $clickable is truthy *}
Awesome.
n:else
If you write the {if} ... {/if}
condition in the form of an n:attribute, you have the option to specify an alternative branch
using n:else
:
<strong n:if="$count > 0">In stock {$count} items</strong>
<em n:else>not available</em>
The n:else
attribute can also be used in conjunction with n:ifset
,
n:foreach
, n:try
, n:ifcontent
, and n:ifchanged
.
{/if $cond}
You might be surprised that the expression in the {if}
condition can also be specified in the closing tag. This is
useful in situations where we don't yet know its value when opening the condition. Let's call it a deferred decision.
For example, we start listing a table with records from the database, and only after completing the output do we realize that
there were no records in the database. So, we put the condition in the closing tag {/if}
, and if there are no
records, none of it will be printed:
{if}
<h1>List of rows from the database</h1>
<table>
{foreach $resultSet as $row}
...
{/foreach}
</table>
{/if isset($row)}
Handy, isn't it?
You can also use {else}
in the deferred condition, but not {elseif}
.
{ifset}
{elseifset}
See also {ifset block}
Use the {ifset $var}
condition to determine if a variable (or multiple variables) exists and has a non-null value.
It's actually the same as if (isset($var))
in PHP. Like any pair tag, it can also be written using an n:attribute, so let's show an example:
<meta name="robots" content={$robots} n:ifset="$robots">
{ifchanged}
{ifchanged}
checks if the value of a variable has changed since the last iteration in a loop (foreach, for, or
while).
If we provide one or more variables in the tag, it checks if any of them have changed and prints the content accordingly. For example, the following example prints the first letter of a name as a heading each time it changes during the listing of names:
{foreach ($names|sort) as $name}
{ifchanged $name[0]} <h2>{$name[0]}</h2> {/ifchanged}
<p>{$name}</p>
{/foreach}
However, if no argument is given, the rendered content itself will be checked against its previous state. This means that in the previous example, we can safely omit the argument in the tag. And of course, we can also use an n:attribute:
{foreach ($names|sort) as $name}
<h2 n:ifchanged>{$name[0]}</h2>
<p>{$name}</p>
{/foreach}
An {else}
clause can also be used inside {ifchanged}
.
{switch}
{case}
{default}
Compares a value with multiple options. This is similar to the switch
statement known from PHP. However, Latte
improves it:
- uses strict comparison (
===
) - does not require
break
It is thus the exact equivalent of the match
structure introduced in PHP 8.0.
{switch $transport}
{case train}
By train
{case plane}
By plane
{default}
Otherwise
{/switch}
The {case}
clause can contain multiple values separated by commas:
{switch $status}
{case $status::New}<b>new item</b>
{case $status::Sold, $status::Unknown}<i>not available</i>
{/switch}
Loops
In Latte, you'll find all the loops you know from PHP: foreach, for, and while.
{foreach}
You write the loop exactly the same way as in PHP:
{foreach $langs as $code => $lang}
<span>{$lang}</span>
{/foreach}
Additionally, it has a few handy features we'll discuss now.
For example, Latte checks that created variables do not accidentally overwrite global variables of the same name. This saves
you from situations where you expect $lang
to contain the current language of the page, and you don't realize that
foreach $langs as $lang
has overwritten that variable.
The foreach loop can also be written very elegantly and economically using an n:attribute:
<ul>
<li n:foreach="$items as $item">{$item->name}</li>
</ul>
Did you know you can add the inner-
prefix to n:attributes? Then only the inner part of the element will be
repeated in the loop:
<div n:inner-foreach="$items as $item">
<h4>{$item->title}</h4>
<p>{$item->description}</p>
</div>
So it prints something like:
<div>
<h4>Foo</h4>
<p>Lorem ipsum.</p>
<h4>Bar</h4>
<p>Sit dolor.</p>
</div>
{else}
Inside the foreach
loop, you can specify an {else}
clause, whose content is displayed if the loop
is empty:
<ul>
{foreach $people as $person}
<li>{$person->name}</li>
{else}
<li><em>Sorry, there are no users in this list</em></li>
{/foreach}
</ul>
$iterator
Inside the foreach
loop, Latte creates the $iterator
variable, which allows us to find useful
information about the ongoing loop:
$iterator->first
– is this the first iteration?$iterator->last
– is this the last iteration?$iterator->counter
– iteration counter, starting from one$iterator->counter0
– iteration counter, starting from zero$iterator->odd
– is this an odd iteration?$iterator->even
– is this an even iteration?$iterator->parent
– the iterator surrounding the current one$iterator->nextValue
– the next item in the loop$iterator->nextKey
– the key of the next item in the loop
{foreach $rows as $row}
{if $iterator->first}<table>{/if}
<tr id="row-{$iterator->counter}">
<td>{$row->name}</td>
<td>{$row->email}</td>
</tr>
{if $iterator->last}</table>{/if}
{/foreach}
Latte is smart, and $iterator->last
works not only for arrays but also when the loop runs over a general
iterator where the number of items is not known in advance.
{first}
{last}
{sep}
These tags can be used inside the {foreach}
loop. The content of {first}
is rendered if it's the
first iteration. The content of {last}
is rendered… can you guess? Yes, if it's the last iteration. These are
actually shortcuts for {if $iterator->first}
and {if $iterator->last}
.
The tags can also be elegantly used as n:attributes:
{foreach $rows as $row}
{first}<h1>List of names</h1>{/first}
<p>{$row->name}</p>
<hr n:last>
{/foreach}
The content of the {sep}
tag is rendered if the iteration is not the last, making it suitable for rendering
delimiters, such as commas between listed items:
{foreach $items as $item} {$item} {sep}, {/sep} {/foreach}
That's quite practical, isn't it?
{iterateWhile}
Simplifies the grouping of linear data during iteration in a foreach loop by performing the iteration in a nested loop as long as the condition is met. Read the detailed instructions.
It can also elegantly replace {first}
and {last}
in the example above:
{foreach $rows as $row}
<table>
{iterateWhile}
<tr id="row-{$iterator->counter}">
<td>{$row->name}</td>
<td>{$row->email}</td>
</tr>
{/iterateWhile true}
</table>
{/foreach}
See also the batch and group filters.
{for}
We write the loop exactly the same way as in PHP:
{for $i = 0; $i < 10; $i++}
<span>Item #{$i}</span>
{/for}
The tag can also be written as an n:attribute:
<h1 n:for="$i = 0; $i < 10; $i++">{$i}</h1>
{while}
Again, we write the loop exactly the same way as in PHP:
{while $row = $result->fetch()}
<span>{$row->title}</span>
{/while}
Or as an n:attribute:
<span n:while="$row = $result->fetch()">
{$row->title}
</span>
A variant with a condition in the closing tag is also possible, corresponding to the do-while loop in PHP:
{while}
<span>{$item->title}</span>
{/while $item = $item->getNext()}
{continueIf}
{skipIf}
{breakIf}
Special tags {continueIf ?}
and {breakIf ?}
can be used to control any loop. They jump to the next
iteration or end the loop, respectively, if the condition is met:
{foreach $rows as $row}
{continueIf $row->date < $now}
{breakIf $row->parent === null}
...
{/foreach}
The {skipIf}
tag is very similar to {continueIf}
, but it does not increment the
$iterator->counter
. This prevents gaps in numbering when printing the counter and skipping some items. Also, the
{else}
clause will be rendered if all items are skipped.
<ul>
{foreach $people as $person}
{skipIf $person->age < 18}
<li>{$iterator->counter}. {$person->name}</li>
{else}
<li><em>Sorry, there are no adults in this list</em></li>
{/foreach}
</ul>
{exitIf}
Ends the rendering of a template or block when a condition is met (i.e., “early exit”).
{exitIf !$messages}
<h1>Messages</h1>
<div n:foreach="$messages as $message">
{$message}
</div>
Including Templates
{include 'file.latte'}
See also {include block}
The {include}
tag loads and renders the specified template. In our favorite PHP language,
it's something like:
<?php include 'header.phtml'; ?>
Included templates do not have access to the variables of the active context, but they do have access to the global variables.
You can pass variables to the included template like this:
{include 'template.latte', foo: 'bar', id: 123}
The template name can be any PHP expression:
{include $someVar}
{include $ajax ? 'ajax.latte' : 'not-ajax.latte'}
The included content can be modified using filters. The following example removes all HTML and adjusts the case:
<title>{include 'heading.latte' |stripHtml|capitalize}</title>
By default, template inheritance is not involved in this.
Although you can use blocks in included templates, they will not replace corresponding blocks in the template they are included
into. Think of included templates as independent, shielded parts of pages or modules. This behavior can be changed using the
with blocks
modifier:
{include 'template.latte' with blocks}
The relationship between the file name specified in the tag and the file on disk depends on the loader.
{sandbox}
When including a template created by an end user, you should consider sandboxing it (more information in the sandbox documentation):
{sandbox 'untrusted.latte', level: 3, data: $menu}
{block}
See also {block name}
Blocks without a name provide the ability to apply filters to a part of the template. For example, you can apply a strip filter to remove unnecessary spaces:
{block|strip}
<ul>
<li>Hello World</li>
</ul>
{/block}
Exception Handling
{try}
Thanks to this tag, it's extremely easy to create robust templates.
If an exception occurs during the rendering of the {try}
block, the entire block is discarded, and rendering
continues after it:
{try}
<ul>
{foreach $twitter->loadTweets() as $tweet}
<li>{$tweet->text}</li>
{/foreach}
</ul>
{/try}
The content of the optional {else}
clause is rendered only when an exception occurs:
{try}
<ul>
{foreach $twitter->loadTweets() as $tweet}
<li>{$tweet->text}</li>
{/foreach}
</ul>
{else}
<p>Sorry, the tweets could not be loaded.</p>
{/try}
The tag can also be written as an n:attribute:
<ul n:try>
...
</ul>
It's also possible to define a custom exception handler, for example, for logging purposes.
{rollback}
The {try}
block can also be stopped and skipped manually using {rollback}
. This way, you don't have
to check all input data in advance, and only during rendering can you decide that the object shouldn't be rendered at all:
{try}
<ul>
{foreach $people as $person}
{skipIf $person->age < 18}
<li>{$person->name}</li>
{else}
{rollback}
{/foreach}
</ul>
{/try}
Variables
{var}
{default}
We create new variables in the template using the {var}
tag:
{var $name = 'John Smith'}
{var $age = 27}
{* Multiple declaration *}
{var $name = 'John Smith', $age = 27}
The {default}
tag works similarly, but it creates variables only if they do not exist. If a variable already
exists and contains the value null
, it will not be overwritten:
{default $lang = 'en'}
You can also specify variable types. For now, they are informative, and Latte does not check them.
{var string $name = $article->getTitle()}
{default int $id = 0}
{parameters}
Just as a function declares its parameters, a template can declare its variables at the beginning:
{parameters
$a,
?int $b,
int|string $c = 10
}
Variables $a
and $b
without a specified default value automatically have a default value of
null
. The declared types are currently informative, and Latte does not check them.
Variables other than those declared are not passed to the template. This differs from the {default}
tag.
{capture}
Captures the output into a variable:
{capture $var}
<ul>
<li>Hello World</li>
</ul>
{/capture}
<p>Captured: {$var}</p>
Like any pair tag, this tag can also be written as an n:attribute:
<ul n:capture="$var">
<li>Hello World</li>
</ul>
The HTML output is stored in the $var
variable as a Latte\Runtime\Html
object to prevent unwanted escaping when printing.
Others
{contentType}
Use this tag to specify the type of content the template represents. The options are:
html
(default type)xml
javascript
css
calendar
(iCal)text
Its use is important because it sets context-sensitive escaping and only then can Latte
escape correctly. For example, {contentType xml}
switches to XML mode, {contentType text}
turns off
escaping completely.
If the parameter is a full MIME type, such as application/xml
, it also sends the Content-Type
HTTP
header to the browser:
{contentType application/xml}
<?xml version="1.0"?>
<rss version="2.0">
<channel>
<title>RSS feed</title>
<item>
...
</item>
</channel>
</rss>
{debugbreak}
Specifies a point where program execution will pause. It is used for debugging purposes, allowing the programmer to inspect the runtime environment and ensure the code runs as expected. It supports Xdebug. You can also add a condition that determines when the program should pause.
{debugbreak} {* pauses the program *}
{debugbreak $counter == 1} {* pauses the program if the condition is met *}
{do}
Executes PHP code and prints nothing. As with all other tags, PHP code means a single expression, see PHP Limitations.
{do $num++}
{dump}
Dumps a variable or the current context.
{dump $name} {* Dumps the $name variable *}
{dump} {* Dumps all currently defined variables *}
Requires the Tracy library.
{php}
Allows executing any PHP code. The tag must be activated using the RawPhpExtension extension.
{spaceless}
Removes unnecessary whitespace from the output. It works similarly to the spaceless filter.
{spaceless}
<ul>
<li>Hello</li>
</ul>
{/spaceless}
Generates:
<ul> <li>Hello</li> </ul>
The tag can also be written as an n:attribute.
{syntax}
Latte tags don't have to be enclosed only in single curly braces. You can choose another separator, even at runtime. This is
done using {syntax …}
, where the parameter can be:
- double:
{{...}}
- off: completely disables Latte tag processing
Using n:attributes, you can disable Latte for just one block of JavaScript, for example:
<script n:syntax="off">
var obj = {var: 123}; // this is no longer a tag
</script>
Latte can be used very comfortably inside JavaScript, just avoid constructs like in this example, where a letter immediately
follows {
, see Latte inside
JavaScript or CSS.
If you disable Latte using {syntax off}
(i.e., the tag, not the n:attribute), it will strictly ignore all tags up
to {/syntax}
.
{trace}
Throws a Latte\RuntimeException
exception, whose stack trace follows the spirit of templates. Thus, instead of
function and method calls, it involves block calls and template inclusions. If you use a tool for clear display of thrown
exceptions, such as Tracy, you will clearly see the call stack, including all passed
arguments.
HTML Coder Helpers
n:class
Thanks to n:class
, it's very easy to generate the HTML class
attribute exactly as needed.
Example: I need the active element to have the class active
:
{foreach $items as $item}
<a n:class="$item->isActive() ? active">...</a>
{/foreach}
And further, I need the first element to have the classes first
and main
:
{foreach $items as $item}
<a n:class="$item->isActive() ? active, $iterator->first ? 'first main'">...</a>
{/foreach}
And all elements should have the class list-item
:
{foreach $items as $item}
<a n:class="$item->isActive() ? active, $iterator->first ? 'first main', list-item">...</a>
{/foreach}
Amazingly simple, isn't it?
n:attr
The n:attr
attribute can generate arbitrary HTML attributes with the same elegance as n:class.
{foreach $data as $item}
<input type="checkbox" n:attr="value: $item->getValue(), checked: $item->isActive()">
{/foreach}
Depending on the returned values, it prints, for example:
<input type="checkbox">
<input type="checkbox" value="Hello">
<input type="checkbox" value="Hello" checked>
n:tag
The n:tag
attribute can dynamically change the name of an HTML element.
<h1 n:tag="$heading" class="main">{$title}</h1>
If $heading === null
, the <h1>
tag is printed without change. Otherwise, the element name is
changed to the value of the variable, so for $heading === 'h3'
, it writes:
<h3 class="main">...</h3>
Because Latte is a secure templating system, it checks that the new tag name is valid and does not contain any unwanted or malicious values.
n:ifcontent
Prevents an empty HTML element from being printed, i.e., an element containing nothing but whitespace.
<div>
<div class="error" n:ifcontent>{$error}</div>
</div>
Depending on the value of the variable $error
, this will print:
{* $error = '' *}
<div>
</div>
{* $error = 'Required' *}
<div>
<div class="error">Required</div>
</div>
Translation
For the translation tags to work, you need to activate the
translator. You can also use the translate
filter
for translation.
{_...}
Translates values into other languages.
<a href="basket">{_'Basket'}</a>
<span>{_$item}</span>
Other parameters can also be passed to the translator:
<a href="basket">{_'Basket', domain: order}</a>
{translate}
Translates parts of the template:
<h1>{translate}Order{/translate}</h1>
{translate domain: order}Lorem ipsum ...{/translate}
The tag can also be written as an n:attribute, to translate the inside of the element:
<h1 n:translate>Order</h1>