Funkce v šablonách

abort()

Přeruší zpracování požadavku s HTTP chybou.

{{ abort(404) }}                     <!-- Stránka nenalezena -->
{{ abort(403, 'Přístup zakázán') }}  <!-- S vlastní zprávou -->
{{ abort(500) }}                     <!-- Chyba serveru -->

Podmíněné použití

{% if not user.canAccess %}
    {{ abort(403, 'Nemáte oprávnění k přístupu') }}
{% endif %}

{% if not product %}
    {{ abort(404, 'Produkt neexistuje') }}
{% endif %}

redirect()

Přesměruje uživatele na jinou URL.

{{ redirect('/login') }}                    <!-- Jednoduché přesměrování -->
{{ redirect('login'|page) }}                <!-- Na CMS stránku -->
{{ redirect('product'|page({'id': 123})) }} <!-- S parametry -->

S HTTP kódem

{{ redirect('/new-url', 301) }}             <!-- Trvalé přesměrování -->
{{ redirect('/temp-page', 302) }}           <!-- Dočasné přesměrování -->

Podmíněné přesměrování

{% if not user.isLoggedIn %}
    {{ redirect('login'|page) }}
{% endif %}

{% if maintenance_mode %}
    {{ redirect('/maintenance') }}
{% endif %}

dump()

Zobrazuje debug informace o proměnné (pouze v debug módu).

{{ dump(variable) }}                        <!-- Celá proměnná -->
{{ dump(user.name) }}                      <!-- Konkrétní hodnota -->
{{ dump(products, categories) }}           <!-- Více proměnných -->

Debug komplexních dat

{{ dump(this.page) }}                      <!-- Informace o stránce -->
{{ dump(this.param) }}                     <!-- URL parametry -->
{{ dump(this.environment) }}               <!-- Prostředí aplikace -->

ℹ️

Funkce dump() zobrazuje výstup pouze pokud je aplikace v debug módu (APP_DEBUG=true).

str()

Poskytuje string helper funkce pro práce s textem.

str_limit()

{{ str_limit(text, 100) }}                 <!-- Omezí na 100 znaků -->
{{ str_limit(product.name, 50, '...') }}   <!-- S vlastním suffixem -->

str_slug()

{{ str_slug('Hello World') }}            <!-- hello-world -->
{{ str_slug('Článek č. 1') }}            <!-- clanek-c-1 -->

str_camel()

{{ str_camel('hello world') }}           <!-- helloWorld -->

str_studly()

{{ str_studly('hello world') }}           <!-- HelloWorld -->

str_snake()

{{ str_snake('hello world') }}           <!-- hello_world -->

{{ str_snake('hello world', '---') }}           <!-- hello---world -->

str_upper() a str_lower()

{{ str_upper('Hello') }}                 <!-- HELLO -->
{{ str_lower('WORLD') }}                 <!-- world -->

form()

Funkce s prefixem form_ vykonávají úkoly, které jsou užitečné při práci s formuláři. Helper mapuje přímo na PHP třídu Form a její metody. Například:

{{ form_close() }}

Výše uvedený kód je PHP ekvivalentem následujícího:

<?= Form::close() ?>

form_open()

Vypíše standardní otevírací tag <form> spolu se skrytými poli _session_key a _token pro CSRF ochranu. Pokud používáte AJAX Framework, doporučuje se místo toho použít form_ajax().

{{ form_open() }}

Atributy lze předat v prvním argumentu.

{{ form_open({ class: 'form-horizontal' }) }}

Výše uvedený příklad by vypsal následující:

<form class="form-horizontal">

Existují některé speciální možnosti, které lze také použít spolu s atributy.

{{ form_open({ request: 'onUpdate' }) }}

Funkce podporuje následující možnosti:

MožnostPopis
methodMetoda požadavku. Odpovídá atributu method tagu FORM. Např.: POST, GET, PUT, DELETE
requestNázev handleru k vykonání na serveru při odeslání formuláře. Podrobnosti o event handlerech najdete v článku Handling forms.
urlSpecifikuje URL pro odeslání formuláře. Odpovídá atributu action tagu FORM.
filesUrčuje, zda formulář bude odesílat soubory. Přijímané hodnoty: true a false.
modelModel objekt pro vazbu formuláře na model.

