Update AGENT.md to reflect current project structure and philosophy Add comprehensive architecture documentation covering: - Directory layout - Stable contracts - Request flow - Module dependencies - Page vs list detection - Deployment models - Demo fallback Remove outdated plugin system documentation Add new content system documentation Add configuration documentation Add context API documentation Add hooks and plugins documentation Add templates documentation Add rendering documentation Add development environment documentation
4.8 KiB
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.
- Check
custom/templates/{name}.php - 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:
[settings]
page_template = "list-grid"
Resolution for list template override (in router.php, at render time):
custom/templates/{page_template}.phpapp/default/templates/{page_template}.php- 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 |
$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:
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:
$contentis 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 foreach ($items as $post): ?>
<?php include __DIR__ . '/partials/post-card.php'; ?>
<?php endforeach; ?>
Variables from the parent scope are available in the included file.