Theme Raed uses Twig as its templating engine. Twig provides a clean, powerful syntax for building dynamic pages.
Template structure
Templates are organized in a hierarchical structure:
src/views/
├── layouts/ # Base layouts
│ ├── master.twig # Main layout
│ └── customer.twig # Customer area layout
├── pages/ # Page templates
│ ├── index.twig # Home page
│ ├── cart.twig # Cart page
│ └── product/ # Product pages
│ └── single.twig
└── components/ # Reusable components
├── header/
├── footer/
└── home/
Template inheritance
Master layout
The base layout (layouts/master.twig) defines the HTML structure:
<! DOCTYPE html >
< html lang = "{{ user . language . code }}" dir = "{{ user . language . dir }}" >
< head >
< meta charset = "UTF-8" >
< meta name = "viewport" content = "width=device-width, initial-scale=1.0" >
{% block head_scripts %}{% endblock %}
{% block styles %}{% endblock %}
< link rel = "stylesheet" href = "{{ 'app.css' | asset }}" >
</ head >
< body >
< div class = "app-inner flex flex-col min-h-full" >
{% component 'header.header' %}
< main id = "main-content" role = "main" >
{% block content %}{% endblock %}
</ main >
{% component 'footer.footer' %}
</ div >
{% block scripts %}{% endblock %}
</ body >
</ html >
Extending layouts
Pages extend the master layout:
{% extends "layouts.master" %}
{% block content %}
< div class = "container" >
< h1 > {{ page . title }} </ h1 >
<!-- Page content -->
</ div >
{% endblock %}
{% block scripts %}
< script defer src = "{{ 'page.js' | asset }}" ></ script >
{% endblock %}
Syntax basics
Output variables
Variables
With filters
With functions
{{ store . name }}
{{ product . price }}
{{ user . language . name }}
{{ product . price | money }}
{{ store . url | cdn }}
{{ product . description | raw }}
{{ trans( 'pages.cart.empty_cart' ) }}
{{ link( '/' ) }}
{{ asset( 'app.js' ) }}
Control structures
Conditionals
If statements
If-elseif-else
{% if product . is_on_sale %}
< span class = "text-red-800" > {{ product . sale_price | money }} </ span >
< span class = "line-through" > {{ product . regular_price | money }} </ span >
{% else %}
< span > {{ product . price | money }} </ span >
{% endif %}
Loops
For loop
For-else
Loop variables
{% for item in cart . items %}
< div class = "cart-item" >
< h3 > {{ item . product_name }} </ h3 >
< p > {{ item . price | money }} </ p >
</ div >
{% endfor %}
Loop helpers
Variable Description loop.indexCurrent iteration (1-indexed) loop.index0Current iteration (0-indexed) loop.firstTrue if first iteration loop.lastTrue if last iteration loop.lengthTotal number of items loop.parentParent context in nested loops
Components
Including components
{% component 'header.header' %}
{% component 'footer.footer' %}
{% component home %}
Including partials
Include directive
Include with variables
{% include 'pages.partials.product.options' %}
Blocks
Blocks define sections that child templates can override:
Define block
Override block
Append to block
{% block content %}
Default content
{% endblock %}
{% extends "layouts.master" %}
{% block content %}
Custom content for this page
{% endblock %}
{% extends "layouts.master" %}
{% block scripts %}
{{ parent () }}
< script src = "{{ 'custom.js' | asset }}" ></ script >
{% endblock %}
Variables
Setting variables
Set simple variable
Set from template
{% set total_price = product . price * quantity %}
{% set has_many_images = product . images | length > 1 %}
Theme settings
{{ theme . settings . set ( 'placeholder' , 'images/placeholder.png' ) }}
Single line
Multi-line
Documentation
{#
This is a multi-line comment
It can span multiple lines
#}
{#
| Variable | Type | Description |
|------------------|---------|---------------------------------|
| cart | object | |
| cart.items_count | int | |
| cart.total | string | Formatted total ex: "١٠٠ ر.س" |
#}
Hooks
Salla hooks allow injecting custom code at specific points:
{% hook 'head:start' %}
{% hook head %}
{% hook 'head:end' %}
{% hook 'body:start' %}
{% hook 'body:end' %}
{% hook 'cart:items.start' %}
{% hook 'cart:items.end' %}
{% hook 'product:single.form.start' %}
{% hook 'product:single.form.end' %}
Hooks enable merchants to add custom content without modifying theme files.
Whitespace control
Control whitespace around tags:
Strip whitespace
Left strip
{%- if condition -%}
Content
{%- endif -%}
Ternary operator
{{ product . is_on_sale ? 'On sale' : 'Regular price' }}
{{ user . type == 'guest' ? 'Sign in' : 'Account' }}
< div class = "{{ product . is_on_sale ? 'sale-badge' : 'hidden' }}" >
Sale!
</ div >
Null coalescing
{{ product . subtitle ?? 'No subtitle' }}
{{ image . alt ?? product . name }}
{{ theme . settings . get ( 'imageZoom' ) ?? 'enabled' }}
String concatenation
{{ 'product-' ~ product . id }}
{{ 'details-slider-' ~ product . id }}
{{ store . url ~ '/cart' }}
Array operations
Array length
{% if product . images | length > 1 %}
< div class = "image-gallery" > ... </ div >
{% endif %}
Array slicing
{% for product in section . products | slice ( 0 , 4 ) %}
<!-- Show first 4 products -->
{% endfor %}
Array contains
{% if 'sms' in product . notify_availability . channels %}
< input type = "checkbox" name = "channel[]" value = "sms" >
{% endif %}
Object property access
Dot notation
Bracket notation
{{ store . name }}
{{ product . brand . logo }}
{{ cart . items [ 0 ].product_name }}
{{ store [ 'name' ] }}
{{ product [ 'brand' ][ 'logo' ] }}
Best practices
Keep logic minimal in templates. Use variables and filters instead of complex expressions.
Use semantic structure
<!-- Good: Clear structure -->
{% set is_on_sale = product . is_on_sale %}
{% set show_quantity = not product . is_hidden_quantity %}
{% if is_on_sale %}
<!-- Sale price display -->
{% endif %}
<!-- Avoid: Complex inline logic -->
{% if product . sale_price and product . sale_price < product . regular_price %}
<!-- Hard to read -->
{% endif %}
Optimize loops
<!-- Good: Check before looping -->
{% if products | length %}
{% for product in products %}
<!-- Product card -->
{% endfor %}
{% endif %}
<!-- Better: Use for-else -->
{% for product in products %}
<!-- Product card -->
{% else %}
< p > No products </ p >
{% endfor %}
Use lazy loading
{% for image in product . images %}
< img
src = "{{ image . url }}"
{% if loop . first %}
loading = "eager"
fetchpriority = "high"
{% else %}
loading = "lazy"
{% endif %}
>
{% endfor %}