folderweb/docs/how-to/custom-templates.md
2025-11-02 13:46:47 +01:00

7.1 KiB

How to Create Custom Templates

This guide shows you how to override default templates with your own custom designs.

Overview

FolderWeb uses a template fallback system:

  1. Check /custom/templates/ for custom version
  2. Fall back to /app/default/templates/ if not found

Important: Never modify files in /app/default/ — always create custom versions in /custom/.

Available Templates

  • base.php - HTML wrapper (header, navigation, footer)
  • page.php - Single page/article wrapper
  • list.php - Simple list view (default)
  • list-grid.php - Grid layout with images
  • list-card-grid.php - Card grid (supports PDFs, external links)
  • list-faq.php - Expandable FAQ/Q&A format

Customizing the Base Template

The base template controls your entire site layout.

Step 1: Copy the Default

mkdir -p custom/templates
cp app/default/templates/base.php custom/templates/base.php

Step 2: Edit Your Copy

The base template has access to these variables:

$content          // The rendered page content (HTML)
$currentLang      // Current language code (e.g., "en", "no")
$navigation       // Array of navigation items
$homeLabel        // Site title
$translations     // Translation strings
$pageTitle        // Current page title
$dirName          // Parent directory name (for CSS classes)
$pageName         // Current page name (for CSS classes)

Example: Add a Custom Header

<header class="site-header">
    <div class="contain">
        <a href="<?= $ctx->langPrefix ?>/" class="logo">
            <img src="/custom/assets/logo.svg" alt="<?= $homeLabel ?>">
        </a>
        <nav>
            <ul>
                <?php foreach ($navigation as $item): ?>
                    <li>
                        <a href="<?= $item['url'] ?>"><?= htmlspecialchars($item['title']) ?></a>
                    </li>
                <?php endforeach; ?>
            </ul>
        </nav>
    </div>
</header>

Customizing the Page Template

The page template wraps individual articles and pages.

Step 1: Copy the Default

cp app/default/templates/page.php custom/templates/page.php

Step 2: Customize

Available variables:

$content          // Main content HTML
$pageMetadata     // Array of metadata (tags, categories, etc.)
$translations     // Translation strings

Example: Add Author Information

<article>
    <?php if (isset($pageMetadata['author'])): ?>
        <div class="author-info">
            <p>Written by <?= htmlspecialchars($pageMetadata['author']) ?></p>
        </div>
    <?php endif; ?>
    
    <?= $content ?>
    
    <?php if (isset($pageMetadata['tags'])): ?>
        <div class="tags">
            <strong><?= $translations['tags'] ?>:</strong>
            <?php foreach ($pageMetadata['tags'] as $tag): ?>
                <span class="tag"><?= htmlspecialchars($tag) ?></span>
            <?php endforeach; ?>
        </div>
    <?php endif; ?>
</article>

Creating a Custom List Template

List templates control how directories with subdirectories are displayed.

Step 1: Create Your Template

touch custom/templates/list-custom.php

Step 2: Use List Template Variables

All list templates receive:

$items            // Array of subdirectories
$metadata         // Directory metadata
$pageContent      // Optional intro content
$translations     // Translation strings

Each item in $items has:

[
    'title' => 'Post Title',
    'date' => '2. november 2025',
    'url' => '/blog/2025-11-02-post/',
    'cover' => '/blog/2025-11-02-post/cover.jpg',
    'summary' => 'Brief description',
    'pdf' => '/blog/2025-11-02-post/document.pdf',
    'redirect' => 'https://external-site.com'
]

Example: Timeline Template

<?php if (!empty($pageContent)): ?>
    <div class="page-intro">
        <?= $pageContent ?>
    </div>
<?php endif; ?>

<div class="timeline">
    <?php foreach ($items as $item): ?>
        <article class="timeline-item">
            <time><?= $item['date'] ?></time>
            <h2>
                <a href="<?= $item['url'] ?>"><?= htmlspecialchars($item['title']) ?></a>
            </h2>
            <?php if ($item['summary']): ?>
                <p><?= htmlspecialchars($item['summary']) ?></p>
            <?php endif; ?>
        </article>
    <?php endforeach; ?>
</div>

Step 3: Apply Your Template

Create a metadata.ini in the directory:

page_template = "list-custom"

Template Best Practices

Always Escape Output

Prevent XSS attacks by escaping user-generated content:

<?= htmlspecialchars($item['title']) ?>

Use Short Echo Tags

FolderWeb uses modern PHP, so short tags are always available:

<?= $variable ?>  // Good
<?php echo $variable; ?>  // Also works, but verbose

Check Before Using

Always check if variables exist:

<?php if (isset($item['cover']) && $item['cover']): ?>
    <img src="<?= $item['cover'] ?>" alt="">
<?php endif; ?>

Leverage CSS Classes

The base template adds dynamic classes to <body>:

<body class="section-<?= $dirName ?> page-<?= $pageName ?>">

Use these for page-specific styling without JavaScript.

Advanced: Accessing the Context Object

Templates can access the full context object $ctx:

<?php
// Available properties:
$ctx->contentDir       // Path to content directory
$ctx->currentLang      // Current language
$ctx->defaultLang      // Default language
$ctx->availableLangs   // Array of available languages
$ctx->langPrefix       // URL prefix (e.g., "/en" or "")
$ctx->requestPath      // Current request path
$ctx->hasTrailingSlash // Boolean
$ctx->navigation       // Navigation array (computed property)
$ctx->homeLabel        // Site title (computed property)
$ctx->translations     // Translation array (computed property)
?>

Example: Breadcrumb Navigation

Add breadcrumbs to your page template:

<nav class="breadcrumbs" aria-label="Breadcrumb">
    <ol>
        <li><a href="<?= $ctx->langPrefix ?>/">Home</a></li>
        <?php
        $parts = array_filter(explode('/', trim($ctx->requestPath, '/')));
        $path = '';
        foreach ($parts as $i => $part):
            $path .= '/' . $part;
            $isLast = ($i === count($parts) - 1);
        ?>
            <li<?= $isLast ? ' aria-current="page"' : '' ?>>
                <?php if ($isLast): ?>
                    <?= htmlspecialchars($part) ?>
                <?php else: ?>
                    <a href="<?= $ctx->langPrefix . $path ?>/">
                        <?= htmlspecialchars($part) ?>
                    </a>
                <?php endif; ?>
            </li>
        <?php endforeach; ?>
    </ol>
</nav>

Testing Your Templates

  1. Clear your browser cache
  2. Reload the page
  3. Check browser console for errors
  4. Validate HTML with W3C validator

Reverting Changes

To revert to default templates, simply delete your custom version:

rm custom/templates/base.php

FolderWeb will automatically fall back to the default.