Guide 02 · Developer docs

Template languages: Smarty and Twig

Core dna renders server-side sites with Smarty or with Twig, one engine per site, and treats the two as peers. This guide is the one place both are documented: what they share, each engine's language and the platform's additions and limits, the two side by side, and translation.

L1–L2
Unit 03 · Twig

Twig security: no sandbox and no autoescaping

Twig on Core dna runs without a sandbox and without autoescaping, and has no translation extension. What each means in practice, how it compares with Smarty's policy, a checklist for reviewing Twig code non-developers can edit, the question to ask before every output, and where translation comes from.

Who this is for. The technical lead of a Twig site, and whoever reviews its templates and the template code kept in its admin. Afterwards you know what the engine leaves to the reviewer, and what to check for it.

No sandbox

Twig offers an optional sandbox: a policy listing the tags, filters, functions, methods and properties a template may use. The platform does not enable it, so there is no such list on a Twig site. A template may use every tag, filter and function installed (What the platform adds to Twig) and call the public methods of the objects it is given.

Compared with Smarty's policy:

SmartyTwig
PHP functionsOnly the 98 on the policy's listNone directly: Twig templates use Twig's own filters and functions
Engine featuresAll of Smarty's tags and modifiersAll of Twig's tags, filters and functions
Methods on recordsOnly those on the record's response model listThe same list: the platform enforces it before either engine sees the record
A refused or unknown callThe template fails to compile, naming the callAn unknown filter or function fails to compile; a method a record refuses prints nothing
FilesOnly from the template foldersOnly from the template folders

So the safety net Smarty's list gives against an expression nobody reviewed is absent in Twig. For templates in the repository that changes little: they go through version control and review either way. It matters for template code that people other than developers can edit: the code in jobs, discount conditions, shipping methods and the search facets template, and on a Twig site the subject and body of Mailer emails (Rendering a template from a string). Decide who may edit those records, rather than relying on the engine to decide for you.

Reviewing Twig code that non-developers can edit

  1. Who can edit it? Restrict editing of jobs, discounts, shipping methods and search settings to the people you would let commit to the repository.
  2. Who last changed it, and why? Read the record's history before trusting the code.
  3. What does it touch? List the objects it uses and check that it only reads them, unless writing is its purpose.
  4. Is every output encoded for its destination? |json_encode into JSON, |e into HTML, |e('url') into a URL.
  5. Does it hold anything secret? Keys and passwords do not belong in template code.
  6. What happens when it fails? A failed discount condition does not apply and a failed shipping method offers no rates; both log the error, so check there rather than waiting on the visitor to report it.

No autoescaping

Stock Twig escapes every {{ }} in an HTML template unless told otherwise. The platform switches that off, so {{ value }} prints the value exactly, as Smarty does. You choose the escaping for each output:

Template code Twig only
<h1>{{ page.getName()|e }}</h1>                                {# text into HTML #}
<a href="/search?q={{ query|e('url') }}" title="{{ label|e('html_attr') }}">…</a>
<script nonce="{{ _inlineScriptNonce }}">window.query = {{ query|json_encode }};</script>
{{ page.body }}                                  {# authored richtext: printed as it is #}
{{ page.body|raw }}                              {# the same output: raw changes nothing here #}

Before every output, ask one question: where did this value come from, and could anyone but a developer or an editor using a richtext area have typed it?

  • From a visitor (a query parameter, a cookie, a form value echoed back): escape it for where it goes, always.
  • From an imported feed or another system: escape it; you do not control what it contains.
  • From a plain-text area (Text, Textarea): escape it, since an editor typing < means the character.
  • From a richtext area: print it as it is; it is HTML on purpose, and escaping it shows the tags.

Do not use |raw as a marker of trust. It does nothing here, so a reviewer cannot tell a deliberate |raw from a habit, and a template ported to an autoescaping environment would treat each one as an instruction. The symptoms of getting this wrong, in either engine, are on Behaviour that differs between the engines.

No translation extension

The platform registers no translation filter or tag for Twig: there is no |trans and no {% trans %}, and a theme cannot add one. What every Twig template does have is the platform's translator itself, as the variable __, reading the same translation files as a Smarty site. A multi-language Twig site writes one macro over __.translate() and uses it everywhere; Translating in Twig gives the complete approach. Translated content, as opposed to interface strings, works identically in both engines.

Go deeper

Was this page helpful?

Your answer goes to the docs team.