Improve cache invalidation by including metadata.ini and config file mtimes in the cache key calculation. This ensures cache entries are invalidated when either the content file, its metadata, or global configuration changes.
119 lines
5.7 KiB
Markdown
119 lines
5.7 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`, `$pageJsUrl`/`$pageJsHash`, `$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`, `pageJsUrl`, `pageJsHash`, `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`, `pageJsUrl`, `pageJsHash`, 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 . $metaMtime . $configMtime . $langPrefix)`
|
|
|
|
- Invalidates when content file is modified (mtime changes)
|
|
- Invalidates when `metadata.ini` in the same directory is modified
|
|
- Invalidates when global config (`custom/config.ini` or `app/default/config.ini`) is modified
|
|
- 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 code 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`, `js`
|
|
|
|
Files not in this list are not served as static assets.
|
|
|
|
### 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 and JS Cache Busting
|
|
|
|
Page-specific CSS and JS get an MD5 hash appended: `?v={hash}`. Computed by `findPageCss()` and `findPageJs()` respectively. 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
|