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žnost | Popis |
---|---|
method | Metoda požadavku. Odpovídá atributu method tagu FORM. Např.: POST, GET, PUT, DELETE |
request | Název handleru k vykonání na serveru při odeslání formuláře. Podrobnosti o event handlerech najdete v článku Handling forms. |
url | Specifikuje URL pro odeslání formuláře. Odpovídá atributu action tagu FORM. |
files | Určuje, zda formulář bude odesílat soubory. Přijímané hodnoty: true a false. |
model | Model 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žnost | Popis |
---|---|
success | JavaScript řetězec k vykonání při úspěšném výsledku. |
error | JavaScript řetězec k vykonání při neúspěšném výsledku. |
confirm | Potvrzovací zpráva k zobrazení před odesláním požadavku. |
redirect | Při úspěšném výsledku přesměruje na URL. |
update | Pole partialů k aktualizaci při úspěchu v následujícím formátu: { 'partial': '#element' }. |
data | Extra 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:mailto:a@b.c">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 %}