Skip to content

Twig Templates

TIP

TTina4Twig is a Twig-compatible template engine for server-side rendering, supporting variables, control structures, filters, functions, template inheritance, and macros.

Basic Usage

pascal
var
  Twig: TTina4Twig;
  Variables: TStringDict;
begin
  Twig := TTina4Twig.Create('C:\templates');
  Variables := TStringDict.Create;
  try
    Variables.Add('name', 'Andre');
    Variables.Add('items', TValue.From<TArray<String>>(['Apple', 'Banana', 'Cherry']));

    Memo1.Lines.Text := Twig.Render('hello.html', Variables);
  finally
    Variables.Free;
    Twig.Free;
  end;
end;

Variables

Output variables with double curly braces:

{{ name }}
{{ user.email }}

Setting Variables

{% set greeting = 'Hello' %}
{% set items = ['Apple', 'Banana'] %}
{% set total = price * quantity %}

Control Structures

if / elseif / else

{% if users|length > 0 %}
  <ul>
    {% for user in users %}
      <li>{{ user.name }}</li>
    {% endfor %}
  </ul>
{% elseif guests|length > 0 %}
  <p>Guests only</p>
{% else %}
  <p>No users found</p>
{% endif %}

for loops

{% for item in items %}
  <p>{{ item }}</p>
{% endfor %}

{% for key, value in pairs %}
  <p>{{ key }}: {{ value }}</p>
{% endfor %}

{% for i in 0..10 %}
  <p>{{ i }}</p>
{% endfor %}

with

Scopes variables to a block:

{% with { title: 'Hello' } %}
  <h1>{{ title }}</h1>
{% endwith %}

Template Inheritance

extends and block

base.html:

<html>
<head><title>{% block title %}Default{% endblock %}</title></head>
<body>
  {% block content %}{% endblock %}
</body>
</html>

page.html:

{% extends 'base.html' %}

{% block title %}My Page{% endblock %}

{% block content %}
  <h1>Hello World</h1>
{% endblock %}

include

{% include 'header.html' %}
{% include 'sidebar.html' with { menu: items } %}

Set the template path so includes resolve correctly:

pascal
Twig := TTina4Twig.Create('C:\MyApp\templates');

Macros

Define reusable template fragments:

{% macro input(name, value, type) %}
  <input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value }}">
{% endmacro %}

{{ input('username', '', 'text') }}
{{ input('password', '', 'password') }}

Filters

Filters transform values using the pipe | operator. They can be chained:

{{ name|upper|length }}

String Filters

FilterDescriptionExample
upperUppercase{{ 'hello'|upper }}HELLO
lowerLowercase{{ 'HELLO'|lower }}hello
capitalizeCapitalize first letter{{ 'hello'|capitalize }}Hello
titleTitle case{{ 'hello world'|title }}Hello World
trimRemove whitespace{{ ' hi '|trim }}hi
nl2brNewlines to <br>{{ text|nl2br }}
striptagsRemove HTML tags{{ html|striptags }}
replaceReplace values{{ 'hello'|replace({'e': 'a'}) }}
splitSplit into array{{ 'a,b,c'|split(',') }}
slugURL-friendly slug{{ 'Hello World'|slug }}hello-world
spacelessRemove whitespace between tags{{ html|spaceless }}
uUnicode string{{ text|u }}

Number Filters

FilterDescriptionExample
absAbsolute value{{ -5|abs }}5
number_formatFormat number{{ 1234.5|number_format(2, '.', ',') }}
format_numberFormat with decimals{{ 1234|format_number }}
format_currencyFormat as currency{{ 1234|format_currency('USD') }}

Array Filters

FilterDescriptionExample
lengthLength of array/string{{ items|length }}
firstFirst element{{ items|first }}
lastLast element{{ items|last }}
joinJoin into string{{ items|join(', ') }}
keysGet array keys{{ obj|keys }}
mergeMerge arrays{{ arr1|merge(arr2) }}
sortSort array{{ items|sort }}
reverseReverse array/string{{ items|reverse }}
shuffleRandomize order{{ items|shuffle }}
sliceExtract portion{{ items|slice(1, 3) }}
batchSplit into chunks{{ items|batch(3) }}
columnExtract column{{ users|column('name') }}
filterFilter with callback{{ items|filter }}
findFind value{{ items|find }}
mapMap with callback{{ items|map }}
reduceReduce to single value{{ items|reduce }}
minMinimum value{{ items|min }}
maxMaximum value{{ items|max }}

Date Filters

FilterDescriptionExample
dateFormat date{{ post.created|date('Y-m-d') }}
date_modifyModify date{{ date|date_modify('+1 day') }}
format_dateFormat date (alias){{ date|format_date }}
format_datetimeFormat datetime (alias){{ date|format_datetime }}
format_timeFormat time{{ date|format_time }}

Date format uses PHP-style specifiers that are automatically converted:

SpecifierMeaningExample
Y4-digit year2026
y2-digit year26
mMonth (zero-padded)03
nMonth (no padding)3
dDay (zero-padded)01
jDay (no padding)1
HHour 24h (zero-padded)14
hHour 12h (zero-padded)02
iMinutes30
sSeconds05
AAM/PMPM
DShort day nameMon
lFull day nameMonday
MShort month nameJan
FFull month nameJanuary

Encoding Filters

FilterDescriptionExample
escape / eEscape HTML entities{{ html|escape }}
rawNo escaping{{ html|raw }}
url_encodeURL encode{{ text|url_encode }}
json_encodeEncode to JSON{{ data|json_encode }}
json_decodeDecode from JSON{{ json|json_decode }}
convert_encodingConvert charset{{ text|convert_encoding('UTF-8') }}
data_uriCreate data URI{{ content|data_uri }}

Other Filters

FilterDescription
defaultFallback value: {{ name|default('Guest') }}
formatString formatting: {{ 'Hi %s'|format(name) }}
pluralPlural form
singularSingular form

Functions

FunctionDescriptionExample
rangeGenerate number/letter sequence{% for i in range(1, 10) %}
dumpDebug output{{ dump(variable) }}
dateCreate/format dates{{ date('now', 'Y-m-d') }}

Operators

CategoryOperators
Comparison==, !=, <, >, <=, >=
Logicaland, or, not
String~ (concatenation), in, starts with, ends with, matches
Math+, -, *, /, %, **
Range.. (e.g., 1..10, 'a'..'z')

Integration with TTina4HTMLRender

The HTML renderer has built-in Twig support via its Twig property:

pascal
Tina4HTMLRender1.SetTwigVariable('title', 'Hello');
Tina4HTMLRender1.Twig.Text := '<h1>{{ title }}</h1>';

See HTML Renderer - Twig Integration for details.