475 lines
10 KiB
Markdown
475 lines
10 KiB
Markdown
|
|
# 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:**
|
||
|
|
```php
|
||
|
|
<main>
|
||
|
|
<?= $content ?>
|
||
|
|
</main>
|
||
|
|
```
|
||
|
|
|
||
|
|
### `$pageTitle`
|
||
|
|
|
||
|
|
The page title for the `<title>` tag.
|
||
|
|
|
||
|
|
**Type:** String
|
||
|
|
**Default:** `"FolderWeb"`
|
||
|
|
**Example:**
|
||
|
|
```php
|
||
|
|
<title><?= htmlspecialchars($pageTitle ?? 'FolderWeb') ?></title>
|
||
|
|
```
|
||
|
|
|
||
|
|
**Source:**
|
||
|
|
1. Language-specific metadata `[lang] title`
|
||
|
|
2. Root metadata `title`
|
||
|
|
3. First heading in content
|
||
|
|
4. Folder name
|
||
|
|
|
||
|
|
### `$metaDescription`
|
||
|
|
|
||
|
|
SEO description for the `<meta name="description">` tag.
|
||
|
|
|
||
|
|
**Type:** String
|
||
|
|
**Optional:** May be empty
|
||
|
|
**Example:**
|
||
|
|
```php
|
||
|
|
<?php if (!empty($metaDescription)): ?>
|
||
|
|
<meta name="description" content="<?= htmlspecialchars($metaDescription) ?>">
|
||
|
|
<?php endif; ?>
|
||
|
|
```
|
||
|
|
|
||
|
|
**Source:**
|
||
|
|
1. Metadata `search_description`
|
||
|
|
2. Metadata `summary`
|
||
|
|
3. Empty if not set
|
||
|
|
|
||
|
|
### `$socialImageUrl`
|
||
|
|
|
||
|
|
URL to cover image for social media meta tags.
|
||
|
|
|
||
|
|
**Type:** String (URL)
|
||
|
|
**Optional:** May be empty
|
||
|
|
**Example:**
|
||
|
|
```php
|
||
|
|
<?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:**
|
||
|
|
```php
|
||
|
|
[
|
||
|
|
['url' => '/about/', 'title' => 'About'],
|
||
|
|
['url' => '/blog/', 'title' => 'Blog'],
|
||
|
|
['url' => '/contact/', 'title' => 'Contact'],
|
||
|
|
]
|
||
|
|
```
|
||
|
|
|
||
|
|
**Example:**
|
||
|
|
```php
|
||
|
|
<?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:**
|
||
|
|
```php
|
||
|
|
<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:**
|
||
|
|
```php
|
||
|
|
<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:**
|
||
|
|
```php
|
||
|
|
<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:**
|
||
|
|
```php
|
||
|
|
[
|
||
|
|
'en' => '/page/',
|
||
|
|
'no' => '/no/side/',
|
||
|
|
'de' => '/de/seite/',
|
||
|
|
]
|
||
|
|
```
|
||
|
|
|
||
|
|
**Example:**
|
||
|
|
```php
|
||
|
|
<?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:**
|
||
|
|
```php
|
||
|
|
[
|
||
|
|
'home' => 'Home',
|
||
|
|
'footer_handcoded' => 'Generated in',
|
||
|
|
'footer_page_time' => 'ms',
|
||
|
|
'months' => 'January,February,March,...',
|
||
|
|
]
|
||
|
|
```
|
||
|
|
|
||
|
|
**Example:**
|
||
|
|
```php
|
||
|
|
<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
|
||
|
|
<?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
|
||
|
|
|
||
|
|
## Page Template Variables
|
||
|
|
|
||
|
|
Available in `page.php`:
|
||
|
|
|
||
|
|
### `$content`
|
||
|
|
|
||
|
|
The fully rendered HTML content from the page.
|
||
|
|
|
||
|
|
**Type:** String (HTML)
|
||
|
|
**Example:**
|
||
|
|
```php
|
||
|
|
<article>
|
||
|
|
<?= $content ?>
|
||
|
|
</article>
|
||
|
|
```
|
||
|
|
|
||
|
|
### `$metadata`
|
||
|
|
|
||
|
|
All metadata for the current page.
|
||
|
|
|
||
|
|
**Type:** Associative array
|
||
|
|
**Structure:**
|
||
|
|
```php
|
||
|
|
[
|
||
|
|
'title' => 'Page Title',
|
||
|
|
'summary' => 'Short description',
|
||
|
|
'date' => '2024-12-15',
|
||
|
|
'formatted_date' => '15. desember 2024',
|
||
|
|
'show_date' => true,
|
||
|
|
'author' => 'Jane Doe', // Custom fields
|
||
|
|
'tags' => 'web,design',
|
||
|
|
// ... all other metadata fields
|
||
|
|
]
|
||
|
|
```
|
||
|
|
|
||
|
|
**Example:**
|
||
|
|
```php
|
||
|
|
<?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['formatted_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
|
||
|
|
<?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:**
|
||
|
|
```php
|
||
|
|
[
|
||
|
|
[
|
||
|
|
'url' => '/blog/my-post/',
|
||
|
|
'path' => '/content/blog/2024-12-15-my-post',
|
||
|
|
'title' => 'My Post',
|
||
|
|
'summary' => 'Short description',
|
||
|
|
'date' => '2024-12-15',
|
||
|
|
'formatted_date' => '15. desember 2024',
|
||
|
|
'cover_image' => '/blog/my-post/cover.jpg',
|
||
|
|
// All custom metadata fields...
|
||
|
|
'author' => 'Jane Doe',
|
||
|
|
'category' => 'Tutorial',
|
||
|
|
],
|
||
|
|
// ... more items
|
||
|
|
]
|
||
|
|
```
|
||
|
|
|
||
|
|
**Example:**
|
||
|
|
```php
|
||
|
|
<?php foreach ($items as $item): ?>
|
||
|
|
<article>
|
||
|
|
<?php if (isset($item['cover_image'])): ?>
|
||
|
|
<img src="<?= $item['cover_image'] ?>"
|
||
|
|
alt="<?= htmlspecialchars($item['title']) ?>">
|
||
|
|
<?php endif; ?>
|
||
|
|
|
||
|
|
<h2>
|
||
|
|
<a href="<?= $item['url'] ?>">
|
||
|
|
<?= htmlspecialchars($item['title']) ?>
|
||
|
|
</a>
|
||
|
|
</h2>
|
||
|
|
|
||
|
|
<?php if (isset($item['date'])): ?>
|
||
|
|
<time datetime="<?= $item['date'] ?>">
|
||
|
|
<?= $item['formatted_date'] ?? $item['date'] ?>
|
||
|
|
</time>
|
||
|
|
<?php endif; ?>
|
||
|
|
|
||
|
|
<?php if (isset($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
|
||
|
|
<?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 |
|
||
|
|
|----------|------|-------------|----------|
|
||
|
|
| `url` | String | Full URL to the item | No |
|
||
|
|
| `path` | String | Filesystem path to item | No |
|
||
|
|
| `title` | String | Item title | No |
|
||
|
|
| `summary` | String | Short description | Yes |
|
||
|
|
| `date` | String | ISO date (YYYY-MM-DD) | Yes |
|
||
|
|
| `formatted_date` | String | Localized date string | Yes |
|
||
|
|
| `cover_image` | String | URL to cover image | Yes |
|
||
|
|
| Custom fields | Mixed | Any metadata fields | Yes |
|
||
|
|
|
||
|
|
## Adding Custom Variables
|
||
|
|
|
||
|
|
Use the `Hook::TEMPLATE_VARS` hook to add custom variables:
|
||
|
|
|
||
|
|
```php
|
||
|
|
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:
|
||
|
|
|
||
|
|
```php
|
||
|
|
<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` | ✓ | — | — |
|
||
|
|
| `$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:
|
||
|
|
|
||
|
|
```php
|
||
|
|
<!-- 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):
|
||
|
|
|
||
|
|
```php
|
||
|
|
<!-- Good (content is already HTML) -->
|
||
|
|
<div class="content">
|
||
|
|
<?= $content ?>
|
||
|
|
</div>
|
||
|
|
```
|
||
|
|
|
||
|
|
## Checking Variable Existence
|
||
|
|
|
||
|
|
Always check if optional variables exist:
|
||
|
|
|
||
|
|
```php
|
||
|
|
<!-- 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:
|
||
|
|
|
||
|
|
```php
|
||
|
|
<p><?= htmlspecialchars($metadata['author'] ?? 'Anonymous') ?></p>
|
||
|
|
```
|
||
|
|
|
||
|
|
## Debugging Variables
|
||
|
|
|
||
|
|
To see all available variables in a template:
|
||
|
|
|
||
|
|
```php
|
||
|
|
<pre><?php var_dump(get_defined_vars()); ?></pre>
|
||
|
|
```
|
||
|
|
|
||
|
|
Or specific variables:
|
||
|
|
|
||
|
|
```php
|
||
|
|
<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
|