innhold/docs/templates.md
Ruben a142b0562f Add documentation for content system, newsletter plugin, petition
system, and templates

Add content system documentation

Add newsletter plugin documentation

Add petition system documentation

Add templates documentation
2026-02-06 19:15:29 +01:00

4.6 KiB

Templates Reference

For LLM agents working on this site's templates. Read when modifying any template file.

Template Hierarchy

Content renders inside-out: content file -> page/list template -> base.php

content file (md/html/php) -> rendered as $content
  -> page.php or list-*.php (wraps content)
    -> base.php (HTML document shell)

File Locations

All in custom/templates/. These override app/default/templates/.

Template Purpose Used When
base.php HTML document wrapper (head, nav, footer) Always
page.php Single page/article Directory has no subdirectories (or hide_list=true)
list.php Default list layout Directory has subdirectories (default)
list-card-grid.php Card grid layout page_template = list-card-grid in metadata
list-faq.php FAQ accordion layout page_template = list-faq in metadata
list-grid.php Brochure grid layout page_template = list-grid in metadata

Template Selection

List template is chosen by page_template field in the directory's metadata.ini:

page_template = list-faq

If not set, defaults to list.php.

Variables Available in All Templates

These are extracted via extract() so they're direct PHP variables:

Variable Type Description
$content string Pre-rendered HTML content (in base.php)
$pageTitle ?string Page title from metadata
$metaDescription ?string Meta description
$socialImageUrl ?string Social media image URL
$navigation array Menu items [['title'=>..., 'url'=>...], ...]
$homeLabel string Home link text
$currentLang string Current language code (no or en)
$langPrefix string URL language prefix (empty for default, /en for English)
$languageUrls array ['no'=>'/path/', 'en'=>'/en/path/']
$translations array Translation strings from language .ini files
$availableLangs array ['no', 'en']
$pageCssUrl ?string Page-specific CSS URL
$pageCssHash ?string CSS cache-bust hash
$pageJsUrl ?string Page-specific JS URL
$pageJsHash ?string JS cache-bust hash
$feedUrl ?string Atom feed URL (only on list pages with feed=true)

Additional Variables in page.php

Variable Type Description
$content string Rendered page content HTML
$pageMetadata array Full metadata array from metadata.ini

Additional Variables in list-*.php Templates

Variable Type Description
$pageContent ?string Rendered intro content from list directory's own content files
$items array List items (see schema below)
$metadata array List directory's metadata

List Item Schema

Each item in $items:

[
    'title'    => string,   // Item title
    'url'      => string,   // Relative URL with lang prefix
    'date'     => string,   // Formatted date (localized)
    'rawDate'  => string,   // ISO date (YYYY-MM-DD)
    'summary'  => ?string,  // Summary text
    'cover'    => ?string,  // Cover image URL
    'pdf'      => ?string,  // PDF file URL
    'redirect' => ?string,  // External redirect URL
    'dirPath'  => string,   // Filesystem path to item directory
]

base.php Key Sections

  1. Head: Meta tags, social OG tags, Twitter cards, stylesheets, feed link, favicon
  2. Header: Logo, navigation menu, language switcher
  3. Main: $content (wrapped content from inner template)
  4. Footer: Social links, page generation time, language links, GoatCounter analytics
<?php if (!empty($feedUrl)): ?>
<link rel="alternate" type="application/atom+xml" title="<?= htmlspecialchars($pageTitle ?? 'Feed') ?>" href="<?= htmlspecialchars($feedUrl) ?>">
<?php endif; ?>

This MUST remain in base.php. It enables feed discovery for any section with feed = true in metadata.

Critical: GoatCounter Analytics

<img style="display:none" src="https://stopplidelsen.goatcounter.com/count?p=<?= htmlspecialchars($_SERVER['REQUEST_URI']) ?>">

This is the analytics tracker. Do not remove or modify the URL.

Conventions

  • Escape all user-generated content: <?= htmlspecialchars($var) ?>
  • Pre-rendered HTML (from markdown) is safe: <?= $content ?>
  • Use $translations['key'] for i18n strings
  • Use $langPrefix before all internal URLs
  • Use CSS <style> blocks at the bottom of list templates for template-specific styles
  • Use CSS nesting inside scoped selectors (e.g., main > section { ... })
  • Use clamp() for responsive sizing, avoid @media queries