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
11 KiB
Template Variables Reference
Templates have access to a set of variables provided by FolderWeb and its plugins. This reference documents all available variables and their types.
Base Template Variables
Available in base.php:
$content
The fully rendered HTML content from the page or list template.
Type: String (HTML)
Example:
<main>
<?= $content ?>
</main>
$pageTitle
The page title for the <title> tag.
Type: String
Default: "FolderWeb"
Example:
<title><?= htmlspecialchars($pageTitle ?? 'FolderWeb') ?></title>
Source:
- Language-specific metadata
[lang] title - Root metadata
title - First heading in content
- Folder name
$metaDescription
SEO description for the <meta name="description"> tag.
Type: String
Optional: May be empty
Example:
<?php if (!empty($metaDescription)): ?>
<meta name="description" content="<?= htmlspecialchars($metaDescription) ?>">
<?php endif; ?>
Source:
- Metadata
search_description - Metadata
summary - Empty if not set
$socialImageUrl
URL to cover image for social media meta tags.
Type: String (URL)
Optional: May be empty
Example:
<?php if (!empty($socialImageUrl)): ?>
<meta property="og:image" content="<?= htmlspecialchars($socialImageUrl) ?>">
<?php endif; ?>
Source: First cover.* image found in content directory
$navigation
Array of navigation menu items.
Type: Array of associative arrays
Structure:
[
['url' => '/about/', 'title' => 'About'],
['url' => '/blog/', 'title' => 'Blog'],
['url' => '/contact/', 'title' => 'Contact'],
]
Example:
<?php if (!empty($navigation)): ?>
<nav>
<?php foreach ($navigation as $item): ?>
<a href="<?= htmlspecialchars($item['url']) ?>">
<?= htmlspecialchars($item['title']) ?>
</a>
<?php endforeach; ?>
</nav>
<?php endif; ?>
Source: Pages with menu = 1 in metadata, sorted by menu_order
$homeLabel
Text for the home link.
Type: String
Default: "Home"
Example:
<a href="/"><?= htmlspecialchars($homeLabel ?? 'Home') ?></a>
Source: Translation string translations['home'] or fallback "Home"
$currentLang
Current language code.
Type: String
Default: From config.ini languages.default
Example:
<html lang="<?= htmlspecialchars($currentLang ?? 'en') ?>">
Values: ISO 639-1 language codes (en, no, de, etc.)
$langPrefix
URL prefix for the current language.
Type: String
Default: Empty string for default language
Example:
<a href="<?= htmlspecialchars($langPrefix ?? '') ?>/">Home</a>
Values:
""(empty) for default language"/no"for Norwegian"/de"for German- etc.
$languageUrls
URLs to switch between available languages.
Type: Associative array
Structure:
[
'en' => '/page/',
'no' => '/no/side/',
'de' => '/de/seite/',
]
Example:
<?php if (!empty($languageUrls) && count($languageUrls) > 1): ?>
<nav class="language-switcher">
<?php foreach ($languageUrls as $lang => $url): ?>
<a href="<?= htmlspecialchars($url) ?>"
<?= ($lang === $currentLang) ? 'aria-current="true"' : '' ?>>
<?= htmlspecialchars(strtoupper($lang)) ?>
</a>
<?php endforeach; ?>
</nav>
<?php endif; ?>
$translations
Translated UI strings for the current language.
Type: Associative array
Structure:
[
'home' => 'Home',
'footer_handcoded' => 'Generated in',
'footer_page_time' => 'ms',
'months' => 'January,February,March,...',
]
Example:
<p><?= htmlspecialchars($translations['home'] ?? 'Home') ?></p>
Source: Language files in custom/languages/[lang].ini or app/default/languages/[lang].ini
$pageCssUrl
URL to page-specific CSS file.
Type: String (URL)
Optional: Only set if styles.css exists in content directory
Example:
<?php if (!empty($pageCssUrl)): ?>
<link rel="stylesheet" href="<?= htmlspecialchars($pageCssUrl) ?>?v=<?= htmlspecialchars($pageCssHash ?? '') ?>">
<?php endif; ?>
$pageCssHash
MD5 hash of page-specific CSS for cache busting.
Type: String (MD5 hash)
Optional: Only set if $pageCssUrl exists
Example: See $pageCssUrl above
$feedUrl
URL to the Atom feed for the current list page.
Type: String (URL path)
Optional: Only set on list pages with feed = true in metadata
Example:
<?php if (!empty($feedUrl)): ?>
<link rel="alternate" type="application/atom+xml" title="<?= htmlspecialchars($pageTitle ?? 'Feed') ?>" href="<?= htmlspecialchars($feedUrl) ?>">
<?php endif; ?>
Source: Set when feed = true in the list directory's metadata.ini
Page Template Variables
Available in page.php:
$content
The fully rendered HTML content from the page.
Type: String (HTML)
Example:
<article>
<?= $content ?>
</article>
$metadata
All metadata for the current page.
Type: Associative array
Structure:
[
'title' => 'Page Title',
'summary' => 'Short description',
'date' => '2024-12-15',
'show_date' => true,
'author' => 'Jane Doe', // Custom fields
'tags' => 'web,design',
// ... all other metadata fields
]
Example:
<?php if (isset($metadata['title'])): ?>
<h1><?= htmlspecialchars($metadata['title']) ?></h1>
<?php endif; ?>
<?php if (isset($metadata['date']) && ($metadata['show_date'] ?? true)): ?>
<time datetime="<?= $metadata['date'] ?>">
<?= $metadata['date'] ?>
</time>
<?php endif; ?>
List Template Variables
Available in list.php, list-grid.php, list-compact.php, etc.:
$pageContent
Optional intro content from the directory's own files.
Type: String (HTML)
Optional: May be empty
Example:
<?php if ($pageContent): ?>
<div class="intro">
<?= $pageContent ?>
</div>
<?php endif; ?>
Source: Content files in the list directory itself (not subdirectories)
$items
Array of items to display in the list.
Type: Array of associative arrays
Structure:
[
[
'title' => 'My Post',
'url' => '/blog/my-post/',
'date' => '15. desember 2024', // Formatted for display
'rawDate' => '2024-12-15', // ISO YYYY-MM-DD
'summary' => 'Short description',
'cover' => '/blog/2024-12-15-my-post/cover.jpg',
'pdf' => null,
'redirect' => null,
'dirPath' => '/path/to/content/blog/2024-12-15-my-post',
],
// ... more items
]
Example:
<?php foreach ($items as $item): ?>
<article>
<?php if ($item['cover']): ?>
<img src="<?= $item['cover'] ?>"
alt="<?= htmlspecialchars($item['title']) ?>">
<?php endif; ?>
<h2>
<a href="<?= $item['url'] ?>">
<?= htmlspecialchars($item['title']) ?>
</a>
</h2>
<?php if ($item['date']): ?>
<time datetime="<?= $item['rawDate'] ?>">
<?= $item['date'] ?>
</time>
<?php endif; ?>
<?php if ($item['summary']): ?>
<p><?= htmlspecialchars($item['summary']) ?></p>
<?php endif; ?>
</article>
<?php endforeach; ?>
$metadata
Metadata for the list directory itself.
Type: Associative array
Structure: Same as page metadata
Example:
<?php if (isset($metadata['title'])): ?>
<h1><?= htmlspecialchars($metadata['title']) ?></h1>
<?php endif; ?>
Item Properties
Each item in $items has these properties:
| Property | Type | Description | Optional |
|---|---|---|---|
title |
String | Item title (from metadata, heading, or folder name) | No |
url |
String | Full URL to the item (with trailing slash + lang prefix) | No |
date |
String | Formatted date string (plugin-processed for display) | Yes |
rawDate |
String | ISO date (YYYY-MM-DD) for feeds and <time> elements |
Yes |
summary |
String | Short description from metadata | Yes |
cover |
String | URL to cover image | Yes |
pdf |
String | URL to first PDF file | Yes |
redirect |
String | External redirect URL | Yes |
dirPath |
String | Filesystem path to item directory (internal use) | No |
Adding Custom Variables
Use the Hook::TEMPLATE_VARS hook to add custom variables:
Hooks::add(Hook::TEMPLATE_VARS, function(array $vars, Context $ctx) {
// Add a custom variable
$vars['siteName'] = 'My Website';
// Add computed values
$vars['currentYear'] = date('Y');
// Add from context
$vars['userName'] = $ctx->get('user_name', 'Guest');
return $vars;
});
Then use in templates:
<p>© <?= $currentYear ?> <?= htmlspecialchars($siteName) ?></p>
Variable Availability by Template
| Variable | base.php |
page.php |
list.php |
|---|---|---|---|
$content |
✓ | ✓ | — |
$pageTitle |
✓ | — | — |
$metaDescription |
✓ | — | — |
$socialImageUrl |
✓ | — | — |
$navigation |
✓ | — | — |
$homeLabel |
✓ | — | — |
$currentLang |
✓ | — | — |
$langPrefix |
✓ | — | — |
$languageUrls |
✓ | — | — |
$translations |
✓ | — | — |
$pageCssUrl |
✓ | — | — |
$pageCssHash |
✓ | — | — |
$feedUrl |
✓ | — | — |
$metadata |
— | ✓ | ✓ |
$pageContent |
— | — | ✓ |
$items |
— | — | ✓ |
Note: All variables are technically available everywhere via plugin hooks, but this table shows the default availability.
Escaping Output
Always escape user content to prevent XSS attacks:
<!-- Good -->
<h1><?= htmlspecialchars($metadata['title']) ?></h1>
<p><?= htmlspecialchars($item['summary']) ?></p>
<!-- Bad -->
<h1><?= $metadata['title'] ?></h1>
<p><?= $item['summary'] ?></p>
Exception: Already-sanitized HTML like $content (rendered from Markdown):
<!-- Good (content is already HTML) -->
<div class="content">
<?= $content ?>
</div>
Checking Variable Existence
Always check if optional variables exist:
<!-- Good -->
<?php if (isset($metadata['author'])): ?>
<p>By <?= htmlspecialchars($metadata['author']) ?></p>
<?php endif; ?>
<!-- Bad (may cause warnings) -->
<p>By <?= htmlspecialchars($metadata['author']) ?></p>
Use null coalescing for defaults:
<p><?= htmlspecialchars($metadata['author'] ?? 'Anonymous') ?></p>
Debugging Variables
To see all available variables in a template:
<pre><?php var_dump(get_defined_vars()); ?></pre>
Or specific variables:
<pre><?php print_r($metadata); ?></pre>
<pre><?php print_r($items); ?></pre>
Remember to remove debug code before deploying to production.
What's Next?
- Internationalization — Use language-specific variables
- Creating Plugins — Add custom template variables
- Template Tutorial — See variables in action