Praktický příklad

<!-- Základní formulář -->
{{ form_open() }}
    <div class="form-group">
        <label for="name">Jméno:</label>
        <input type="text" name="name" id="name" class="form-control" required>
    </div>
    
    <div class="form-group">
        <label for="email">Email:</label>
        <input type="email" name="email" id="email" class="form-control" required>
    </div>
    
    <button type="submit" class="btn btn-primary">Odeslat</button>
{{ form_close() }}

<!-- Formulář s upload souboru -->
{{ form_open({ files: true, method: 'POST' }) }}
    <div class="form-group">
        <label for="avatar">Avatar:</label>
        <input type="file" name="avatar" id="avatar" accept="image/*">
    </div>
    
    <button type="submit" class="btn btn-success">Nahrát</button>
{{ form_close() }}

form_ajax()

Vypíše otevírací tag FORM s povoleným AJAX. První parametr funkce form_ajax() je název AJAX handleru. Handler může být definován v layout nebo page PHP sekci kódu, může být také definován v komponentě.

{{ form_ajax('onUpdate') }}

Atributy lze předat ve druhém argumentu.

{{ form_ajax('onSave', { class: 'form-horizontal'}) }}

Výše uvedený příklad by vypsal následující:

<form data-request="onSave" class="form-horizontal">

Existují některé speciální možnosti, které lze také použít spolu s atributy.

{{ form_ajax('onDelete', { data: { id: 2 }, confirm: 'Opravdu smazat tento záznam?' }) }}

{{ form_ajax('onRefresh', { update: { statistics: '#statsPanel' } }) }}

ℹ️

Poznámka: Při pokusu o odkaz na alias komponenty s __SELF__ jako argumentem pro form_ajax() musíte nejprve sestavit řetězec, který chcete použít, mimo samotné volání.

{% set targetPartial = "'" ~ __SELF__ ~ "::statistics': '#statsPanel'" %}
{{ form_ajax('onUpdate', { update: targetPartial }) }}

Funkce podporuje následující možnosti:

MožnostPopis
successJavaScript řetězec k vykonání při úspěšném výsledku.
errorJavaScript řetězec k vykonání při neúspěšném výsledku.
confirmPotvrzovací zpráva k zobrazení před odesláním požadavku.
redirectPři úspěšném výsledku přesměruje na URL.
updatePole partialů k aktualizaci při úspěchu v následujícím formátu: { 'partial': '#element' }.
dataExtra data k zahrnutí s požadavkem v následujícím formátu: { 'myvar': 'myvalue' }.

Praktické příklady AJAX formulářů

<!-- Kontaktní formulář s AJAX -->
{{ form_ajax('onContact', { 
    update: { 'contact-form': '#contact-form', 'flash-messages': '#flash' },
    confirm: 'Odeslat kontaktní zprávu?'
}) }}
    <div id="contact-form">
        <div class="form-group">
            <label for="name">Jméno *</label>
            <input type="text" name="name" id="name" class="form-control" required>
        </div>
        
        <div class="form-group">
            <label for="email">Email *</label>
            <input type="email" name="email" id="email" class="form-control" required>
        </div>
        
        <div class="form-group">
            <label for="message">Zpráva *</label>
            <textarea name="message" id="message" class="form-control" rows="5" required></textarea>
        </div>
        
        <button type="submit" class="btn btn-primary">
            Odeslat zprávu
        </button>
    </div>
{{ form_close() }}

<!-- Newsletter signup -->
{{ form_ajax('onSubscribe', { 
    update: { 'newsletter-form': '#newsletter' },
    success: "alert('Děkujeme za přihlášení k newsletteru!')" 
}) }}
    <div id="newsletter" class="newsletter-form">
        <div class="input-group">
            <input type="email" name="email" placeholder="Váš email" class="form-control" required>
            <div class="input-group-append">
                <button type="submit" class="btn btn-success">Přihlásit</button>
            </div>
        </div>
    </div>
{{ form_close() }}

