This PR provides a complete rewrite of the Antlers parser to separate it into two pieces:
- An Antlers parser: parses input strings into a list of nodes that can be evaluated to produce a final string
- An Antlers Runtime: a virtual execution environment to evaluate parser nodes
Important Note: While some new Antlers features look like PHP, Antlers is still not PHP :)
Issues Accounted For
This PR resolves, or makes improvements for, the following issues:
- Closes #4249 - ensure_right doesn't work with
|
Developers may use shorthand syntax to supply the vertical pipe as an argument: {{ title | ensure_right:"|" }}
Developers utilizing parameter-style modifiers will still need to use the HTML entity version: {{ title ensure_right=" |" }}
- Closes #4099 - Logical operator
||
seen as modifier in some case
- Closes #3636 -
where
doesn't work on terms
- Closes #4066 - in_array or contains not working as expected
- Closes #2671 - Passing data through a partial to a grandchild partial results in "NULL"
- Closes #2066 -
{{ select_var:label }}
is not working
- Closes #1798 - Can't render Antlers in content
- Closes #3286 - Yield and section tags are affected by order
- Closes #2505 - Modifier doesn't accept parameter
Any tag/expression can be returned from an Antlers sub-expression. The {{ title translate="{site:short_locale}" }}
syntax will work, but the variable reference will not.
- Closes #3624
- Closes #5128
- Closes #3980 - Shorthand if/else doesn't work with pagination
- Closes #3631 - Antlers tag is rendered in bard code block
- Closes #2161 - Noparse issue with markdown fields
- Closes #2655 - modifier & logical operators in conditions
- Closes #2722 - Some Antlers logic not working combining modifiers
- Closes #1945 -
{{ if {collection:count in="collection_name" taxonomy:year="2019"} > 0}}
throws an error when taxonomy condition is added
- Closes #3381 - Antlers if-statements do not evaluate tags correctly when using more than one
- Closes #3610 - Using double quoted parameters for modifiers in Antlers if condition throws error about unexpected double-quote
- Closes #2001 -
{{ if (collection == "pages") && (parent:slug != "home") }}
causes error
- Closes #3685 - simple OR/AND condition does not work
- Closes #3835 - Using
??
instead of or
causes form tag parser weirdness
These two are now equivalent: { foo || 'contact' }
and { foo or 'contact' }
- Closes #3790 - Can't access view's array variable with dynamic key
- Closes #3514 - Can't use
old
variable with dynamic key
- Closes #3097 - Collection tag flawed. Maybe deeper Antlers/Syntax issues?
For 3097, the syntax should preferentially use single-braces inside the tag, but double braces will technically work here:
{{ collection from="faq" limit="3"
faq_categories:contains="{faq_categories:0:id}"
:id:isnt="id"
sort="{ randomizer ? 'random' : 'order' }"
}}
Adds test coverage for #2529 (Can't use modifiers in array syntax). Cannot repro in current 3.2 branch, however.
Cannot reproduce #4993 with Runtime parser. Partial tag receives expected parameters.
Ideas Implemented
- Fixes statamic/ideas#492 - Named slots for partials
Partial: partials/_card.antlers.html
:
<div class="max-w-sm rounded overflow-hidden shadow-lg">
<img class="w-full" src="image/path.jpg" alt="{{ title }}">
<div class="px-6 py-4">
<div class="font-bold text-xl mb-2">{{ title }}</div>
<p class="text-gray-700 text-base">{{ slot }}</p>
</div>
<div class="px-6 pt-4 pb-2">
{{ if !slot:bottom }}
<span class="inline-block bg-gray-200 rounded-full px-3 py-1 text-sm font-semibold text-gray-700 mr-2 mb-2">#tag1</span>
<span class="inline-block bg-gray-200 rounded-full px-3 py-1 text-sm font-semibold text-gray-700 mr-2 mb-2">#tag2</span>
<span class="inline-block bg-gray-200 rounded-full px-3 py-1 text-sm font-semibold text-gray-700 mr-2 mb-2">#tag3</span>
{{ else }}
{{ slot:bottom }}
{{ /if }}
</div>
</div>
Other code:
{{ partial:card }}
{{ slot:bottom }}
<span>I'll appear in the bottom section.</span>
{{ /slot:bottom }}
Default slot content.
{{ /partial:card }}
- Fixes statamic/ideas#479 -
user:can
should be a conditional
Any Antlers tag/expression can now be used in a condition (even if has spaces, or HTML-like parameters):
{{ if {user:cant do="edit projects collection"} }}
{{ else }}
{{ /if }}
- Fixes statamic/ideas#364 - Output array from custom tag as var rather than iterable tag pair
- Results of tags (or any Antlers) can be assigned to variables if from an interpolation region:
{{ articles = {collection:articles} }}
{{ data = {my_tag_pair_data} }}
- Fixes statamic/ideas#200 - YAML front matter with Antlers
- Custom variables now takes its place
- Fixes statamic/ideas#41 - Temporary Variables in Antlers
Backwards Compatibility
- All existing Antlers tests pass when targeting the updated runtime
There are some instances where backwards compatibility has been broken (Antlers tags nested inside other tags, and anything that is currently taking advantage of parser bugs).
Great care has been taken to break as little as possible, but accounting for every possible scenario in the wild is not possible. Because of this, existing Antlers has not been removed, and can be used on existing projects.
Creating Variables
This PR allows developers to create variables within Antlers:
{{ total = 0 }}
{{ loop from="1" to="10" }}
{{ total += 1 }}
{{ /loop }}
<p>The total is: {{ total }}</p>
Sub-expression/interpolated regions can also be assigned to variables:
{{ pages = {collection:pages limit="5"} }}
<p>Pages:</p>
{{# Use pages as if it were the actual tag #}}
{{ pages }}
{{ if no_results }}
{{ /if }}
{{ /pages }}
Creating Arrays
Developers may create arrays within Antlers if they want to (although getting them from a view model, view composer, etc. is still preferred):
{{ myarray = arr('one', 'two', 'three') }}
Associative arrays are also supported:
{{
my_array = arr(
"one" => 1,
"two" => 2,
"three" => arr(
1,
2,
3,
4 => arr(
1,
2
)
))
}}
Calling Methods
Developers may now call methods on objects using the {{ VARNAME:METHOD_NAME() }}
syntax:
{{ object:method() }}
Developers may also pass arguments to methods:
{{ object:method('arg1', 'arg2', 'etc') }}
Additional Improvements
- Can now use nested parenthesis to get as complex as you want
- Behavior of
{}
single brace sub-expressions (interpolations) as well as nested parenthesis is now deterministic
- Predictable/deterministic tag pairing algorithm
- Developers can now use self-closing Antlers tags:
{{ myarray | length /}}
- Better parser error messages
- Internal runtime caching for augmentation (only persists for the current request)
- Large and extensive test suite
- Introduces a
once
tag-like to ensure that a part of a template only executes once
- Adds support for template stacks and queues
- Adds ways to tell the runtime how to resolve variable and tag name collisions
- Improves escaped content handling
- A low-level runtime "tracing" API that allows developers to create very complex integrations with third party tools
- Configurable block-list to prevent variable name patterns, tags, or modifiers from being executed
- And a whole lot more
Upgrading/Downgrading
By default, all existing sites and all new sites will continue to use the regex Antlers parser.
To upgrade, set the statamic.antlers.version
configuration option to runtime
.
In config/statamic/antlers.php
:
<?php
return [
'version' => 'runtime',
// ...
];
To downgrade to "legacy" Antlers, set the value to regex
(new default):
In config/statamic/antlers.php
:
<?php
return [
'version' => 'regex',
// ...
];