Templates
Templates are Twig files in templates/. In production they're compiled to PHP classes in var/cache/twig (by deploy or on first use).
The layout
templates/_layout.twig is the page shell. Two parts of it matter to TinyTank:
<html lang="{{ site.language }}">
<head>
{{ theme_script() }} {# first: light/dark before anything is painted #}
{% block seo %}{% endblock %} {# pages can set metadata here… #}
{{ seo_tags() }} {# …printed once: title, description, Open Graph, hreflang, JSON-LD #}
{{ public_config() }} {# config values allowlisted for JavaScript #}
{{ vite('resources/js/app.js', page_scripts ?? []) }} {# plus the page's own bundles #}
</head>A page sets its metadata either in its controller ($this->app->seo->title(…)) or in its template, in the seo block that renders before the tags are printed:
{% extends '_layout.twig' %}
{% block seo %}{% do seo.title('About').description('Who we are.') %}{% endblock %}What TinyTank adds to Twig
| Name | Kind | Example |
|---|---|---|
path(name, params, language) | function | {{ path('blog_post', {slug: post.slug}) }} |
t | filter | {{ 'Load more'|t }}, {{ '{n} posts'|t({n: 3}) }} |
t(message, params) | function | {{ t('Blog') }} |
vite(entry, …) | function | {{ vite('resources/js/app.js', page_scripts ?? []) }} |
public_config() | function | config values allowlisted for JavaScript |
vite_preload(source, …) | function | <link rel="preload"> for a built font or image |
theme_script() | function | the light/dark script for the top of <head> |
content(item) | function | a post, page or item's HTML with its components rendered: {{ content(post) }} |
posts(), pages(), collection(name) | functions | content queries: posts().tag('php').limit(3).all() (Querying content) |
seo_tags() | function | prints the page's metadata |
absolute_url(path) | function | {{ absolute_url('/blog') }} → https://example.com/blog |
language_switcher() | function | the current page in every language |
format_date, format_number… | filters | {{ post.date|format_date('long', locale: site.locale) }} (Twig Intl) |
site | global | site.name, site.language, site.locale |
seo | global | {% do seo.title('…') %} |
datastar | global | datastar.get('_partials/search') (Datastar) |
Plus the Datastar tags patch_elements, patch_signals, remove_elements, execute_script and location used in partials. The Twig reference has every signature.
Partials
Files in templates/_partials/ are fragments: included by pages, and rendered on their own by Datastar requests. The leading underscore is a convention; Datastar can render any template.
Error pages
templates/_error.twig renders every error (404, 405, 500) with two variables, status and message. Error pages get noindex automatically.
Escaping
Twig escapes everything by default. Use |raw only for HTML you trust; the blog's rendered post HTML is safe to print raw, because Markdown is parsed with raw HTML escaped and unsafe links removed.
Debug mode
With APP_DEBUG=1, templates aren't cached and strict_variables is on: using an undefined variable is an error instead of an empty string. Use ?? for optional variables: {{ signals.q ?? '' }}.