<!-- Dynamické vyhledávání -->
{{ form_ajax('onSearch', { 
    update: { 'search-results': '#results' },
    data: { category: this.param.category }
}) }}
    <div class="search-form">
        <input type="text" name="query" placeholder="Hledat..." class="form-control">
        <button type="submit" class="btn btn-outline-primary">
            <i class="fas fa-search"></i>
        </button>
    </div>
{{ form_close() }}

<div id="results">
    <!-- Výsledky vyhledávání se načtou zde -->
</div>

form_close()

Vypíše standardní uzavírací tag FORM. Tento tag je obecně dostupný pro zajištění konzistence v používání.

{{ form_close() }}

Výše uvedený příklad by vypsal následující:

</form>

Předávání atributů do generovaného elementu

Můžete předat další atributy metodě Form::open() předáním pole názvů atributů a hodnot, které budou vykresleny na finálním generovaném elementu <form>.

<?= Form::open(array('id' => 'example', 'class' => 'something')) ?>
    // ..
<?= Form::close() ?>

Výše uvedený příklad by vypsal následující:

<form method="POST" action="" accept-charset="UTF-8" id="example" class="something">

</form>

Pokročilé atributy

<!-- Formulář s vlastním ID a třídami -->
{{ form_open({ 
    id: 'registration-form',
    class: 'form-horizontal validated-form',
    'data-toggle': 'validator',
    novalidate: true
}) }}
    <!-- Obsah formuláře -->
{{ form_close() }}

<!-- AJAX formulář s callback funkcemi -->
{{ form_ajax('onRegister', {
    id: 'user-registration',
    class: 'registration-form',
    success: 'onRegistrationSuccess(data)',
    error: 'onRegistrationError(xhr, status, error)',
    confirm: 'Potvrdit registraci?'
}) }}
    <!-- Registrační formulář -->
{{ form_close() }}

Kompletní příklad registračního formuláře

<div class="registration-container">
    <h2>{{ 'Registrace nového uživatele'|_ }}</h2>
    
    <div id="flash-messages">
        {% flash %}
            <div class="alert alert-{{ type }}">{{ message }}</div>
        {% endflash %}
    </div>
    
    {{ form_ajax('onRegister', {
        id: 'registration-form',
        class: 'form-registration',
        update: { 
            'registration-form': '#registration-form',
            'flash-messages': '#flash-messages' 
        },
        confirm: 'Potvrdit registraci s těmito údaji?'
    }) }}
        <div class="form-group">
            <label for="first_name">{{ 'Jméno'|_ }} *</label>
            <input type="text" 
                   name="first_name" 
                   id="first_name" 
                   class="form-control" 
                   value="{{ form_value('first_name') }}"
                   required>
        </div>
        
        <div class="form-group">
            <label for="last_name">{{ 'Příjmení'|_ }} *</label>
            <input type="text" 
                   name="last_name" 
                   id="last_name" 
                   class="form-control"
                   value="{{ form_value('last_name') }}"
                   required>
        </div>
        
        <div class="form-group">
            <label for="email">{{ 'Email'|_ }} *</label>
            <input type="email" 
                   name="email" 
                   id="email" 
                   class="form-control"
                   value="{{ form_value('email') }}"
                   required>
        </div>
        
        <div class="form-group">
            <label for="password">{{ 'Heslo'|_ }} *</label>
            <input type="password" 
                   name="password" 
                   id="password" 
                   class="form-control"
                   minlength="8"
                   required>
        </div>
        
        <div class="form-group">
            <label for="password_confirmation">{{ 'Potvrdit heslo'|_ }} *</label>
            <input type="password" 
                   name="password_confirmation" 
                   id="password_confirmation" 
                   class="form-control"
                   required>
        </div>
        
        <div class="form-group">
            <div class="form-check">
                <input type="checkbox" 
                       name="terms" 
                       id="terms" 
                       class="form-check-input"
                       value="1"
                       required>
                <label for="terms" class="form-check-label">
                    {{ 'Souhlasím s'|_ }} 
                    <a href="{{ 'terms'|page }}" target="_blank">{{ 'obchodními podmínkami'|_ }}</a>
                </label>
            </div>
        </div>
        
        <div class="form-actions">
            <button type="submit" class="btn btn-primary btn-lg">
                {{ 'Registrovat se'|_ }}
            </button>
            
            <a href="{{ 'login'|page }}" class="btn btn-link">
                {{ 'Již mám účet'|_ }}
            </a>
        </div>
    {{ form_close() }}
