Antlers Templates

Experimental Feature

Antlers is a simple and powerful templating engine provided with Statamic. It can fetch and filter content, display, modify, and set variables, tap into core features like user authentication and search, and handle complex logic.

Heads up!

These docs are for our brand new, opt-in Antlers Engine, added in Statamic 3.3. Read more about it, learn how to enable it on your site, and keep reading to see all the new things it can do!

Overview

Antlers is one Statamic's foundational features. It consists of a tightly coupled template language, runtime engine, and library of Tags that can be used to fetch and manipulate data, handle logic, and help you write easier to maintain HTML.

Antlers templates are also called views. Any files in the resources/views directory with an .antlers.html file extension is an "Antlers Template", and will be parsed with the Antlers Engine.

Hot Tip!

The .antlers.html extension is important. Without it, your template will be rendered as unparsed, static HTML.

Basic Example

Antlers adds dynamic features to HTML in the form of "tags" – expressions contained inside a pair of curly braces: {{ and }} Those curly braces (often called double mustaches or squiggly gigglies) look a whole lot like antlers to us, hence the name.

This is a very simple Antlers tag:

{{ hello_world }}
DON'T SKIP THIS!

About the New Antlers Engine

Not only this new Antlers Engine a complete and fundamental rewrite, but it takes a completely different, more sophisticated approach to the business of template parsing.

The original parser was essentially a glorified find and replace machine relying heavily on RegEx. It parsed and evaluated logic as it worked its way through the template. This means it couldn't stop, go backwards, set variables, or handle nested logic well because it had to keep moving forward. It also slowed down the larger the template got because of the amount of characters being pushed through the RegEx.

The New Antlers Engine now has two stages – first, it parses and builds an Abstract Syntax Tree from your complete template, and then it evaluates and executes the nodes and logic in the tree in a runtime fashion (much like a programming language) according to the established rules.

This affords Statamic an incredible amount of control. It can go sideways and slantways and longways and backways and squareways and frontways and any other ways that you can think of. This in turn allowed us to build dozens of new features, fix every single known Parser-related bug, and support syntax scenarios that were impossible in the previous "parse and evaluate" flow. Features like...

  • The ability to set variables
  • Syntax errors that reference the exact line, character, and type of error
  • The ability to control parse order through sub-expressions
  • Merge, group, order, and manipulate data without modifiers
  • Perform a robust set of mathematical operations
  • Concatenate, increment, and decrement values
  • More template logic and control flow operators
  • An improved Modifier syntax to provide better readability and type handling
  • A smarter, more forgiving matching engine so more things Just Workβ„’
  • Self-iterating assignments
  • Self-closing tags
  • next and previous loop traversal helpers
  • Run-time caching for huge performance boosts

This new engine is a powerful factory, mad scientist laboratory, and wizarding school all rolled into one. πŸ­πŸ§‘β€πŸ”¬πŸ§™β€β™€οΈ

We're calling it "Experimental"

Because of how fundamental Antlers is to the entire Statamic experience, we're shipping this new version under an opt-in feature flag until Statamic 3.4 β€” just in case it affects the behavior or output of one or more of your templates in an unexpected way. Here are a few situations we wish to avoid, in order of most-to-least likely to happen:

  1. Templates that rely on a bug in the RegEx parser suddenly behave correctly, but do so unexpectedly
  2. Templates that rely on undocumented or unknown behaviors that may have been fixed, removed, or otherwise not ported to the New Parser
  3. Actual regressions created by the new parser
  4. Performance gains are so high that your site rips a hole in the Space Time Continuum and inhales everything in the solar system into it, collapsing everything you've ever known into the space of a single atom
  5. Half-Life 3 comes out but everyone is too distracted by New Antlers to notice

If you encounter any of these scenarios (and you still exist), please open an issue so we can address it or help you get sorted.

How to Enable It

To try out the new Antlers engine, switch the statamic.antlers.version config option from regex to runtime in config/statamic/antlers.php. If you don't have this config file, create it and add the following:

// config/statamic/antlers.php
return [
'version' => 'runtime',
// ...
];

Huge Thanks to John Koster πŸ‘

This rewrite was a huge undertaking by the incomparable John Koster, who apparently found it a relaxing break from his day job. You can see the effort involved in this massive PR.

We owe him a debt of gratitude for this amazing gift.

The Basics

Delimiters

