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
117 lines
5.6 KiB
Markdown
117 lines
5.6 KiB
Markdown
# Rendering & Caching
|
|
|
|
## Content Rendering
|
|
|
|
**`renderContentFile(string $filePath, ?Context $ctx = null): string`**
|
|
|
|
Renders a single content file to HTML string based on extension:
|
|
|
|
| Extension | Rendering |
|
|
|---|---|
|
|
| `md` | Parsedown + ParsedownExtra → HTML. Cached. Language prefix injected into internal links. |
|
|
| `html` | Included directly (output buffered) |
|
|
| `php` | Included with `Hook::TEMPLATE_VARS` variables extracted into scope |
|
|
|
|
PHP content files receive variables from `Hook::TEMPLATE_VARS` (starting with an empty array). This includes plugin-provided variables like `$translations`, `$currentLang`, etc. However, page-level context like `$metadata` and `$pageTitle` is **not** included — those are only available in the wrapping template (page.php/list.php), not in content files.
|
|
|
|
## Page Rendering
|
|
|
|
**`renderMultipleFiles(Context $ctx, array $files, string $pageDir): void`**
|
|
|
|
Used for both frontpage and page views:
|
|
|
|
1. Load metadata for `$pageDir`
|
|
2. Load page plugins (from metadata `plugins` field)
|
|
3. Render all content files, concatenate HTML
|
|
4. Compute: `$pageTitle`, `$metaDescription`, `$pageCssUrl`/`$pageCssHash`, `$socialImageUrl`
|
|
5. Fire `Hook::TEMPLATE_VARS` with all variables
|
|
6. `extract()` variables → render `page.php` → capture output as `$content`
|
|
7. Render `base.php` with `$content` + base variables
|
|
8. `exit`
|
|
|
|
## List Rendering
|
|
|
|
Handled directly in `router.php` (not a separate function):
|
|
|
|
1. Render directory's own content files as `$pageContent`
|
|
2. Load metadata, check `hide_list`
|
|
3. Select list template from `page_template` metadata
|
|
4. Call `buildListItems()` from `helpers.php` (builds + sorts items)
|
|
5. Store `pageTitle`, `metaDescription`, `pageCssUrl`, `pageCssHash`, `feedUrl` on context
|
|
6. Fire `Hook::TEMPLATE_VARS`
|
|
7. Render list template → capture as `$content`
|
|
8. Pass to `renderTemplate()` which renders `base.php`
|
|
|
|
**`renderTemplate(Context $ctx, string $content, int $statusCode = 200): void`** — Wraps content in base template. Used for list views and error pages. Reads `pageTitle`, `metaDescription`, `pageCssUrl`, `pageCssHash`, and `feedUrl` from the context object (set by the list case in `router.php`). For error pages, these context keys are unset, so base.php receives nulls.
|
|
|
|
## Atom Feed Rendering
|
|
|
|
Handled in `router.php` before `parseRequestPath()`. When a request path ends with `feed.xml`:
|
|
|
|
1. Strip `feed.xml` suffix, resolve parent as list directory via `parseRequestPath()`
|
|
2. Check `feed = true` in metadata — 404 if missing or if parent is not a list
|
|
3. Call `buildListItems()` to get items
|
|
4. For each item: call `findAllContentFiles()` + `renderContentFile()` to get full HTML content
|
|
5. Build Atom XML with absolute URLs (`$_SERVER['HTTP_HOST']` + scheme detection)
|
|
6. Output `Content-Type: application/atom+xml` and exit
|
|
|
|
Feed piggybacks on the existing Markdown cache — no separate feed cache needed. The `rawDate` field on items provides ISO dates for Atom `<updated>` elements. Content is wrapped in `<![CDATA[...]]>` with `]]>` safely escaped.
|
|
|
|
## Markdown Caching
|
|
|
|
Defined in `app/cache.php`. File-based cache in `/tmp/folderweb_cache/`.
|
|
|
|
**Cache key:** `md5($filePath . $mtime . $langPrefix)`
|
|
|
|
- Invalidates when file is modified (mtime changes)
|
|
- Invalidates per-language (different link rewriting)
|
|
- No explicit TTL — entries persist until temp directory cleanup
|
|
- **Does not track plugin state** — if a plugin modifies Markdown output (e.g., via PROCESS_CONTENT on files), changing plugin config won't bust the cache. Clear `/tmp/folderweb_cache/` manually after plugin changes that affect rendered Markdown.
|
|
|
|
```php
|
|
getCachedMarkdown(string $filePath, string $langPrefix = ''): ?string
|
|
setCachedMarkdown(string $filePath, string $html, string $langPrefix = ''): void
|
|
```
|
|
|
|
## Static File Serving
|
|
|
|
### Content Assets (router.php)
|
|
|
|
Before content routing, the router serves static files from content directory with an explicit MIME type allowlist:
|
|
|
|
`css`, `jpg`, `jpeg`, `png`, `gif`, `webp`, `svg`, `pdf`, `woff`, `woff2`, `ttf`, `otf`
|
|
|
|
Files not in this list are not served as static assets. Notably, `.js` files are excluded — JavaScript must be placed in `custom/assets/` to be served (at the document root URL), or linked from an external source.
|
|
|
|
### Custom Assets (router.php)
|
|
|
|
Files in `custom/assets/` are served at the document root URL. Example: `custom/assets/favicon.ico` → `/favicon.ico`. Uses `mime_content_type()` for MIME detection.
|
|
|
|
### Framework Assets (static.php)
|
|
|
|
`/app/*` requests are handled by `static.php` with directory traversal protection (`../` stripped):
|
|
|
|
| URL Path | Filesystem Path |
|
|
|---|---|
|
|
| `/app/styles/*` | `custom/styles/*` |
|
|
| `/app/fonts/*` | `custom/fonts/*` |
|
|
| `/app/assets/*` | `custom/assets/*` |
|
|
| `/app/default-styles/*` | `app/default/styles/*` |
|
|
|
|
MIME types resolved from extension map, falling back to `mime_content_type()`.
|
|
|
|
## CSS Cache Busting
|
|
|
|
Page-specific CSS gets an MD5 hash appended: `?v={hash}`. Computed by `findPageCss()`. The default theme's CSS is linked directly without hash (uses browser caching).
|
|
|
|
## Parsedown
|
|
|
|
Markdown rendering uses `Parsedown` + `ParsedownExtra` from `app/vendor/`. These are the only third-party dependencies. Loaded lazily on first Markdown render.
|
|
|
|
**Internal link rewriting:** After Markdown→HTML conversion, `href="/..."` links are prefixed with the current language prefix (e.g., `/no`). This ensures Markdown links work correctly in multilingual sites.
|
|
|
|
## Error Responses
|
|
|
|
- **403:** Invalid path (outside content directory or unreadable)
|
|
- **404:** Slug resolution failed or unknown route type
|
|
- Both render via `renderTemplate()` with appropriate status code
|