</div>

<style>
.registration-container {
    max-width: 500px;
    margin: 2rem auto;
    padding: 2rem;
    border: 1px solid #dee2e6;
    border-radius: 0.5rem;
    background: #fff;
}

.form-group {
    margin-bottom: 1.5rem;
}

.form-actions {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-top: 2rem;
}

.btn-lg {
    padding: 0.75rem 1.5rem;
    font-size: 1.1rem;
}
</style>

Best Practices

1. CSRF ochrana

<!-- ✅ Vždy používejte form_open() nebo form_ajax() -->
{{ form_open() }}
<!-- Automaticky zahrnuje CSRF token -->

<!-- ❌ Nikdy nevytvářejte formulář ručně bez CSRF -->
<form method="POST"> <!-- Chybí CSRF ochrana -->

2. Validace na straně klienta

{{ form_ajax('onSubmit', { class: 'needs-validation', novalidate: true }) }}
    <div class="form-group">
        <input type="email" 
               name="email" 
               class="form-control" 
               required
               pattern="[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$">
        <div class="invalid-feedback">
            {{ 'Zadejte platnou emailovou adresu'|_ }}
        </div>
    </div>
{{ form_close() }}

3. Progresivní načítání

{{ form_ajax('onProcess', {
    update: { 'form-container': '#form-container' },
    success: "showSuccessMessage()",
    error: "showErrorMessage()"
}) }}
    <div id="form-container">
        <!-- Formulář s loading stavy -->
        <div class="loading-overlay" style="display: none;">
            <div class="spinner"></div>
        </div>
        
        <!-- Formulářové pole -->
    </div>
{{ form_close() }}

html()

Funkce s prefixem html_ vykonávají úkoly, které jsou užitečné při práci s HTML označením. Helper mapuje přímo na PHP třídu Html a její metody. Například:

{{ html_strip() }}

Výše uvedený kód je PHP ekvivalentem následujícího:

<?= Html::strip() ?>

> Poznámka: Metody v _camelCase_ by měly být převedeny na _snake_case_.

HTML funkce můžete také použít jako Twig filtr.

{{ ''|html_strip }}

html_strip()

Odstraňuje HTML značky z řetězce.

{{ html_strip('<strong>Ahoj světe</strong>') }}

Praktické příklady

<!-- Základní použití -->
{% set htmlContent = '<p>Toto je <strong>tučný text</strong> s <a href="#">odkazem</a>.</p>' %}
{{ html_strip(htmlContent) }}
<!-- Výstup: Toto je tučný text s odkazem. -->

<!-- Čištění uživatelského vstupu -->
{% set userComment = post.comment %}
<div class="comment-preview">
    {{ html_strip(userComment)|truncate(100) }}
</div>

<!-- Použití jako filtr -->
{{ article.content|html_strip|truncate(200) }}

<!-- Meta popis bez HTML -->
<meta name="description" content="{{ page.content|html_strip|truncate(160) }}">

Pokročilé použití

<!-- Seznam článků bez HTML -->
{% for article in articles %}
    <div class="article-card">
        <h3>{{ article.title }}</h3>
        <p class="excerpt">
            {{ article.content|html_strip|truncate(150, '...') }}
        </p>
        <a href="{{ article.url }}" class="read-more">{{ 'Číst více'|_ }}</a>
    </div>
{% endfor %}

<!-- Breadcrumb s čistým textem -->
<nav aria-label="breadcrumb">
    <ol class="breadcrumb">
        <li class="breadcrumb-item">
            <a href="{{ 'home'|page }}">{{ 'Domů'|_ }}</a>
        </li>
        <li class="breadcrumb-item active">
            {{ this.page.title|html_strip }}
        </li>
    </ol>
</nav>

html_limit()

Omezuje HTML na specifickou délku s korektním zacházením se značkami.

{{ html_limit('<p>Obsah příspěvku...</p>', 100) }}

Pro přidání přípony při aplikování limitu ji předejte jako třetí argument. Výchozí je ....