There are three kinds of delimiters.

  • {{ }} The basic and primary delimiter pair, used to render variables, evaluate expressions, call Tags, and do almost all core Antlers things.
  • {{? ?}} and {{$ $}} Allow you to write, execute, and echo PHP.
  • {{# #}} Are for code comments.

Formatting Rules

  1. Each set of curly braces must stay together always, like Kenan & Kel or Wayne & Garth. There must be a left pair and a right pair, just like HTML's < and > angle braces.
  2. Expressions are case sensitive.
  3. Use underscores and not dashes to separate words in variable names.
  4. Whitespace between the curly braces expression is optional, but recommended for readability.
  5. You may break up an expression onto multiple lines.

Consistency is important. We recommend using a single space between braces and the inner expression, lowercase variable names, and underscores as word separators. Pick your style and stick to it. Future you will thank you, but don't expect a postcard.

This is great!
{{ perfectenschlag }}
 
This is allowed.
{{squished}}
 
This can make sense when you have lots of parameters.
{{
testimonials
limit="5"
order="username"
}}
 
This is terrible in every possible way.
{{playSad_Tromb0ne }}
Hot Tip!

We recommend indenting the markup in your HTML for human readability and maintainability, not for final rendered output. Anyone still caring about that this day and age probably needs a long vacation and strong Mai Tai or two. 🍹🍹

IDE Integrations

Syntax highlighting and auto-completion packages are available for many of the popular IDEs:

Variables

Data passed into your Antlers views can be rendered by wrapping the name of a variable with double curly braces. For example, given the following data:

---
title: DJ Jazzy Jeff & The Fresh Prince
---

The title variable can be rendered like this:

<h1>{{ title }}</h1>
<h1>DJ Jazzy Jeff & The Fresh Prince</h1>

Valid Characters

Variable must start with an alpha character or underscore (a-zA-Z_), followed by any number of additional uppercase or lowercase alphanumeric characters, hyphens, or underscores (a-zA-Z_0-9). Spaces or other special characters are not allowed.

Don't be weird and mix-and-match them like a serial killer though:

<!-- Get outta here. -->
{{ this_iS-RiDicuL-ou5_ }}

Strings

Strings (simple sequences of text) are one of the most basic data types. They come in the form of variables or static expressions. To render a string variable, wrap the name with double curly braces.

<h1>{{ title }}</h1>

Antlers also handles static expressions, which are useful when concatenating strings together, setting fallback or default values, combining with modifiers, and numerous other situations we can't think of right now but you may find yourself in eventually.

To render a static string, wrap it in single or double quotes, inside a pair of curly braces.

<h1>{{ "I will eat you, donut" | upper }}</h1>
<h1>I WILL EAT YOU, DONUT</h1>

Arrays

An array is a collection of elements (values and/or variables). Elements inside the array may be iterated or looped through using the {{ value }} variable. You may also "reach in" and pluck out specific elements by their index.

Looping

---
songs:
- Brand New Funk
- Parents Just Don't Understand
- Summertime
---
 
<ul>
{{ songs }}
<li>{{ value }}</li>
{{ /songs }}
</ul>
<ul>
<li>Brand New Funk</li>
<li>Parents Just Don't Understand</li>
<li>Summertime</li>
</ul>

Plucking

To pluck values out of an array, you may use "colon", "dot", or "bracket" notation to pull out values by their array key. All three of these syntaxes are equivalent, so feel free to use the one that feels most natural to you. Note that the first item of the array starts with a zero-index key.

---
sports:
- BMXing
- rollerblading
- skateboarding
- scootering
---
 
<p>Let's go {{ sports:0 }}, {{ sports.1 }} or {{ sports[2] }}.</p>
<p>Let's go BMXing, rollerblading, or skateboarding.</p>

Dictionaries

Dictionaries are represented in YAML by nested key:value pairs, inside another variable name. These are sometimes called element maps, or associative arrays.

mailing_address:
address: 123 Foo Ave
city: Barville
province: West Exampleton
country: Docsylvania

You can access the keys inside the dictionary "colon", "dot", or "bracket" notation to traverse the levels of the array. All three of these syntaxes are equivalent, so feel free to use the one that feels most natural to you.

I live in {{ mailing_address:city }}. It's in {{ mailing_address:province }}.

Multi-Dimensional Arrays

More complex data is stored in objects or arrays inside arrays. This is usually called a multi-dimensional array.

skaters:
-
name: Tony Hawk
style: Vert
-
name: Rodney Mullen
style: Street
-
name: Bob Burnquist
style: Vert

If you know the names of the variables inside the array, you can loop through the items and access their variables.

{{ skaters }}
<div class="card">
<h2>{{ name }}</h2>
<p>{{ style }}</p>
</div>
{{ /skaters }}
<div class="card">
<h2>Tony Hawk</h2>
<p>Vert</p>
</div>
<div class="card">
<h2>Rodney Mullen</h2>
<p>Street</p>
</div>
<div class="card">
<h2>Bob Burnquist</h2>
<p>Vert</p>
</div>

You may also use "colon", "dot", or "bracket" notation to access individual values. Note that the first iteration of the array starts with a zero-index.

{{ skaters:0:name }}
{{ skaters.1.name }}<br>
{{ skaters[2]['name'] }}<br>
Tony Hawk<br>
Rodney Mullen<br>
Bob Burnquist

Dynamic Access

If you don't know the names of the keys inside the array – which can happen when working with dynamic or user submitted data – you can access the elements dynamically using variables for the key names.

Using the mailing list example, we could use a field variable to access specific keys.

---
field: country
mailing_address:
address: 123 Scary Mansion Lane
country: Docsylvania
city: Arteefem
postal_code: RU 7337
---
{{ mailing_address[field] }}
 
// Output
Docsylvania

You can combine literal and dynamic keys and get real fancy if you need to.

{{ complex_data[3][field]['title'] }}

Disambiguation πŸ†•

As your templates grow and increase in complexity, you may find yourself unsure if you're working with a variable or a tag. You may optionally disambiguate your variables by prefixing them with a $ dollar sign, just like PHP.

{{ $content }}

Modifiers

Modifiers change the output of an Antlers variable. They are used inside any expression and are separated by a pipe character |.

Multiple modifiers can be chained on one output, each separated by another pipe |, and are are applied in order from left to right. Let's look at an example.

---
title: Nickelodeon Studios
---
<!-- NICKELODEON STUDIOS rocks! -->
<h1>{{ title | upper | ensure_right('rocks!') }}</h1>
 
<!-- NICKELODEON STUDIOS ROCKS! (order matters) -->
<h1>{{ title | ensure_right('rocks!') | upper }}</h1>

Some modifiers accept parameters to control their behavior. Arguments can be passed inside a pair of () braces, just like a native PHP function. If you don't have any arguments to pass, you may omit the braces.

You may pass strings, arrays, booleans, integers, floats, objects, or references to existing variables as arguments.

{{ var | modifier('hi', ['pooh', 'pea'], true, 42, $favoriteVar) }}
Examples

Here are a few examples of modifiers in action.

summary: "It was the best of times, it was the worst of times."
noun: soups
{{ summary | replace('worst', 'yummiest') }}
{{ summary | replace('It was', 'It was also') | replace('times', $noun) }}
{{ summary | explode(' ') | ul }}
{{ (summary | contains('best')) ?= "It was lunch, is what it was." }}
It was the best of times, it was the yummiest of times.
It was also the best of soups, it was the worst of soups.
<ul><li>It</li><li>was</li><li>the</li><li>best</li><li>of</li><li>times,</li><li>it</li><li>was</li><li>the</li><li>worst</li><li>of</li><li>times.</li></ul>
It was lunch, is what it was.

There are more than 150 built-in modifiers that can do anything from array manipulations to automatically writing HTML for you. You can also create your own modifiers to do unthinkable things we assumed nobody would ever need to do, until you arrived.

You can even create Macros to combine sets of often used modifiers into one, new reusable one.

Legacy Syntax

The New Antlers Parser still supports what we're now calling the "Legacy Syntax" styles, and will continue to do so until Statamic 4.0.

Creating Variables πŸ†•

You can now set variables by using the assignment operator, =.

{{ total = 0 }}
 
{{ loop from="1" to="9" }}
{{ total += 1 }}
{{ /loop}}
 
<p>I can count to {{ total }}!</p>
<p>I can count to 9!</p>

Arrays

You can also create arrays, if you find the need. Keep in mind that more complex data might be better suited to being managed in Entries, Globals, View Models, or Controllers.

{{ todo = ['Get haircut', 'Bake bread', 'Eat soup'] }}
 
<ul>
{{ todo }}
<li>{{ value }}</li>
{{ /todo }}
</ul>

Sub-Expressions

You can assign sub-expressions or interpolated statements to variables too. In this example, you can use {{ items }} as if it were the actual Collection Tag. Because it is.

{{ items = {collection:products sort="rating:desc" limit="5"} }}
 
<h2>Our Top Products</h2>
<ul>
{{ items }}
<li><a href="{{ url }}">{{ title }}</a></li>
{{ /items }}
</ul>

Truthy and Falsy

All variables are considered "truthy" if they exist and contain a value. Variables that don't exist, contain an empty string, or are structured and empty (e.g. an empty array or object) are considered "falsy".

This is a powerful pattern that can help keep template logic simple and uncluttered. For instance, you can set a series of "fallback" variables all in one expression, allowing you to have default values and optionally override them instead of having to a bunch of if/else checks.

<!-- Which one is better? -->
<title>
{{ if meta_title }}
{{ meta_title }}
{{ elseif title }}
{{ title }}
{{ else }}
{{ site:name }}
{{ /if }}
</title>
 
<!-- Don't be ridiculous, the answer is this one. -->
<title>{{ meta_title ?? title ?? site:name }}</title>

Another use case is when you sometimes have an array variable to loop through in a template to render some markup. You may skip the existence check entirely, keep the markup inside the loop, and if the variable doesn't exist, nothing inside the tag pair will be rendered.

{{ nothing_to_see_here }}
<!-- Doesn't matter, won't see it -->
{{ /nothing_to_see_here }}

Escaping

By default, Antlers {{ }} statements are not automatically escaped. This is because in a CMS context (vs a web application), content is very often stored inside HTML markup, and this is the most logical, default behavior.

The simplest way to escape data is by using the sanitize modifier. This will run the data through PHP's htmlspecialchars() function to prevent XSS attacks.

{{ user_submitted_content | sanitize }}
Hot Tip!

Just remember: never render user-submitted data without escaping it first!

Operators

An operator is a special symbol or phrase that you use to check, change, or combine values. For example, the addition operator (+) adds numbers, as in 1 + 2. Statamic supports many of the operators you may already know from PHP, and adds a few new ones to make your life as developer easier.

Control Flow

Statamic provides a variety of control flow statements. These include if, else, or, unless, and switch statements to run different branches of template code based on defined conditions.

if

Executes a block of code only if a condition is true or "truthy".

{{ if logged_in }}
Welcome to Narnia!
{{ /if }}

You may also close if statements with {{ endif }} if you prefer.

unless

Unless is the opposite of if – executing a block of code only if a condition is not met.

{{ unless logged_in }}
You see a large wardrobe in front of you.
{{ /unless }}

You may also close unless statements with {{ endunless }} if you prefer.

elseif / else

Adds more conditions with an if or unless block.

{{ if neighbor == "Kramer" }}
These pretzels are making me thirsty!
{{ elseif neighbor == "Newman" }}
Hello...Newman.
{{ else }}
Who are you?
{{ /if }}

switch πŸ†•

The switch is perfect for complex conditions with many possible cases, or using inside interpolated regions that don't support tag pairs, like Tag Parameters.

{{ size = 'lg' }}
 
{{ switch(
(size == 'sm') => '(min-width: 768px) 35vw, 90vw',
(size == 'md') => '(min-width: 768px) 55vw, 90vw',
(size == 'lg') => '(min-width: 768px) 75vw, 90vw',
(size == 'xl') => '90vw',
() => '100vw'
)
}}
(min-width: 768px) 75vw, 90vw

Comparison

Comparison operators, as their name implies, allow you to compare two values or expressions.

Name Example Description
Equal $a == $b true if $a is equal to $b after type juggling.
Identical $a === $b true if $a is equal to $b, and are of the same type
Greater than $a > $b true if $a is greater than $b.
Greater than or equal to $a >= $b true if $a is greater than or equal to $b.
Less than $a < $b true $a is less than the $b.
Less than or equal to $a <= $b true if $a is less than or equal $b.
Not equal $a != $b true if $a is not equal to $b after type juggling.
Not identical $a !== $b true if $a is not equal to $b, only if they are of the same type.
Spaceship πŸ†• $a <=> $b Returns -1, 0 or 1 when $a is less than, equal to, or greater than $b, respectively.

Examples

Let's compare some numbers.

{{ if songs === 1 }}
<p>This is a song!</p>
{{ elseif songs > 100 }}
<p>This is noisy!</p>
{{ elseif songs }}
<p>There are some songs here.</p>
{{ else }}
<p>It is quiet.</p>
{{ /if }}

Here's a more complicated condition involving the output from a Tag.

{{ if {collection:count from="episodes"} >= 100 }}
This show is ready to be syndicated!
{{ /if }}

Logical

Logical operators join two or more expressions to create compound conditions.

Name Example Description
And $a && $b or $a and $b true if both $a and $b are true.
Or $a || $b or $a or $b true if either $a or $b is true.
Not !$a true if $a is not true.
Xor $a xor $b true if either $a or $b is true, but not both.

Ternary Statements

Ternary statements let you write a simple condition and return one value if true and another if false, all one one expression.

This item is {{ is_sold ? "sold" : "for sale" }}.
Best Practice

Ternary statements are a double-edged sword – they can simplify template code when used effectively, and greatly complicate it if pushed too far β€” like nesting one ternary inside another using a sub-expression. Make sure other developers will be able wrap their Mind Grapesβ„’ around your ternary statements.

<!-- While valid, this can be hard to follow. -->
{{ is_sold ? "sold" : (on_sale ? "on sale" : "for sale") }}

Null Coalescence

The null coalescing operator ($a ?? $b) considers each variable in a statement optional, returning the first one that passes a "truthy" check. This lets you set fallback or default values for optional data.

{{ meta_title ?? title ?? "Someone Forgot the Title" }}

The Gatekeeper (Truthy Assignment)

The Gatekeeper operator (a ?= b) will execute an expression if and only if it passes a "truthy" check. It doesn't exist in any programming language β€”Β we invented this one. Enjoy!

{{ show_bio ?= author:bio }}
 
{{ show_newsletter ?= {partial:newsletter} }}

This syntax can handle any valid expression on the right-hand side of the operator. Just make sure that when using the Gatekeeper that it's the most readable way to construct the template.

Concatenation πŸ†•

There are two methods for concatenating strings.

First, to concatenate and render a string in a single tag, you may use a + plus sign between variables and string literals to combine them. (You may also use multiple tags. Opt for whatever makes the code most readable.)

title: Marv's Coffee Shop
quality: pretty good
{{# These are equivalent #}}
<p>{{ $title + " makes " + $quality + " donuts." }}</p>
<p>{{ title }} makes {{ quality }} donuts.</p>
<p>Marv's Coffee Shop makes pretty good donuts.</p>
<p>Marv's Coffee Shop makes pretty good donuts.</p>

You may also concatenate through assignment, allowing you to render the result later in a template.

{{ string = "Hello" }}
 
{{ if something }}
{{ string += " World"}}
{{ else }}
{{ string += " Universe" }}
{{ /if }}
 
{{ string }}

Math πŸ†•

Math is all the rage. Teenagers have been found in back rooms and back alleys doing math and nobody can seem to stop them. And since the cool kids are doing it, Antlers does math now too!

Name Example Description
Addition $a + $b Sum of $a and $b.
Subtraction $a - $b. Difference of $a and $b.
Multiplication $a * $b. Product of $a and $b.
Division $a / $b. Quotient of $a and $b.
Modulo $a % $b. Remainder of $a divided $b.
Exponentiation $a ** $b Result of raising $a to the $b'th power.
Factorial $a! Factorial of $a.

Assignment πŸ†•

The basic assignment operator is =. You might immediately think that means "equal to", but stop right there. Do not pass go and do not receive $200. This means left operand gets set to the value of the expression on the right.

This is how you create variables as well as increment, decrement, or otherwise manipulate numerical variables.

Name Example Description
Left Assignment $a = $b Sets the value of $a to the value of $b.
Addition $a += $b Assigns the sum $a and $b to $a.
Subtraction $a -= $b Assigns the difference of $a and $b to $a.
Multiplication $a *= $b Assigns the product of $a and $b to $a.
Division $a /= $b Assigns the quotient of $a and $b to $a.
Modulus $a %= $b Assigns the remainder of $a divided by $a to var.

Self-Iterating Assignments πŸ†•

The left assignment operator has a super power not shared by the others. If the value of the right-hand expression returns a value that can be iterated (arrays, objects, etc.), the captured variable name can be used as a tag pair to iterate the returned value immediately.

{{ pages = {collection:pages} }}
{{ title }}
{{ /pages }}

Advanced Operators πŸ†•

These operators are here for the edge cases, the wild ideas, and the unexpected client requests at midnight the night before a site launch. These are the data wangjanglers.

Much of what they do is already handled by Modifiers or Tag Parameters (and you should use those if and whenever you can), but these operators become very useful as part of assignment expressions β€” when you've left the safety of a Tag or simplicity of a primitive variable in the dust behind you.

Merge πŸ†•

The merge operator can merge two or more "array-like" variables or expressions. The resulting data is immediately iterable without any kind of intermediate step, if you desire.

{{ articles = favourite_articles merge not_favourite_articles }}
 
{{ articles }}
{{# do your thing here #}}
{{ /articles }}
 
{{ items = {collection:headlines} merge {collection:news limit="5"} }}
{{# your thing can be done here too #}}
{{ /items }}
Best Practice

You shouldn't need to merge collections this way because the Collection Tag already supports the feature (and is more performant), but we want to show what's technically possible.

{{ %collection from="headline|news" }}
 
{{ /%collection }}

OrderBy πŸ†•

The orderby operator can be applied to any array and supports ordering by multiple properties as well as dynamic fields and directions.

Arguments are passed into a pair of parenthesis () in the following format, which accepts variables of literal 'asc' and 'desc' strings or boolean true and false for ascending and descending sort directions, respectively.

{{ var orderby (FIELD_1 DIRECTION, FIELD_2 DIRECTION) }}

Examples

dir: 'asc'
shouldSortAscending: false
{{ people orderby (age 'desc', last_name 'asc', first_name 'asc') }}
 
{{ places orderby (state $dir, city $dir, zip_code $dir) }}
 
{{ things =
{collection:hats} merge {collection:books}
orderby (rating $shouldSortAscending)
}}

GroupBy πŸ†•

The groupby operator can be applied to any array or tag output as part of an assignment expression, which automatically iterates through the newly created groups.

Arguments are passed into a pair of parenthesis (). Each argument accepts the name of a field to group by and an optional alias, with additional arguments for additional fields separated by commas ,. If you don't set an alias, it will match the name of the field you pass in.

Additionally you may set the name of the per-group values array with as 'anything_you_want at the end of the expression.

groupby (FIELD 'KEY1', FIELD2 'KEY2') as 'things'

Examples

We'll use the following data for a few of the next examples.

players:
- { team: Chicago Bulls, name: Michael Jordan, position: Guard }
- { team: Chicago Bulls, name: Scottie Pippen, position: Forward }
- { team: Chicago Bulls, name: Dennis Rodman, position: Forward }
- { team: Detroit Pistons, name: Isiah Thomas, position: Guard }
- { team: Detroit Pistons, name: Terry Mills, position: Forward }
- { team: Detroit Pistons, name: Joe Dumars, position: Guard }
Group by Single Field
{{ items = players groupby (team) }}
<h2>{{ key }}</h2>
<ul>
{{ values }}
<li>{{ name }} - {{ position }}</li>
{{ /values }}
</ul>
{{ /items }}
<h2>Chicago Bulls</h2>
<ul>
<li>Michael Jordan</li>
<li>Scotty Pippen</li>
<li>Dennis Rodman</li>
</ul>
<h2>Detroit Pistons</h2>
<ul>
<li>Isiah Thomas</li>
<li>Terry Mills</li>
<li>Joe Dumars</li>
</ul>
Group by Multiple Fields
{{ items = players groupby (team, position) }}
<h2>{{ key:team }} - {{ key:position }}</h2>
<ul>
{{ values }}
<li>{{ name }}</li>
{{ /values }}
</ul>
{{ /items }}
<h2>Chicago Bulls - Guard</h2>
<ul>
<li>Michael Jordan</li>
</ul>
 
<h2>Chicago Bulls - Forward</h2>
<ul>
<li>Scottie Pippen</li>
<li>Dennis Rodman</li>
</ul>
 
<h2>Detroit Pistons - Guard</h2>
<ul>
<li>Isiah Thomas</li>
<li>Joe Dumars</li>
</ul>
 
<h2>Detroit Pistons - Forward</h2>
<ul>
<li>Terry Mills</li>
</ul>

Group Collection Entries by Year

{{ blog = {collection:blog} groupby (date|format('Y') 'year') as 'entries' }}
<h2>{{ year }}</h2>
<ul>
{{ entries }}
<li><a href="{{ url }}">{{ title }}</a></li>
{{ /entries }}
</ul>
{{ /blog }}

Where πŸ†•

Everything you can do inside a regular Antlers condition can be performed inside a where statement. Additionally, you can use an "arrow function" (x => x.field) to establish a scoped context inside an array or object.

Examples

products:
- [name: Talkboy, price: 30]
- [name: Super Nintendo, price: 90]
- [name: Pogs, price: 1]
budget: 50
{{ bulls = players where (team == "Chicago Bulls") }}
{{# returns [Michael Jordan, Scottie Pippen, Dennis Rodman] #}}
 
{{ afford = products where (x => x.price < budget) }}
{{# returns [Talkboy, Pogs] #}}
 
{{ electronic = products where
(name == "Talkboy" || name == "Super Nintendo")
}}
{{# returns [Talkboy, Super Nintendo] #}}

Take πŸ†•

You may use the take operator to limit the number of results returned from an assignment operation.

{{ players = players take (2) }}

Skip πŸ†•

You may use the skip operator to skip a given number of results returned from an assignment operation.

{{ players = players skip (2) }}

Pluck πŸ†•

If you would like to retrieve the values from a single field, use pluck.

{{ players = players pluck ('name') }}
{{ value }}
{{ /players }}
Michael Jordan
Scottie Pippen
Dennis Rodman
Isiah Thomas
Terry Mills
Joe Dumars

The Terminator πŸ†•

Multiple expressions or statements can be performed inside a single Antlers tag pair by terminating each with ;. These terminators can often lend to more readable code for multi-line statements. However, if you don't like them, you can tell 'em "hasta la vista, baby" because they're optional (just like in JavaScript).

{{
$michael = 9986000;
$minutes_in_a_year = 60 * 24 * 365;
(($michael / $minutes_in_a_year) | format_number(0)) + " years";
}}
19 years

Expressions and Statements

If you want the computer science answer, an "expression" is a combination of values and functions that are combined and interpreted to create new values, whereas a "statement" is a standalone unit of execution that doesn't return anything. πŸ₯±

Simply put, expressions show things and statements do things. Even more simply put β€”Β they're the stuff between {{ }} braces. It's not terribly important to remember the semantic differences as it is usually clear from context whether you're trying to show a thing or do a thing.

Let's just go through the list of valid "in between braces stuff" so you can accomplish your goals and hopefully win a trophy of some kind. πŸ†

{{ "This is a single expression that renders this very text. nothing more and nothing oesseiuhdieuhd " }}
 
{{# This statement fetches Entries and begins iterating through them #}}
{{ collection:blog limit="5" }}
 
{{# This statement runs a condition check #}}
{{ if template == "home" }}
 
{{# Brace yourself β€” this complex statement assigns a boolean value
to a new variable based on a the result of a condition inside a
sub-expression, and then writes a value to the user session in
a separate statement, all inside a single Antlers region. πŸ˜… #}}
{{ $show_sale_popup = (
global:active_sale === true
&& !{session:has key="seen_popup"}
);
{session:set seen_popup="true"};
}}

Literals

Literals are the simplest type of expression. They include strings, arrays, booleans, integers, and so on. Antlers can handle literals as stand-alone expressions, as arguments, and during assignments (creating and updating variables) .

To check the type of any variable or value, use the type_of modifier:

{{ "Wazzaaap" | type_of }} -> string
{{ [1, 2, 3] | type_of }} -> array
{{ false | type_of }} -> boolean
{{ 42 | type_of }} -> integer
{{ 26.2 | type_of }} -> double (aka float)

Sub-Expressions πŸ†•

Sub-expressions are indicated by wrapping a pair of parenthesis around () a portion of text. Anything inside a sub-expression will be parsed immediately and independently, which allows you to control the order of operations inside an Antlers tag and improve code readability.

{{ 5 + 3 * 2 }} -> 11
{{ (5 + 3) * 2 }} -> 16
 
{{ if (gallery | length) >= 12 && (content | read_time) > 5 }}

Sub-expressions are supported everywhere: variable assignments, logic conditions, interpolated Tag arguments, you name it.

Tags

Tags (note the capital "T") are the primary method for accessing data from Statamic and tapping into many of the available dynamic features like search, forms, nav building, pagination, entry listing, filtering, image resizing, and so on. Check out the full list of Tags to see what's available.

Tags usually operate as pairs as they're often fetching data (like entries or assets) and looping through the results.

<ul>
{{ collection:blog }}
<li><a href="{{ url }}">{{ title }}</a>
{{ /collection:blog }}
</li>

Disambiguation πŸ†•

You may optionally disambiguate your tags by prefixing them with a % percent sign. If you're already disambiguating your variables, you may find this unnecessary, but it's here if you need it.

{{ %collection:blog }}

Tag Parameters

Most Tags can be configured through the use of Parameters, which accepts arguments β€” much like an HTML attribute. In following example, the SVG Tag is accepting a filename and string of classes to apply while rendering an inline <svg> element.

{{ svg src="icons/hamburger" class="w-8 h-8" }}

Tag Parameters are interpolated, so you can include variables and primitive forms of logic, using {single braces} instead of double. Avoid using tag pairs.

{{ nav from="{segment_1}/{segment_2}" }}
{{ collection:blog limit="{entry_limit ?? 10}" }}

You can use dynamic binding to pass the value of any variable by prefixing the parameter with a colon and using the name of the variable as your argument:

{{ nav :from="segment_1" }}

You can "void" a parameter using the void keyword. A voided parameter will act like you haven't used it at all. It's most useful when you may or may not need a parameter:

{{ if wide }}
{{ svg src="hamburger" }}
{{ else }}
{{ svg src="hamburger" class="w-full" }}
{{ /if }}
 
{{ svg src="hamburger" class="{wide ? 'w-full' : void}" }}

Working With Templates

Layouts

Most websites maintain the same general layout across various pages. Any markup you always want to present should go into a layout.

By default, Statamic uses /resources/views/layout.antlers.html, but you can create other layouts and configure specific entries or collections to use those instead by setting layout: your_layout on the entry or collection config file respectively.

Layouts often contain <head></head> markup, navs, footer, JavaScript includes, and so on. Somewhere in all that HTML you should add the {{ template_content }} variable β€” the place where content-defined templates will be injected.

<!-- resources/views/layout.antlers.html -->
<html>
<head>
<title>{{ title }} | {{ site:name }}</title>
<link rel="stylesheet" href="/css/tailwind.css">
</head>
<body>
{{ partial:nav }}
 
{{ template_content }}
 
{{ partial:footer }}
<script src="/js/site.js"></script>
</body>
</html>

Partials

Statamic's {{ partial }} tag allows you to include a view from within another view. All variables that are available to the parent view will be made available to the included partial view.

{{ partial:footer }}

Even though the included view will inherit all data available in the parent view, you may also pass an array of additional data that will be made available to the included view:

{{ partial:blog/card mode="stacked" }}

If you attempt to use a partial that doesn't exist, Statamic will throw an error. If you would like to include a partial that may or may not exist (for example, using a variable in the partial name), you should use the {{ partial:if_exists }} tag.

{{ partial:if_exists src="blog/card" }}

All views inside your /resources/views/ directory can be used as a partial, including Blade views.

Slots

Sometimes you might need to pass a large chunk of content into a partial. Jamming a bunch of HTML through a parameter would be like trying to shove a pizza through a donut. Entertaining, but futile.

Slots are the solution. By using the partial tag as a pair, everything inside will be passed into the partial, mapped to the {{ slot }} variable. Let's look at an example "modal" type of design component.

{{# /resources/views/partials/modal.antlers.html #}}
 
<div class="modal">
{{ slot }}
</div>

We can now pass whatever we want into the slot by injecting content into the partial:

{{ partial:modal }}
<h2>50% off everything, today only!</h2>
<a href="/sale">
<img src="/img/sale.jpg" alt="Man eating banana on sale." />
</a>
{{ /partial:modal }}

Named Slots πŸ†•

Sometimes you might want to render multiple different slots in different locations inside a partial. Let's modify our example to allow of the injection of a "title" slot:

{{# /resources/views/partials/modal.antlers.html #}}
 
<div class="modal">
<div class="modal-header">{{ slot:header }}</div>
<div class="modal-content">
{{ slot }}
</div>
</div>

Now you can define the context of the named slot using the slot:name tag format. Any content not within an explicit slot:name tag will be passed to the partial in the slot variable.

{{ partial:modal }}
{{ slot:header }}
{{ svg src="icons/flag" class="w-4 h-4 mr-2" }}
{{ /slot:header }}
 
<a href="/sale">
<img src="/img/sale.jpg" alt="Man eating banana on sale." />
</a>
{{ /partial:modal }}

Stacks πŸ†•

Antlers allows you to push template code to a "stack" which can be rendered somewhere else in your layout (most commonly) or another view. This can be particularly useful for specifying any JavaScript libraries required by your child views:

{{ push:scripts }}
<script src="//unpkg.com/alpinejs" defer></script>
{{ /push:scripts }}

You may push to a stack as many times as needed. To render the complete stack contents, pass the name of the stack to the {{ stack }} tag:

<head>
<!-- All that heady stuff here -->
{{ stack:scripts }}
</head>

If you would like to prepend content onto the beginning of a stack, you should use the {{ prepend }} tag:

{{ push:scripts }}
This will be second...
{{ /push:scripts }}
 
{{# Later... #}}
 
{{ prepend:scripts }}
This will be first...
{{ prepend:scripts }}

Once πŸ†•

The {{ once }} tag allows you to define a portion of the template that will only be evaluated once per rendering cycle. This may be useful for pushing a given piece of JavaScript into the page's header using stacks. For example, if you are looping through entries and rendering them with a partial, you may wish to only push the JavaScript to the header once, not every single time.

{{ collection:blog }}
 
{{ once }}
{{ push:scripts }}
<script src="//unpkg.com/alpinejs" defer></script>
{{ /push:scripts }}
{{ /once }}
 
{{ partial:blog/card }}
 
{{ /collection:blog }}

Section & Yield

You may find that you wish you to define areas of a layout that may need to change depending on which template is being rendered.

Let's peek at this basic layout as an example:

<html>
<head>
<title>{{ title }} / {{ site:name }}</title>
</head>
<body>
<div class="container">
{{ template_content }}
</div>
 
{{ yield:footer }}
<footer>
This is the main footer
</footer>
{{ /yield:footer }}
</body>
</html>

Notice the yield tag. The contents of that tag will be rendered unless another template injects content into it using the section tag.

{{# /resources/views/landing/special.antlers.html #}}
 
{{ section:footer }}
<p>Hi, I am a special footer! πŸ‘‹</p>
{{ /section:footer }}

Prevent Parsing

You may find you need to prevent Antlers statements from being parsed. This is common when working with a JavaScript library like Vue.js, writing code examples, like we do in these docs. In either case, you have a few options.

The @ ignore symbol

First, you may use an @ symbol on the outside of your curly braces to tell Antlers to leave it alone like a jellyfish on the beach. The @ symbol will be stripped out automatically leaving nothing but your full expression behind.

Hey, look at that @{{ noun }}!
Hey, look at that {{ noun }}!

The @ can also be used to escape individual braces within tag parameters or strings.

{{ partial:example attributes="class='@{font-bold: [email protected]}'" }}
// attributes="class='{font-bold: isImportant"}'"
{{ "string @{[email protected]} bar" }}
// "string {foo} bar"

The noparse Tag

Use this method if you need to prevent entire code blocks from being parsed.

{{ noparse }}
Welcome to {{ fast_food_chain }},
home of the {{ fast_food_chain_specialty_item }},
can I take your order?
{{ /noparse }}

Using Antlers in Content

Antlers template code inside your content is not parsed automatically for security and performance reasons.

You may enable Antlers parsing on a per-field basis by setting antlers: true in a given field's blueprint config.

Code Comments

Antlers code comments are not rendered in HTML (unlike HTML comments), which allows you to use them to "turn off" chunks of code, document your work, or leave notes and inside jokes for yourself and other developers.

{{# Remember to replace the lorem ipsum this time, Karen! #}}
 
{{#
<h1>@{{ title }}</h1>
<div>{{ date }}</div>
<div class="markdown">{{ content }}</div>
#}}

Using PHP in Antlers πŸ†•

You can write PHP inside special delimiters. You may use {{?...?}} to write raw PHP and manipulate the current context (variables that exist in a given request), and {{$...$}} to echo the result of a PHP expression and render HTML.

Examples

The following two examples are functionally equivalent, but each uses a different approach based on the delimiter.

{{? $register = route('account.register'); ?}}
 
<a href="{{ $register }}">Register for a new account</a>
<a href="{{$ route('account.register') $}}">Register for a new account</a>

PHP File Extension

You can also change your view's file extension from .antlers.html to .antlers.php and you can write all the raw PHP you want using native PHP tags.

<?php
echo 'Keep it simple, please';
?>
Docs feedback

Submit improvements, related content, or suggestions through Github.

Betterify this page →