Themes built on the Twig templating engine are now deprecated and require migration to Vitrin to ensure continued support and compatibility with Zid.
.twig
and .html
files to .jinja
.Twig | Jinja | Notes |
---|---|---|
raw | safe | Marks string as safe HTML so jinja doesn't double-escape. |
json_encode() | tojson | Useful for embedding data in <script> . |
filter | select / reject | Jinja uses tests/expressions: items | selectattr('x', 'equalto', 1) etc. |
url_encode | urlencode | Percent-encodes strings. |
In many cases, function-style helpers in Twig become filters in Jinja.
Twig (function/helper) | Jinja (filter) | Notes |
---|---|---|
asset_url | asset_url | Same name (environment-provided). |
assetUrl | asset_url | Switch to snake_case. |
strReplace(haystack, search, replace) | haystack | replace(search, replace) | Jinja replace takes (old, new) . |
Name | What it does | Typical usage |
---|---|---|
today() | Current date in the request’s timezone, preformatted | {{ today() }} |
now() | Current time in the request’s timezone | {{ now() }} |
format_datetime | DateTime formatter with tz /locale already set | {{ format_datetime(order.created_at) }} |
format_time | Time formatter with tz /locale already set | {{ format_time(order.created_at) }} |
url_for | Application route builder | {{ url_for('list_products') }} |
{# Current date (uses prebound fmt) #}
{{ today() }} {# e.g., 2025/08/20 #}
{# Current time #}
{{ now() }} {# e.g., 17:05 #}
{# Format a specific datetime with defaults (tz/locale are prebound) #}
{{ format_datetime(order.created_at) }}
{# Choose a predefined width: "full" | "long" | "medium" | "short" #}
{{ format_datetime(order.created_at, fmt="long") }}
{# Override the format string if needed #}
{{ format_datetime(order.created_at, fmt="%Y-%m-%d %H:%M") }}
{# Format only the time portion #}
{{ format_time(order.created_at) }}
datetime_
/time_
is omitted (None
), the helpers use “now” in the request’s timezone.fmt
accepts "full" | "long" | "medium" | "short"
or a custom format string.tz
and locale
are already supplied via partial application; override only when you truly need to.Twig Global / Helper | Jinja / App Equivalent | Example |
---|---|---|
requestAdd(query: dict) | session.url.include_query_params(**params) | session.url.include_query_params(page=2) |
requestGet | session.query_params.get() | session.query_params.get('q') |
requestUri | session.url.path | /products/123 |
requestInputs | session.url.params | Dict-like of current query. |
urlWithQuery | session.url.include_query_params(**params) | — |
rangeN | Python range(n) | range(5) → 0..4 |
rangeNWithStep | Python range(start, stop, step) | range(0, 10, 2) |
tDate | — (no direct equivalent) | Use Babel date/time formatters. |
— | url_for(name, *, localize=True, query_params=None, **path_params) | Returns app route: url_for('list_products') |
url_for
is provided by your app. Usequery_params
to append query strings.
Concept | Twig (old) | Jinja (new) |
---|---|---|
Items | response.data | response.results |
Total count | response.total | response.count |
Current page | response.current_page | response.page |
Page size / per page | response.per_page | response.page_size |
Total pages | response.last_page | response.pages_count |
Task | Twig | Jinja | Notes |
---|---|---|---|
Default value | var ?? 'x' | var or 'x' or var | default('x') | Short alias: | d('x') |
Force default on falsy | — | default('x', true) | Treats None,'' ,0,[],False as “missing”. |
Null literal | null | None | — |
{{ title or 'Untitled' }}
{{ title | default('Untitled') }}
{{ count | default(0, true) }}
Twig | Jinja |
---|---|
{% include 'x' with {a: 1} %} | {% with a=1 %}{% include 'x' %}{% endwith %} |
locals.hello_world
_("Hello world")
{{ _("Hello %(name)s", name=user.name) }}
{{ ngettext("%(n)s item", "%(n)s items", n, n=n) }}
{% schema %}...{% endschema %}
to a separate {}.schema.json
file with the same base filename..jinja
template.locals.*
usages with _('English text')
using strings from en.json
..po
file and migrate Arabic strings from ar.json
into that PO._("Welcome, {}").format(name)
_("Welcome, %(name)s", name=name)
When including or extending vitrin-managed templates, prefix with vitrin:{template}
.
Old (Twig-like) | New (Jinja) |
---|---|
{{ template_for_product_badge }} | {% include 'vitrin:products/badge.jinja' %} |
{{ template_for_product_variants_list }} | {% include 'vitrin:products/variants_list.jinja' %} |
{{ template_for_product_variants_dropdown }} | {% include 'vitrin:products/variants_dropdown.jinja' %} |
{{ template_for_product_payments_widget }} | {% include 'vitrin:products/payment_widgets.jinja' %} |
{{ template_for_product_custom_input_fields }} | {% include 'vitrin:products/custom_input_fields' %} |
{{ account_profile_template_content|safe }} | {% include 'vitrin:account/profile.jinja' %} |
{{ template_for_mazeed_badge }} | {% include 'vitrin:shared/mazeed_badge.jinja' %} |
{{ template_for_cart_products_list }} | {% include 'vitrin:cart/products_list.jinja' %} |
strReplace
:{# Twig-ish #}
{{ strReplace(title, 'old', 'new') }}
{# Jinja #}
{{ title | replace('old', 'new') }}
{{ session.url.include_query_params(page=page+1) }}
{{ url_for('list_products') }}
{{ url_for('product_details', path_params={'id': product.id}) }}
{{ format_datetime(order.created_at, format='medium', locale=session.lang) }}
{{ format_time(order.created_at, format='short') }}
select
/reject
rely on tests/expressions (e.g., selectattr
, rejectattr
, equalto
).%(name)s
) over string concatenation for translatable messages.