{{ html_limit('<p>Obsah příspěvku...</p>', 100, '... Číst více!') }}

Praktické příklady

<!-- Základní omezení délky -->
{% set articleContent = '<p>Velmi dlouhý článek s <strong>různými</strong> HTML značkami...</p>' %}
{{ html_limit(articleContent, 50) }}

<!-- Vlastní přípona -->
{{ html_limit(article.content, 200, ' <a href="' ~ article.url ~ '">číst celý článek</a>') }}

<!-- Seznam náhledů článků -->
{% for post in blogPosts %}
    <article class="post-preview">
        <h2>{{ post.title }}</h2>
        <div class="post-excerpt">
            {{ html_limit(post.content, 300, '...') }}
        </div>
        <div class="post-meta">
            <time>{{ post.published_at|date('j. n. Y') }}</time>
        </div>
    </article>
{% endfor %}

<!-- Widget nejnovějších příspěvků -->
<div class="latest-posts-widget">
    <h3>{{ 'Nejnovější příspěvky'|_ }}</h3>
    {% for post in latestPosts %}
        <div class="widget-post">
            <h4><a href="{{ post.url }}">{{ post.title }}</a></h4>
            <p>{{ html_limit(post.content, 80, '...') }}</p>
        </div>
    {% endfor %}
</div>

Pokročilé příklady

<!-- Responzivní omezení textu -->
<div class="content-preview">
    <div class="d-none d-md-block">
        <!-- Desktop verze - delší text -->
        {{ html_limit(content, 400, ' <span class="read-more-link">Pokračovat ve čtení</span>') }}
    </div>
    <div class="d-md-none">
        <!-- Mobilní verze - kratší text -->
        {{ html_limit(content, 150, '...') }}
    </div>
</div>

<!-- Dynamické omezení podle typu obsahu -->
{% set limit = this.page.id == 'blog' ? 250 : 150 %}
{{ html_limit(post.content, limit, ' <a href="' ~ post.url ~ '" class="btn btn-sm btn-outline-primary">Více</a>') }}

html_clean()

Čistí HTML pro prevenci většiny XSS útoků.

{{ html_clean('<script>window.location = "http://google.com"</script>') }}

Praktické příklady

<!-- Bezpečné zobrazení uživatelského obsahu -->
{% set userContent = comment.content %}
<div class="user-comment">
    {{ html_clean(userContent)|raw }}
</div>

<!-- Čištění obsahu z externích zdrojů -->
{% set externalContent = api.getContent() %}
<div class="external-content">
    {{ html_clean(externalContent)|raw }}
</div>

<!-- Formulář s WYSIWYG editorem -->
{{ form_ajax('onSave') }}
    <div class="form-group">
        <label for="content">{{ 'Obsah'|_ }}</label>
        <textarea name="content" id="content" class="wysiwyg-editor">
            {{ html_clean(form_value('content', model.content))|raw }}
        </textarea>
    </div>
    <button type="submit" class="btn btn-primary">{{ 'Uložit'|_ }}</button>
{{ form_close() }}

Bezpečnostní příklady

<!-- ✅ Bezpečné zobrazení uživatelského HTML -->
<div class="user-generated-content">
    {{ html_clean(user.bio)|raw }}
</div>

<!-- ✅ Čištění před uložením -->
{% set cleanContent = html_clean(form_value('content')) %}

<!-- ❌ Nezabezpečené - nepoužívejte pro nedůvěryhodný obsah -->
{{ untrustedContent|raw }}

<!-- ✅ Kombinace s dalšími filtry -->
{{ user.description|html_clean|nl2br|raw }}

<!-- Newsletter s uživatelským obsahem -->
<div class="newsletter-content">
    <h2>{{ newsletter.title }}</h2>
    <div class="content">
        {{ html_clean(newsletter.content)|raw }}
    </div>
    
    {% if newsletter.allowComments %}
        <div class="comments">
            {% for comment in newsletter.comments %}
                <div class="comment">
                    <strong>{{ comment.author }}</strong>
                    <div class="comment-text">
                        {{ html_clean(comment.text)|raw }}
                    </div>
                </div>
            {% endfor %}
        </div>
    {% endif %}
