Syntax
Latte syntax originated from the practical requirements of web designers. We were looking for the most user-friendly syntax, with which you can elegantly write constructs that are otherwise a real challenge. At the same time, all expressions are written exactly the same as in PHP, so you don't have to learn a new language. You simply leverage what you already know.
Below is a minimal template that illustrates several basic elements: tags, n:attributes, comments, and filters.
{* this is a comment *}
<ul n:if=$items> {* n:if is an n:attribute *}
{foreach $items as $item} {* tag representing a foreach loop *}
<li>{$item|capitalize}</li> {* tag that prints a variable with a filter *}
{/foreach} {* end of the loop *}
</ul>
Let's take a closer look at these important elements and how they can help you create an amazing template.
Tags
A template contains tags that control the template logic (for example, foreach loops) or output expressions. A single
delimiter { ... }
is used for both, so you don't have to think about which delimiter to use in which situation,
unlike other systems. If the {
character is followed by a quote or space, Latte does not consider it the beginning of
a tag, allowing you to use JavaScript constructs, JSON, or CSS rules in your templates without problems.
See the overview of all tags. Additionally, you can create your own custom tags.
Latte Understands PHP
Inside the tags, you can use PHP expressions that you are familiar with:
- variables
- strings (including HEREDOC and NOWDOC), arrays, numbers, etc.
- operators
- function and method calls (which can be restricted by sandbox)
- match
- arrow functions
- first class callable syntax
- multi-line comments
/* ... */
- etc…
Furthermore, Latte enhances PHP syntax with several nice extensions.
n:attributes
Every pair tag, such as {if} … {/if}
, operating on a single HTML element, can be rewritten in the form of
n:attributes. For example, the {foreach}
in the introductory example could also be written this way:
<ul n:if=$items>
<li n:foreach="$items as $item">{$item|capitalize}</li>
</ul>
The functionality then applies to the HTML element in which it is placed:
{var $items = ['I', '♥', 'Latte']}
<p n:foreach="$items as $item">{$item}</p>
outputs:
<p>I</p>
<p>♥</p>
<p>Latte</p>
Using the inner-
prefix, we can modify the behavior so that it applies only to the inner part of the element:
<div n:inner-foreach="$items as $item">
<p>{$item}</p>
<hr>
</div>
Outputs:
<div>
<p>I</p>
<hr>
<p>♥</p>
<hr>
<p>Latte</p>
<hr>
</div>
Or, using the tag-
prefix, we apply the functionality only to the HTML tags themselves:
<p><a href={$url} n:tag-if="$url">Title</a></p>
Which outputs, depending on the variable $url
:
{* when $url is empty *}
<p>Title</p>
{* when $url contains 'https://nette.org' *}
<p><a href="https://nette.org">Title</a></p>
However, n:attributes are not only a shortcut for pair tags, there are some pure n:attributes as well, for example the coder's best friend n:class or the very handy n:href.
Filters
See the overview of standard filters.
Filters are written after the pipe symbol (a preceding space is allowed):
<h1>{$heading|upper}</h1>
Filters can be chained, and they are applied in order from left to right:
<h1>{$heading|lower|capitalize}</h1>
Parameters are entered after the filter name, separated by colons or commas:
<h1>{$heading|truncate:20,''}</h1>
Filters can also be applied to an expression:
{var $name = ($title|upper) . ($subtitle|lower)}
On a block:
<h1>{block |lower}{$heading}{/block}</h1>
Or directly on a value (in combination with the {=expr}
tag):
<h1>{=' Hello world '|trim}<h1>
Dynamic HTML Tags
Latte supports dynamic HTML tags, which are useful when you need flexibility in tag names:
<h{$level}>Heading</h{$level}>
For example, the code above can generate <h1>Heading</h1>
or <h2>Heading</h2>
depending on the value of the variable $level
. Dynamic HTML tags in Latte must always be paired. Their alternative is
n:tag.
Because Latte is a secure templating system, it checks that the resulting tag name is valid and does not contain any unwanted or malicious values. It also ensures that the end tag name always matches the opening tag name.
Comments
Comments are written this way and do not get into the output:
{* this is a comment in Latte *}
PHP comments work inside tags:
{include 'file.info', /* value: 123 */}
Syntactic Sugar
Strings Without Quotation Marks
Quotation marks can be omitted for simple strings:
as in PHP: {var $arr = ['hello', 'btn--default', '€']}
abbreviated: {var $arr = [hello, btn--default, €]}
Simple strings are those composed purely of letters, digits, underscores, hyphens, and periods. They must not start with a
digit and must not start or end with a hyphen. They must not consist solely of uppercase letters and underscores, as they are then
considered constants (e.g., PHP_VERSION
). And they must not conflict with the keywords: and
,
array
, clone
, default
, false
, in
, instanceof
,
new
, null
, or
, return
, true
, xor
.
Constants
Since quotes can be omitted for simple strings, we recommend writing global constants with a leading slash to distinguish them:
{if \PROJECT_ID === 1} ... {/if}
This notation is entirely valid in PHP itself, where the slash indicates that the constant is in the global namespace.
Short Ternary Operator
If the third value of the ternary operator is empty, it can be omitted:
as in PHP: {$stock ? 'In stock' : ''}
abbreviated: {$stock ? 'In stock'}
Modern Key Notation in Arrays
Array keys can be written similarly to named parameters when calling functions:
as in PHP: {var $arr = ['one' => 'item 1', 'two' => 'item 2']}
modern: {var $arr = [one: 'item 1', two: 'item 2']}
Filters
Filters can be used for any expression; just enclose the whole expression in parentheses:
{var $content = ($text|truncate: 30|upper)}
Operator in
The in
operator can replace the in_array()
function. The comparison is always strict:
{* like in_array($item, $items, true) *}
{if $item in $items}
...
{/if}
A Window into History
Over its history, Latte introduced several syntactic sugar features that appeared in PHP itself a few years later. For example,
in Latte, it was possible to write arrays as [1, 2, 3]
instead of array(1, 2, 3)
or use the nullsafe
operator $obj?->foo
long before it was possible in PHP itself. Latte also introduced the array expansion operator
(expand) $arr
, which is equivalent to today's ...$arr
operator from PHP.
The undefined-safe operator ??->
, which is similar to the nullsafe operator ?->
but does not
raise an error if the variable does not exist, was created for historical reasons, and today we recommend using the standard PHP
operator ?->
.
PHP Limitations in Latte
Only PHP expressions can be written in Latte. That is, statements ending with a semicolon cannot be used. You cannot declare
classes or use control structures, such as
if
, foreach
, switch
, return
, try
, throw
, and others,
for which Latte offers its tags. You also cannot use attributes, backticks, or some magic constants. You cannot use unset
,
echo
, include
, require
, exit
, eval
either, because they are not
functions but special PHP language constructs, and thus not expressions. Only multi-line comments /* ... */
are
supported.
However, these limitations can be bypassed by activating the RawPhpExtension extension, which allows you to use any PHP code
within the {php ...}
tag at the template author's responsibility.