# Templates ## Template Hierarchy Three levels, rendered inside-out: ``` Content (Markdown/HTML/PHP rendered to HTML string) → page.php or list-*.php (wraps content in semantic markup) → base.php (HTML scaffold: doctype, head, header, nav, main, footer) ``` ## Template Resolution (canonical reference) **`resolveTemplate(string $name): string`** — in `helpers.php`. This is the single resolution function used throughout the framework. 1. Check `custom/templates/{name}.php` 2. Fall back to `app/default/templates/{name}.php` The three core templates (`base`, `page`, `list`) are resolved at context creation and stored in `$ctx->templates`. Other docs reference this section for resolution behavior. ### List Template Override In `metadata.ini`: ```ini [settings] page_template = "list-grid" ``` Resolution for list template override (in `router.php`, at render time): 1. `custom/templates/{page_template}.php` 2. `app/default/templates/{page_template}.php` 3. Fall back to `$ctx->templates->list` (the default resolved at context creation) ### Default Templates Provided | Template | Purpose | |---|---| | `base.php` | HTML document scaffold | | `page.php` | Single page wrapper (`
`) | | `list.php` | Default list with cover images, dates, summaries | | `list-compact.php` | Minimal list variant | | `list-grid.php` | Card grid layout | ## Template Variables Variables are injected via `extract()` — each array key becomes a local variable. ### base.php Variables | Variable | Type | Always Set | Description | |---|---|---|---| | `$content` | string (HTML) | yes | Rendered output from page.php or list template | | `$pageTitle` | ?string | yes | Page title (null if unset) | | `$metaDescription` | ?string | no | SEO description | | `$socialImageUrl` | ?string | no | Cover image URL for og:image | | `$navigation` | array | yes | Menu items: `['title','url','order']` | | `$homeLabel` | string | yes | Home link text | | `$pageCssUrl` | ?string | no | Page-specific CSS URL | | `$pageCssHash` | ?string | no | CSS cache-bust hash | | `$currentLang` | string | plugin | Language code (from languages plugin) | | `$langPrefix` | string | plugin | URL language prefix | | `$languageUrls` | array | plugin | `[lang => url]` for language switcher | | `$translations` | array | plugin | UI strings for current language | ### page.php Variables All base.php variables plus: | Variable | Type | Description | |---|---|---| | `$content` | string (HTML) | Rendered page content | | `$metadata` | ?array | Page metadata from `metadata.ini` | ### list-*.php Variables All base.php variables plus: | Variable | Type | Description | |---|---|---| | `$items` | array | List items (see schema below) | | `$pageContent` | ?string (HTML) | Rendered content from the list directory itself | | `$metadata` | ?array | List directory metadata | ## List Item Schema Each entry in `$items`: | Key | Type | Always | Description | |---|---|---|---| | `title` | string | yes | From metadata, first heading, or folder name | | `url` | string | yes | Full URL path with trailing slash and lang prefix | | `date` | ?string | no | Formatted date string (plugin-processed) | | `summary` | ?string | no | From metadata | | `cover` | ?string | no | URL to cover image | | `pdf` | ?string | no | URL to first PDF file | | `redirect` | ?string | no | External redirect URL | Items sorted by date — direction controlled by `order` metadata on parent (`descending` default, `ascending` available). **Asset URLs vs page URLs:** Item `url` uses the translated slug. Asset paths (`cover`, `pdf`) use the actual folder name, ensuring assets resolve regardless of language. ## Adding Custom Template Variables Via `Hook::TEMPLATE_VARS`: ```php Hooks::add(Hook::TEMPLATE_VARS, function(array $vars, Context $ctx): array { $vars['myVar'] = 'value'; return $vars; }); ``` Then in any template: ``. ## Template Conventions - **Escape all user-derived output:** `` - **Exception:** `$content` is pre-rendered HTML — output raw: `` - **Check optional vars:** `` - **Use null coalescing for defaults:** `` - **Use short echo tags:** `` - **Semantic HTML5:** `
`, `