</div>

html_email()

Obfuskuje emailovou adresu pro prevenci spam-botů.

{{ html_email('a@b.c') }}

Například:

<a href="mailto:{{ html_email('a@b.c')|raw }}">Napište mi</a>

<!-- Výše uvedené vypíše -->
<a href="mailto:&#109;&#97;&#105;&#108;&#x74;o&#x3a;&#97;&#64;b.&#x63;">Napište mi</a>

Praktické příklady

<!-- Základní kontakt -->
<div class="contact-info">
    <h3>{{ 'Kontakt'|_ }}</h3>
    <p>
        <strong>{{ 'Email'|_ }}:</strong>
        <a href="mailto:{{ html_email('info@example.com')|raw }}">
            {{ html_email('info@example.com')|raw }}
        </a>
    </p>
</div>

<!-- Seznam kontaktů -->
{% for contact in contacts %}
    <div class="contact-card">
        <h4>{{ contact.name }}</h4>
        <p>{{ contact.position }}</p>
        <a href="mailto:{{ html_email(contact.email)|raw }}" class="btn btn-outline-primary">
            <i class="fas fa-envelope"></i> {{ 'Kontaktovat'|_ }}
        </a>
    </div>
{% endfor %}

<!-- Footer s kontaktními údaji -->
<footer class="site-footer">
    <div class="container">
        <div class="row">
            <div class="col-md-4">
                <h5>{{ 'Kontakt'|_ }}</h5>
                <p>
                    <i class="fas fa-envelope"></i>
                    <a href="mailto:{{ html_email(settings.contact_email)|raw }}">
                        {{ html_email(settings.contact_email)|raw }}
                    </a>
                </p>
            </div>
        </div>
    </div>
</footer>

Pokročilé použití

<!-- Kontaktní formulář s obfuskovaným emailem -->
<div class="contact-section">
    <h2>{{ 'Napište nám'|_ }}</h2>
    
    {{ form_ajax('onContact') }}
        <div class="form-group">
            <label for="email">{{ 'Váš email'|_ }}</label>
            <input type="email" name="email" id="email" class="form-control" required>
        </div>
        
        <div class="form-group">
            <label for="message">{{ 'Zpráva'|_ }}</label>
            <textarea name="message" id="message" class="form-control" rows="5" required></textarea>
        </div>
        
        <button type="submit" class="btn btn-primary">{{ 'Odeslat'|_ }}</button>
    {{ form_close() }}
    
    <div class="alternative-contact">
        <p>{{ 'Nebo nás kontaktujte přímo na'|_ }}:</p>
        <a href="mailto:{{ html_email(settings.support_email)|raw }}" class="email-link">
            {{ html_email(settings.support_email)|raw }}
        </a>
    </div>
</div>

<!-- Tým s kontakty -->
<div class="team-section">
    <h2>{{ 'Náš tým'|_ }}</h2>
    <div class="row">
        {% for member in teamMembers %}
            <div class="col-md-4">
                <div class="team-member">
                    {% if member.photo %}
                        <img src="{{ member.photo|media|resize(200, 200) }}" 
                             alt="{{ member.name }}" 
                             class="member-photo">
                    {% endif %}
                    
                    <h4>{{ member.name }}</h4>
                    <p class="position">{{ member.position }}</p>
                    
                    {% if member.bio %}
                        <p class="bio">{{ member.bio|truncate(100) }}</p>
                    {% endif %}
                    
                    <div class="contact-links">
                        {% if member.email %}
                            <a href="mailto:{{ html_email(member.email)|raw }}" 
                               class="btn btn-sm btn-outline-primary">
                                <i class="fas fa-envelope"></i>
                            </a>
                        {% endif %}
                        
                        {% if member.linkedin %}
                            <a href="{{ member.linkedin }}" 
                               target="_blank" 
                               class="btn btn-sm btn-outline-info">
                                <i class="fab fa-linkedin"></i>
                            </a>
                        {% endif %}
                    </div>
                </div>
            </div>
        {% endfor %}
    </div>
</div>

