folderweb/app/rendering.php
Ruben f8a352afce Add JavaScript support to page templates
Add support for page-specific JavaScript files with cache busting
via MD5 hash. The script is loaded at the end of the body with
defer attribute. The JavaScript file must be named script.js and
located in the same directory as the page content.
2026-02-06 18:47:17 +01:00

126 lines
4.1 KiB
PHP

<?php
function renderContentFile(string $filePath, ?Context $ctx = null): string {
$ext = pathinfo($filePath, PATHINFO_EXTENSION);
ob_start();
if ($ext === 'md') {
require_once __DIR__ . '/cache.php';
$langPrefix = $ctx ? $ctx->get('langPrefix', '') : '';
$cached = getCachedMarkdown($filePath, $langPrefix);
if ($cached !== null) {
echo $cached;
} else {
// Update to newer versions before PHP 9.0 release
// Current versions have been patched for PHP 8.4+ compatibility
if (!class_exists('Parsedown')) {
require_once __DIR__ . '/vendor/Parsedown.php';
}
if (!class_exists('ParsedownExtra')) {
require_once __DIR__ . '/vendor/ParsedownExtra.php';
}
$html = (new ParsedownExtra())->text(file_get_contents($filePath));
if ($langPrefix) {
$html = preg_replace(
'/href="(\/[^"]*)"/',
'href="' . $langPrefix . '$1"',
$html
);
}
setCachedMarkdown($filePath, $html, $langPrefix);
echo $html;
}
} elseif (in_array($ext, ['html', 'php'])) {
if ($ctx !== null && $ext === 'php') {
$templateVars = Hooks::apply(Hook::TEMPLATE_VARS, [], $ctx);
extract($templateVars);
}
include $filePath;
}
return ob_get_clean();
}
function renderTemplate(Context $ctx, string $content, int $statusCode = 200): void {
global $GLOBALS;
$navigation = $ctx->navigation;
$homeLabel = $ctx->homeLabel;
$templateVars = Hooks::apply(Hook::TEMPLATE_VARS, [
'content' => $content,
'navigation' => $navigation,
'homeLabel' => $homeLabel,
'pageTitle' => $ctx->get('pageTitle'),
'metaDescription' => $ctx->get('metaDescription'),
'pageCssUrl' => $ctx->get('pageCssUrl'),
'pageCssHash' => $ctx->get('pageCssHash'),
'pageJsUrl' => $ctx->get('pageJsUrl'),
'pageJsHash' => $ctx->get('pageJsHash'),
'feedUrl' => $ctx->get('feedUrl')
], $ctx);
extract($templateVars);
http_response_code($statusCode);
include $ctx->templates->base;
exit;
}
function renderMultipleFiles(Context $ctx, array $files, string $pageDir): void {
// Load metadata and page plugins BEFORE rendering content files
// so that plugin-provided template variables are available to PHP content files
$pageMetadata = loadMetadata($pageDir);
getPluginManager()->loadPagePlugins($pageMetadata);
$content = '';
foreach ($files as $file) {
$content .= renderContentFile($file, $ctx);
}
$navigation = $ctx->navigation;
$homeLabel = $ctx->homeLabel;
$pageTitle = $pageMetadata['title'] ?? null;
$metaDescription = extractMetaDescription($pageDir, $pageMetadata);
$pageCss = findPageCss($pageDir, $ctx->contentDir);
$pageCssUrl = $pageCss['url'] ?? null;
$pageCssHash = $pageCss['hash'] ?? null;
$pageJs = findPageJs($pageDir, $ctx->contentDir);
$pageJsUrl = $pageJs['url'] ?? null;
$pageJsHash = $pageJs['hash'] ?? null;
$coverImage = findCoverImage($pageDir);
$socialImageUrl = null;
if ($coverImage) {
$relativePath = str_replace($ctx->contentDir, '', $pageDir);
$relativePath = trim($relativePath, '/');
$socialImageUrl = '/' . ($relativePath ? $relativePath . '/' : '') . $coverImage;
}
$templateVars = Hooks::apply(Hook::TEMPLATE_VARS, [
'content' => $content,
'navigation' => $navigation,
'homeLabel' => $homeLabel,
'pageTitle' => $pageTitle,
'metaDescription' => $metaDescription,
'pageCssUrl' => $pageCssUrl,
'pageCssHash' => $pageCssHash,
'pageJsUrl' => $pageJsUrl,
'pageJsHash' => $pageJsHash,
'socialImageUrl' => $socialImageUrl
], $ctx);
extract($templateVars);
ob_start();
require $ctx->templates->page;
$wrappedContent = ob_get_clean();
include $ctx->templates->base;
exit;
}