Compare commits
2 commits
0e63ed1444
...
33943a907b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
33943a907b | ||
|
|
611bf75576 |
5 changed files with 27 additions and 12 deletions
|
|
@ -46,10 +46,7 @@ Hooks::add(Hook::PROCESS_CONTENT, function(mixed $data, string $dirOrType, strin
|
||||||
|
|
||||||
// Filter content files by language variant
|
// Filter content files by language variant
|
||||||
if (is_array($data) && !empty($data) && isset($data[0]['path'])) {
|
if (is_array($data) && !empty($data) && isset($data[0]['path'])) {
|
||||||
error_log("filterFilesByLanguage called with " . count($data) . " files, current lang: $currentLang");
|
return filterFilesByLanguage($data, $dirOrType, $ctx);
|
||||||
$filtered = filterFilesByLanguage($data, $dirOrType, $ctx);
|
|
||||||
error_log("Filtered to " . count($filtered) . " files");
|
|
||||||
return $filtered;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,8 @@ function renderTemplate(Context $ctx, string $content, int $statusCode = 200): v
|
||||||
'pageCssHash' => $ctx->get('pageCssHash'),
|
'pageCssHash' => $ctx->get('pageCssHash'),
|
||||||
'pageJsUrl' => $ctx->get('pageJsUrl'),
|
'pageJsUrl' => $ctx->get('pageJsUrl'),
|
||||||
'pageJsHash' => $ctx->get('pageJsHash'),
|
'pageJsHash' => $ctx->get('pageJsHash'),
|
||||||
'feedUrl' => $ctx->get('feedUrl')
|
'feedUrl' => $ctx->get('feedUrl'),
|
||||||
|
'socialImageUrl' => $ctx->get('socialImageUrl')
|
||||||
], $ctx);
|
], $ctx);
|
||||||
|
|
||||||
extract($templateVars);
|
extract($templateVars);
|
||||||
|
|
@ -73,8 +74,8 @@ function renderTemplate(Context $ctx, string $content, int $statusCode = 200): v
|
||||||
function renderMultipleFiles(Context $ctx, array $files, string $pageDir): void {
|
function renderMultipleFiles(Context $ctx, array $files, string $pageDir): void {
|
||||||
// Load metadata and page plugins BEFORE rendering content files
|
// Load metadata and page plugins BEFORE rendering content files
|
||||||
// so that plugin-provided template variables are available to PHP content files
|
// so that plugin-provided template variables are available to PHP content files
|
||||||
$pageMetadata = loadMetadata($pageDir);
|
$metadata = loadMetadata($pageDir);
|
||||||
getPluginManager()->loadPagePlugins($pageMetadata);
|
getPluginManager()->loadPagePlugins($metadata);
|
||||||
|
|
||||||
$content = '';
|
$content = '';
|
||||||
foreach ($files as $file) {
|
foreach ($files as $file) {
|
||||||
|
|
@ -83,8 +84,8 @@ function renderMultipleFiles(Context $ctx, array $files, string $pageDir): void
|
||||||
|
|
||||||
$navigation = $ctx->navigation;
|
$navigation = $ctx->navigation;
|
||||||
$homeLabel = $ctx->homeLabel;
|
$homeLabel = $ctx->homeLabel;
|
||||||
$pageTitle = $pageMetadata['title'] ?? null;
|
$pageTitle = $metadata['title'] ?? null;
|
||||||
$metaDescription = extractMetaDescription($pageDir, $pageMetadata);
|
$metaDescription = extractMetaDescription($pageDir, $metadata);
|
||||||
|
|
||||||
$pageCss = findPageCss($pageDir, $ctx->contentDir);
|
$pageCss = findPageCss($pageDir, $ctx->contentDir);
|
||||||
$pageCssUrl = $pageCss['url'] ?? null;
|
$pageCssUrl = $pageCss['url'] ?? null;
|
||||||
|
|
@ -112,7 +113,8 @@ function renderMultipleFiles(Context $ctx, array $files, string $pageDir): void
|
||||||
'pageCssHash' => $pageCssHash,
|
'pageCssHash' => $pageCssHash,
|
||||||
'pageJsUrl' => $pageJsUrl,
|
'pageJsUrl' => $pageJsUrl,
|
||||||
'pageJsHash' => $pageJsHash,
|
'pageJsHash' => $pageJsHash,
|
||||||
'socialImageUrl' => $socialImageUrl
|
'socialImageUrl' => $socialImageUrl,
|
||||||
|
'metadata' => $metadata
|
||||||
], $ctx);
|
], $ctx);
|
||||||
|
|
||||||
extract($templateVars);
|
extract($templateVars);
|
||||||
|
|
|
||||||
|
|
@ -249,6 +249,14 @@ switch ($parsedPath['type']) {
|
||||||
? $langPrefix . '/' . trim($ctx->requestPath, '/') . '/feed.xml'
|
? $langPrefix . '/' . trim($ctx->requestPath, '/') . '/feed.xml'
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
|
// Build social image URL from cover image if present
|
||||||
|
$coverImage = findCoverImage($dir);
|
||||||
|
$socialImageUrl = null;
|
||||||
|
if ($coverImage) {
|
||||||
|
$relativePath = trim(str_replace($ctx->contentDir, '', $dir), '/');
|
||||||
|
$socialImageUrl = '/' . ($relativePath ? $relativePath . '/' : '') . $coverImage;
|
||||||
|
}
|
||||||
|
|
||||||
// Store for base template (renderTemplate reads these from context)
|
// Store for base template (renderTemplate reads these from context)
|
||||||
$ctx->set('pageTitle', $pageTitle);
|
$ctx->set('pageTitle', $pageTitle);
|
||||||
$ctx->set('metaDescription', $metaDescription);
|
$ctx->set('metaDescription', $metaDescription);
|
||||||
|
|
@ -257,6 +265,7 @@ switch ($parsedPath['type']) {
|
||||||
$ctx->set('pageJsUrl', $pageJsUrl);
|
$ctx->set('pageJsUrl', $pageJsUrl);
|
||||||
$ctx->set('pageJsHash', $pageJsHash);
|
$ctx->set('pageJsHash', $pageJsHash);
|
||||||
$ctx->set('feedUrl', $feedUrl);
|
$ctx->set('feedUrl', $feedUrl);
|
||||||
|
$ctx->set('socialImageUrl', $socialImageUrl);
|
||||||
|
|
||||||
// Let plugins add template variables
|
// Let plugins add template variables
|
||||||
$templateVars = Hooks::apply(Hook::TEMPLATE_VARS, [
|
$templateVars = Hooks::apply(Hook::TEMPLATE_VARS, [
|
||||||
|
|
@ -270,7 +279,9 @@ switch ($parsedPath['type']) {
|
||||||
'pageJsHash' => $pageJsHash,
|
'pageJsHash' => $pageJsHash,
|
||||||
'items' => $items,
|
'items' => $items,
|
||||||
'pageContent' => $pageContent,
|
'pageContent' => $pageContent,
|
||||||
'feedUrl' => $feedUrl
|
'feedUrl' => $feedUrl,
|
||||||
|
'socialImageUrl' => $socialImageUrl,
|
||||||
|
'metadata' => $metadata
|
||||||
], $ctx);
|
], $ctx);
|
||||||
|
|
||||||
extract($templateVars);
|
extract($templateVars);
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,7 @@ Returns flat key-value array with a special `_raw` key containing the full parse
|
||||||
| `order` | string | `"descending"` | List sort direction (`ascending`\|`descending`) |
|
| `order` | string | `"descending"` | List sort direction (`ascending`\|`descending`) |
|
||||||
| `redirect` | string | — | External URL (list items can redirect) |
|
| `redirect` | string | — | External URL (list items can redirect) |
|
||||||
| `feed` | bool | `false` | Enable Atom feed on list pages (`feed.xml`) |
|
| `feed` | bool | `false` | Enable Atom feed on list pages (`feed.xml`) |
|
||||||
|
| `author` | string | title | Atom feed author name (falls back to page title) |
|
||||||
| `plugins` | string | — | Comma-separated page-level plugin names |
|
| `plugins` | string | — | Comma-separated page-level plugin names |
|
||||||
|
|
||||||
### Settings Section
|
### Settings Section
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,8 @@ Handled in `router.php` before `parseRequestPath()`. When a request path ends wi
|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
||||||
|
**Date deduplication:** Atom requires unique `<updated>` timestamps per entry. Items sharing the same date get seconds incremented (`T00:00:00Z`, `T00:00:01Z`, etc.) to ensure uniqueness while preserving sort order.
|
||||||
|
|
||||||
## Markdown Caching
|
## Markdown Caching
|
||||||
|
|
||||||
Defined in `app/cache.php`. File-based cache in `/tmp/folderweb_cache/`.
|
Defined in `app/cache.php`. File-based cache in `/tmp/folderweb_cache/`.
|
||||||
|
|
@ -87,7 +89,9 @@ Files not in this list are not served as static assets.
|
||||||
|
|
||||||
### Custom Assets (router.php)
|
### 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.
|
Files in `custom/assets/` are served at the document root URL. Example: `custom/assets/favicon.ico` → `/favicon.ico`. Uses an explicit MIME type map; falls back to `application/octet-stream`.
|
||||||
|
|
||||||
|
Cache-Control headers: `json` and `geojson` files get `max-age=60` (short TTL for data files); all other asset types get `max-age=31536000` (1 year, immutable).
|
||||||
|
|
||||||
### Framework Assets (static.php)
|
### Framework Assets (static.php)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue