Programming

Twig from scratch — templates, filters, macros and inheritance

Anna Nowak 17.10.2026 162 wyświetleń 0 komentarzy
This translation was generated by AI and may contain inaccuracies. Read the original (PL)

Three kinds of Twig tags

{# comment — does not appear in the HTML #}

{{ variable }}
{{ article.title }}
{{ user.getName() }}

{% if condition %}...{% endif %}
{% for item in collection %}...{% endfor %}
{% block content %}...{% endblock %}

Layout inheritance

This is Twig's most important feature — you avoid duplicating HTML:

{# templates/base.html.twig #}
<!DOCTYPE html>
<html>
<head>
    <title>{% block title %}FactoryCode{% endblock %}</title>
    {% block stylesheets %}{% endblock %}
</head>
<body>
    {% block body %}{% endblock %}
    {% block javascripts %}{% endblock %}
</body>
</html>
{# templates/blog/show.html.twig #}
{% extends 'base.html.twig' %}

{% block title %}{{ article.title }} — Blog{% endblock %}

{% block body %}
    <h1>{{ article.title }}</h1>
    <div class="content">
        {{ article.content|markdown }}
    </div>
{% endblock %}

Filters

{{ 'hello world'|upper }}              {# HELLO WORLD #}
{{ 'HELLO'|lower }}                    {# hello #}
{{ article.content|length }}           {# number of characters #}
{{ article.content|truncate(200) }}    {# shorten to 200 characters #}
{{ price|number_format(2, ',', ' ') }} {# 1 234,56 #}
{{ date|date('d.m.Y H:i') }}           {# 23.06.2025 14:30 #}
{{ article.content|nl2br }}            {# \n → <br> #}
{{ article.content|markdown }}         {# Markdown → HTML #}
{{ rawHtml|raw }}                      {# disable escaping #}

Conditions and loops

{% if article.isPublished %}
    <span class="badge bg-success">Published</span>
{% elseif article.status == 'draft' %}
    <span class="badge bg-secondary">Draft</span>
{% else %}
    <span class="badge bg-warning">{{ article.status }}</span>
{% endif %}

{% for tag in article.tags %}
    <span class="tag">#{{ tag.name }}</span>
{% else %}
    <span class="text-muted">No tags</span>
{% endfor %}

Macros — reuse

{% macro alert(message, type = 'info') %}
    <div class="alert alert-{{ type }}">
        {{ message }}
    </div>
{% endmacro %}

{# usage #}
{{ _self.alert('Article saved!', 'success') }}
{{ _self.alert('Validation error', 'danger') }}

include vs embed

{# include — inserts a template, inherits all variables #}
{% include 'components/_card.html.twig' with {article: article} %}

{# embed — inserts a template and lets you override its blocks #}
{% embed 'components/_modal.html.twig' %}
    {% block title %}Delete confirmation{% endblock %}
    {% block body %}Are you sure you want to delete this article?{% endblock %}
{% endembed %}

A custom Twig extension

// src/Twig/AppExtension.php
class AppExtension extends AbstractExtension
{
    public function getFilters(): array
    {
        return [
            new TwigFilter('reading_time', function (string $content): int {
                $words = str_word_count(strip_tags($content));
                return (int) ceil($words / 200); // ~200 words/min
            }),
        ];
    }
}
{# usage #}
<span>{{ article.content|reading_time }} min read</span>
Tagi: #PHP #Symfony #Twig
Udostępnij: Facebook X LinkedIn

Komentarze (0)


Bądź pierwszy — zostaw komentarz!

Zaloguj się, aby dodać komentarz.