Skip to main content

Custom Twig Filters Reference API

SitePack registers a small set of custom filters inside the Twig environment to streamline asset URLs and sanitize link behavior. Colour math lives in the Functions Guide (calculate_brightness, calculate_text_color), though CSS color-mix() is usually the better tool — see below.

Twig filters are applied directly to variables using the pipe character (|). They can be chained together or parameterized to yield precise layouts.


Filters Reference Directory​

asset_url​

An alias for the theme_asset() function (see the Functions Guide). Turns a relative path inside your theme's /assets directory into a fully qualified, CDN-served URL.

  • Signature: string | asset_url
  • Example Usage:
    <link rel="stylesheet" href="{{ 'css/theme.css' | asset_url }}">
    <img src="{{ 'img/icons/bag.svg' | asset_url }}" alt="Shopping Bag">

Validates and normalizes an arbitrary path string (typically merchant-entered, e.g. a custom banner link or CTA URL) so it always resolves to a working link.

  • Behavior:
    • An empty or null value becomes /.
    • Values starting with /, http, #, mailto:, or tel: pass through unchanged.
    • Anything else gets a leading / prepended (e.g., 'contact-us' becomes /contact-us).
  • Signature: string | ensure_link
  • Example Usage:
    <a href="{{ page['hero-cta-url'] | ensure_link }}" class="btn-primary btn-lg">
    Shop Collection
    </a>

sitepack_html​

Safely renders a trusted rich-text HTML field — a product description, a product short description, a blog post body — that a merchant authored in the editor. It sanitizes the HTML against an allowlist (formatting, headings, lists, tables, links and images are kept; <script>, <iframe>, on* handlers and javascript: URLs are stripped) and then marks it safe to print.

  • Signature: string | sitepack_html
  • Use it instead of raw. The generic raw filter is not available in the theme sandbox (see the note under Core Twig filters); sitepack_html is the safe replacement for printing rich HTML fields. For plain text you never need it — ordinary {{ ... }} output is already escaped.
  • Example Usage:
    <div class="product-description">
    {{ product.description | sitepack_html }}
    </div>

    <div class="hub-prose">
    {{ article.content | sitepack_html }}
    </div>

sitepack_json​

Renders data as JSON for a <script> tag. It encodes with the HTML-hex flags, so <, >, & and quotes come out as \uXXXX escapes and a value containing </script> can never terminate the element that holds it.

  • Signature: any | sitepack_json
  • Use it instead of json_encode | raw. That combination is the classic way to turn a merchant's own text into stored XSS: one product title with </script><img onerror=...> in it breaks out of your script tag. sitepack_json cannot.
  • Example Usage:
    <script>
    window.ThemeConfig = {{ {currency: site.currency, products: products} | sitepack_json }};
    </script>

Translating Strings: the trans Filter​

To render translated copy, use the trans filter documented in full in the Translations Guide:

{{ 'general.welcome' | trans({'%site_name%': site.name}) }}

This is Symfony's standard translation filter running against your theme's translations/*.json dictionaries — note that its parameter placeholders use the %percent-sign% style, not Twig's own {{ double-curly }} interpolation.


Combining Filters and Functions​

Filters chain naturally and combine with the color functions from the Functions Guide to build small dynamic stylesheet snippets:

<style>
:root {
{# Calculate a darker hover shade from a merchant-picked colour #}
--accent-hover: {{ calculate_brightness(page['accent-color'] | default('#ff5500'), -15) }};
}
</style>

Prefer deriving shades in plain CSS where you can — color-mix() and filter: brightness() stay bound to the merchant's live setting, whereas a Twig-computed value is baked in at render time:

.btn:hover { filter: brightness(92%); }
.card { border: 1px solid color-mix(in srgb, var(--text-color) 15%, transparent); }

Core Twig filters you may use​

Custom filters are only part of the picture: theme templates run in a sandbox, and any core Twig filter not on its allow-list is rejected. These are permitted:

abs capitalize date default escape first
join json_encode keys last length lower
merge nl2br number_format replace reverse round
slice sort striptags title trim upper
url_encode format

Anything absent from that list and from the custom filters above is rejected when you sync the theme. That includes filters you may know from Twig elsewhere, such as split, map, reduce, batch, column and spaceless.

raw is not available

The generic raw filter is deliberately not in the sandbox — it is the classic way to introduce cross-site scripting from a template. To output a trusted rich-text HTML field (a product or blog description) use the sitepack_html filter, which sanitizes the HTML for you; to put data in a <script> tag use sitepack_json; to emit structured data use sitepack_json_ld(). All three are safe by construction.

The same rule applies to apps, which render off the same allow-list as themes. See Storefront Blocks.

A few common needs are handled by a function or a filter chain rather than a single core filter:

To do thisUse
Render a product or article image{{ article.image }} — image fields arrive fully qualified and ready to use.
Shorten copy to an excerpt{{ article.content|striptags|slice(0, 200) }}
Output a trusted rich-text HTML field{{ product.description | sitepack_html }} — sanitizes and prints merchant HTML (see above).
Emit structured data (JSON-LD){{ sitepack_json_ld(event.json_ld) }} — a safe <script type="application/ld+json"> block, e.g. the Event object from sitepack_events().

Exploring Further:​

Now that you have configured functions and filters, learn how to build extensibility zones for app integrations in the Template Hooks & App Blocks Guide!