Template Directives v26.9+
Transactional emails, newsletter templates, and CMS pages/blocks are processed by Maho's template filter, which understands a small set of {{...}} directives. This page documents the directives and the condition syntax, including the expression support introduced in 26.9.
Variables: {{var}}
Outputs a template variable. Dotted paths traverse objects, and method calls are supported:
Hi {{var customer.name}},
your order {{var order.increment_id}} has shipped.
{{var order.getBillingAddress().format('html')}}
For object properties (order.increment_id), Maho first looks for a real getter method (getIncrementId()) and falls back to raw data access, so computed values like order.billing_address resolve the same way they do in PHP code.
Conditions: {{if}} and {{depend}}
{{if}} renders one of two branches, {{depend}} renders its body only when the condition holds:
{{if order.getIsNotVirtual()}}
Your tracking number is {{var shipment.getTrackingNumber()}}.
{{else}}
Your download is ready in your customer account.
{{/if}}
{{depend comment}}
Note from the merchant: {{var comment}}
{{/depend}}
Expressions v26.9+
Conditions are evaluated with Symfony ExpressionLanguage, so they are not limited to a single variable - comparisons, boolean logic, and method calls all work:
{{if order.grand_total > 100 && customer.group_id == 2}}
Thanks for the big wholesale order!
{{/if}}
{{if order.status in ['complete', 'closed']}}...{{/if}}
{{if customer.getName() starts with 'Dr.'}}...{{/if}}
Commonly used operators:
| Category | Operators |
|---|---|
| Comparison | == != < <= > >= |
| Boolean | && (and), || (or), ! (not) |
| Strings | ~ (concatenation), starts with, ends with, contains, matches |
| Arrays | in, not in |
| Numbers | + - * / % |
The full syntax is documented in the ExpressionLanguage reference.
Evaluation rules
- Truthiness follows PHP:
'',0,'0',null,false, and empty arrays are false, everything else is true. (Before 26.9,0and'0'were treated as true - a quirk of the old evaluator, not a feature.) - Absent variables evaluate as empty.
{{depend comment}}with nocommentvariable simply renders nothing; it does not log or fail. - A broken condition never breaks the template. If an expression fails to parse or evaluate, the else branch renders (or nothing, for
{{depend}}) and a warning is written to the log with the offending expression. - Property paths prefer getters. As with
{{var}},order.status_labelcallsgetStatusLabel()when it exists and falls back togetData('status_label').
Security
Template authors get the same power in conditions as in {{var}}, no more:
- The ExpressionLanguage
constant()function is disabled, so templates cannot read PHP or class constants. getConfig()calls against encrypted configuration paths (API passwords, keys) are neutralized, mirroring the protection applied to{{var}}output.
Includes: {{include}} and {{template}}
{{include template="..."}} includes another template by code; {{template config_path="..."}} includes the email template referenced by a system configuration path, which is how the shared header and footer are pulled into every transactional email:
Where directives are available
| Context | Filter |
|---|---|
| Transactional emails | Mage_Core_Model_Email_Template_Filter |
| Newsletter templates | Mage_Newsletter_Model_Template_Filter |
| CMS pages and blocks | Mage_Cms_Model_Template_Filter |
These filters form an inheritance chain (newsletter extends widget extends CMS extends email), so they all share the directives and condition evaluation described above. On top of the base set, the email filter adds {{block}}, {{layout}}, {{store}}, {{skin}}, {{media}}, {{config}}, {{customvar}}, {{protocol}}, {{inlinecss}}, and output modifiers such as {{var subscriber_email|escape}}; {{widget}} is available in the CMS, widget, and newsletter contexts.