# Working with Templates Templates control how your content is presented. FolderWeb uses a simple PHP-based template system—no complex templating languages, just HTML with a sprinkle of PHP. ## Template Types FolderWeb has three template levels: ### 1. Base Template (`base.php`) The HTML scaffold wrapping every page: ``` Page Title
``` **You typically customize this once** to set up your site structure. ### 2. Page Template (`page.php`) Wraps single-page content: ```php
``` **Customize this** to control how individual pages look. ### 3. List Template (`list.php`, `list-grid.php`, `list-compact.php`) Displays multiple items from subdirectories: ```php

``` **Customize this** to control how lists of content (blogs, portfolios, etc.) appear. ## Template Location Templates live in your `custom/` directory: ``` custom/ └── templates/ ├── base.php # HTML scaffold ├── page.php # Single page wrapper ├── list.php # Default list layout ├── list-grid.php # Grid card layout └── list-compact.php # Compact list layout ``` **FolderWeb falls back** to `app/default/templates/` if a custom template doesn't exist. ## Customizing the Base Template Let's modify `base.php` to add your site name and custom navigation: **custom/templates/base.php:** ```php <?= htmlspecialchars($pageTitle) ?>
``` **Key points:** - Always escape user content: `htmlspecialchars($var)` - Use short echo tags: `` - Check if variables exist: `isset($var)` - The `$content` variable contains the rendered page/list content ## Customizing Page Templates The page template wraps your single-page content. Let's add a reading time estimate: **custom/templates/page.php:** ```php

min read

``` ## Customizing List Templates List templates display collections of content. Let's create a custom blog list: **custom/templates/list.php:** ```php
<?= htmlspecialchars($item['title']) ?>

Read more →
``` ## Choosing List Templates You can create multiple list templates and select them per directory: **Available by default:** - `list.php` — Simple vertical list - `list-grid.php` — Card grid layout - `list-compact.php` — Minimal compact list **Select in metadata.ini:** ```ini title = "Projects" [settings] page_template = "list-grid" ``` Now the `projects/` directory uses the grid layout. ## Creating Custom List Templates Let's create a timeline template for a blog: **custom/templates/list-timeline.php:** ```php

``` **Use in metadata.ini:** ```ini [settings] page_template = "list-timeline" ``` ## Available Template Variables Templates have access to these variables (see [Reference: Template Variables](#) for complete list): **Base template:** ```php $content // Rendered page/list HTML $pageTitle // Page title for tag $metaDescription // SEO description $navigation // Array of menu items $homeLabel // "Home" link text (translated) $currentLang // Current language code $languageUrls // Links to other language versions $translations // Translated UI strings $cssHash // Cache-busting hash for CSS $pageCssUrl // Page-specific CSS URL (if exists) $pageLoadTime // Page generation time ``` **Page template:** ```php $content // Rendered HTML $metadata // Metadata array (title, date, etc.) ``` **List template:** ```php $items // Array of items to display $pageContent // Optional intro content from page $metadata // Directory metadata // Each $item has: $item['url'] // Full URL to item $item['title'] // Item title $item['summary'] // Short description $item['date'] // ISO date (YYYY-MM-DD) $item['formatted_date'] // Localized date string $item['cover_image'] // Cover image URL (if exists) ``` ## Best Practices ### 1. Always Escape Output ```php <!-- Bad --> <h1><?= $title ?></h1> <!-- Good --> <h1><?= htmlspecialchars($title) ?></h1> ``` **Exception:** Already-sanitized HTML like `$content` (rendered from Markdown). ### 2. Check Variables Exist ```php <!-- Bad --> <p><?= $metadata['summary'] ?></p> <!-- Good --> <?php if (isset($metadata['summary'])): ?> <p><?= htmlspecialchars($metadata['summary']) ?></p> <?php endif; ?> ``` ### 3. Use Short Echo Tags ```php <!-- Verbose --> <?php echo htmlspecialchars($title); ?> <!-- Concise --> <?= htmlspecialchars($title) ?> ``` ### 4. Keep Logic Minimal Templates should display data, not process it. Complex logic belongs in plugins. ```php <!-- Bad: complex logic in template --> <?php $posts = array_filter($items, function($item) { return strtotime($item['date']) > strtotime('-30 days'); }); usort($posts, function($a, $b) { return strcmp($b['date'], $a['date']); }); ?> <!-- Good: prepare data in a plugin, display in template --> <?php foreach ($recentPosts as $post): ?> ... <?php endforeach; ?> ``` ### 5. Use Semantic HTML ```php <!-- Bad --> <div class="title">Title</div> <div class="content">Content</div> <!-- Good --> <article> <h1>Title</h1> <div class="content">Content</div> </article> ``` ## Practical Examples ### Simple Portfolio Page Template ```php <article class="portfolio-item"> <header> <?php if (isset($metadata['cover_image'])): ?> <img src="<?= $metadata['cover_image'] ?>" alt=""> <?php endif; ?> <h1><?= htmlspecialchars($metadata['title'] ?? 'Untitled') ?></h1> </header> <div class="content"> <?= $content ?> </div> <?php if (isset($metadata['project_url'])): ?> <footer> <a href="<?= htmlspecialchars($metadata['project_url']) ?>" class="button">View Project →</a> </footer> <?php endif; ?> </article> ``` ### Card Grid List Template ```php <?= $pageContent ?> <div class="card-grid"> <?php foreach ($items as $item): ?> <article class="card"> <?php if (isset($item['cover_image'])): ?> <img src="<?= $item['cover_image'] ?>" alt="" loading="lazy"> <?php endif; ?> <div class="card-content"> <h3> <a href="<?= $item['url'] ?>"> <?= htmlspecialchars($item['title']) ?> </a> </h3> <?php if (isset($item['summary'])): ?> <p><?= htmlspecialchars($item['summary']) ?></p> <?php endif; ?> </div> </article> <?php endforeach; ?> </div> ``` ## What's Next? You now know how to customize templates. Next, learn about: - **[Template Variables Reference](#)** — Complete list of available variables - **[Creating Plugins](#)** — Extend functionality and add custom data to templates - **[Internationalization](#)** — Build multilingual sites Or explore the examples in `app/default/content/examples/templates-demo/` to see templates in action.