<!-- Dynamická obfuskace podle nastavení -->
{% if settings.obfuscate_emails %}
    <a href="mailto:{{ html_email(contact.email)|raw }}">
        {{ html_email(contact.email)|raw }}
    </a>
{% else %}
    <a href="mailto:{{ contact.email }}">{{ contact.email }}</a>
{% endif %}

Kombinované použití HTML funkcí

<!-- Kompletní zpracování obsahu -->
{% set processedContent = content|html_clean|html_limit(500, '...')|nl2br %}
<div class="processed-content">
    {{ processedContent|raw }}
</div>

<!-- Bezpečný náhled uživatelského obsahu -->
{% for post in userPosts %}
    <div class="user-post">
        <h3>{{ post.title|html_strip }}</h3>
        <div class="author">
            {{ 'Autor'|_ }}: {{ post.author.name }}
            {% if post.author.email %}
                <a href="mailto:{{ html_email(post.author.email)|raw }}">
                    <i class="fas fa-envelope"></i>
                </a>
            {% endif %}
        </div>
        <div class="content">
            {{ html_limit(html_clean(post.content), 300, '...')|raw }}
        </div>
    </div>
{% endfor %}

<!-- Newsletter s plnou funkčností -->
<div class="newsletter-template">
    <header class="newsletter-header">
        <h1>{{ newsletter.title|html_strip }}</h1>
        <p class="subtitle">{{ newsletter.subtitle|html_clean|raw }}</p>
    </header>
    
    <main class="newsletter-content">
        {% for article in newsletter.articles %}
            <article class="newsletter-article">
                <h2>{{ article.title|html_strip }}</h2>
                
                {% if article.author %}
                    <div class="author-info">
                        <span>{{ 'Autor'|_ }}: {{ article.author.name }}</span>
                        {% if article.author.email and settings.show_author_email %}
                            <a href="mailto:{{ html_email(article.author.email)|raw }}">
                                {{ html_email(article.author.email)|raw }}
                            </a>
                        {% endif %}
                    </div>
                {% endif %}
                
                <div class="article-content">
                    {{ html_limit(html_clean(article.content), 400, ' <a href="' ~ article.url ~ '">číst více</a>')|raw }}
                </div>
            </article>
        {% endfor %}
    </main>
    
    <footer class="newsletter-footer">
        <p>
            {{ 'Máte otázky? Kontaktujte nás na'|_ }}:
            <a href="mailto:{{ html_email(settings.support_email)|raw }}">
                {{ html_email(settings.support_email)|raw }}
            </a>
        </p>
    </footer>
</div>

Best Practices

1. Bezpečnost uživatelského obsahu

<!-- ✅ Vždy čistěte nedůvěryhodný obsah -->
{{ html_clean(userContent)|raw }}

<!-- ✅ Kombinujte s dalšími filtry -->
{{ userContent|html_clean|html_limit(200)|raw }}

<!-- ❌ Nikdy nezobrazujte neočištěný obsah -->
{{ userContent|raw }}

2. Optimalizace pro SEO

<!-- Meta popis bez HTML značek -->
<meta name="description" content="{{ page.content|html_strip|truncate(160) }}">

<!-- Open Graph bez HTML -->
<meta property="og:description" content="{{ article.excerpt|html_strip|truncate(200) }}">

<!-- Strukturovaná data -->
<script type="application/ld+json">
{
    "@context": "https://schema.org",
    "@type": "Article",
    "headline": "{{ article.title|html_strip }}",
    "description": "{{ article.content|html_strip|truncate(200) }}"
}
</script>

3. Responzivní náhledy

<!-- Adaptivní délka podle zařízení -->
<div class="content-preview">
    <div class="d-none d-lg-block">
        {{ html_limit(content, 500, '...') }}
    </div>
    <div class="d-none d-md-block d-lg-none">
        {{ html_limit(content, 300, '...') }}
    </div>
    <div class="d-md-none">
        {{ html_limit(content, 150, '...') }}
    </div>
</div>

4. Ochrana emailů

<!-- ✅ Vždy obfuskujte veřejné emaily -->
{{ html_email(publicEmail)|raw }}

<!-- ✅ Podmíněná obfuskace -->
{% if settings.protect_emails %}
    {{ html_email(email)|raw }}
{% else %}
    {{ email }}
{% endif %}