Introduce `feed` metadata option to enable Atom feeds Update list item structure with standardized fields Add `$feedUrl` template variable for autodiscovery Improve date handling with raw/processed date separation Document feed generation in architecture and rendering docs Update template examples to use new item structure
147 lines
5 KiB
Markdown
147 lines
5 KiB
Markdown
# 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 (`<article><?= $content ?></article>`) |
|
|
| `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 |
|
|
| `$feedUrl` | ?string | no | Atom feed URL (only on lists with `feed = true`) |
|
|
| `$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) |
|
|
| `rawDate` | ?string | no | ISO `YYYY-MM-DD` date (for feeds, `<time>` elements) |
|
|
| `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 |
|
|
| `dirPath` | string | yes | Filesystem path to item directory (internal use) |
|
|
|
|
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: `<?= $myVar ?>`.
|
|
|
|
## Template Conventions
|
|
|
|
- **Escape all user-derived output:** `<?= htmlspecialchars($var) ?>`
|
|
- **Exception:** `$content` is pre-rendered HTML — output raw: `<?= $content ?>`
|
|
- **Check optional vars:** `<?php if (!empty($var)): ?>`
|
|
- **Use null coalescing for defaults:** `<?= $var ?? 'fallback' ?>`
|
|
- **Use short echo tags:** `<?= $expr ?>`
|
|
- **Semantic HTML5:** `<article>`, `<nav>`, `<header>`, `<footer>`, `<time>`, `<main>`
|
|
- **ARIA labels** on navigation elements
|
|
- **Classless defaults** — the default theme uses semantic HTML without classes where possible
|
|
|
|
## Partials
|
|
|
|
Not a framework feature — just PHP includes. Convention:
|
|
|
|
```
|
|
custom/templates/partials/post-card.php
|
|
```
|
|
|
|
Include from templates:
|
|
|
|
```php
|
|
<?php foreach ($items as $post): ?>
|
|
<?php include __DIR__ . '/partials/post-card.php'; ?>
|
|
<?php endforeach; ?>
|
|
```
|
|
|
|
Variables from the parent scope are available in the included file.
|