Add language prefix parameter to cache functions Update renderContentFile to handle language prefixes Add language prefix to internal links in markdown Make template variables available to PHP content files
185 lines
6.1 KiB
PHP
185 lines
6.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 = '<article>' . (new ParsedownExtra())->text(file_get_contents($filePath)) . '</article>';
|
|
|
|
// Add language prefix to internal links
|
|
if ($langPrefix) {
|
|
$html = preg_replace(
|
|
'/href="(\/[^"]*)"/',
|
|
'href="' . $langPrefix . '$1"',
|
|
$html
|
|
);
|
|
}
|
|
|
|
setCachedMarkdown($filePath, $html, $langPrefix);
|
|
echo $html;
|
|
}
|
|
} elseif (in_array($ext, ['html', 'php'])) {
|
|
// Make template variables available to PHP content files
|
|
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;
|
|
|
|
// Get basic template vars
|
|
$navigation = $ctx->navigation;
|
|
$homeLabel = $ctx->homeLabel;
|
|
$pageTitle = null;
|
|
|
|
// Let plugins add template variables
|
|
$templateVars = Hooks::apply(Hook::TEMPLATE_VARS, [
|
|
'content' => $content,
|
|
'navigation' => $navigation,
|
|
'homeLabel' => $homeLabel,
|
|
'pageTitle' => $pageTitle
|
|
], $ctx);
|
|
|
|
extract($templateVars);
|
|
|
|
http_response_code($statusCode);
|
|
include $ctx->templates->base;
|
|
exit;
|
|
}
|
|
|
|
function renderFile(Context $ctx, string $filePath): void {
|
|
$realPath = realpath($filePath);
|
|
if (!$realPath || !str_starts_with($realPath, $ctx->contentDir) || !is_readable($realPath)) {
|
|
renderTemplate($ctx, "<article><h1>403 Forbidden</h1><p>Access denied.</p></article>", 403);
|
|
}
|
|
|
|
$ext = pathinfo($realPath, PATHINFO_EXTENSION);
|
|
|
|
if (in_array($ext, CONTENT_EXTENSIONS)) {
|
|
$content = renderContentFile($realPath, $ctx);
|
|
|
|
$pageDir = dirname($realPath);
|
|
$pageMetadata = loadMetadata($pageDir);
|
|
|
|
// Load page-level plugins
|
|
getPluginManager()->loadPagePlugins($pageMetadata);
|
|
|
|
$navigation = $ctx->navigation;
|
|
$homeLabel = $ctx->homeLabel;
|
|
$pageTitle = $pageMetadata['title'] ?? null;
|
|
$metaDescription = extractMetaDescription($pageDir, $pageMetadata);
|
|
|
|
// Check for page-specific CSS
|
|
$pageCss = findPageCss($pageDir, $ctx->contentDir);
|
|
$pageCssUrl = $pageCss['url'] ?? null;
|
|
$pageCssHash = $pageCss['hash'] ?? null;
|
|
|
|
// Check for cover image for social media
|
|
$coverImage = findCoverImage($pageDir);
|
|
$socialImageUrl = null;
|
|
if ($coverImage) {
|
|
$relativePath = str_replace($ctx->contentDir, '', $pageDir);
|
|
$relativePath = trim($relativePath, '/');
|
|
$socialImageUrl = '/' . ($relativePath ? $relativePath . '/' : '') . $coverImage;
|
|
}
|
|
|
|
// Let plugins add template variables
|
|
$templateVars = Hooks::apply(Hook::TEMPLATE_VARS, [
|
|
'content' => $content,
|
|
'navigation' => $navigation,
|
|
'homeLabel' => $homeLabel,
|
|
'pageTitle' => $pageTitle,
|
|
'metaDescription' => $metaDescription,
|
|
'pageCssUrl' => $pageCssUrl,
|
|
'pageCssHash' => $pageCssHash,
|
|
'socialImageUrl' => $socialImageUrl
|
|
], $ctx);
|
|
|
|
extract($templateVars);
|
|
|
|
// Wrap content with page template
|
|
ob_start();
|
|
require $ctx->templates->page;
|
|
$wrappedContent = ob_get_clean();
|
|
|
|
include $ctx->templates->base;
|
|
exit;
|
|
}
|
|
|
|
// Unknown type - 404
|
|
renderTemplate($ctx, "<article><h1>404 - Not Found</h1><p>The requested file could not be found.</p></article>", 404);
|
|
}
|
|
|
|
function renderMultipleFiles(Context $ctx, array $files, string $pageDir): void {
|
|
$content = '';
|
|
foreach ($files as $file) {
|
|
$content .= renderContentFile($file, $ctx);
|
|
}
|
|
|
|
$pageMetadata = loadMetadata($pageDir);
|
|
|
|
// Load page-level plugins
|
|
getPluginManager()->loadPagePlugins($pageMetadata);
|
|
|
|
$navigation = $ctx->navigation;
|
|
$homeLabel = $ctx->homeLabel;
|
|
$pageTitle = $pageMetadata['title'] ?? null;
|
|
$metaDescription = extractMetaDescription($pageDir, $pageMetadata);
|
|
|
|
// Check for page-specific CSS
|
|
$pageCss = findPageCss($pageDir, $ctx->contentDir);
|
|
$pageCssUrl = $pageCss['url'] ?? null;
|
|
$pageCssHash = $pageCss['hash'] ?? null;
|
|
|
|
// Check for cover image
|
|
$coverImage = findCoverImage($pageDir);
|
|
$socialImageUrl = null;
|
|
if ($coverImage) {
|
|
$relativePath = str_replace($ctx->contentDir, '', $pageDir);
|
|
$relativePath = trim($relativePath, '/');
|
|
$socialImageUrl = '/' . ($relativePath ? $relativePath . '/' : '') . $coverImage;
|
|
}
|
|
|
|
// Let plugins add template variables
|
|
$templateVars = Hooks::apply(Hook::TEMPLATE_VARS, [
|
|
'content' => $content,
|
|
'navigation' => $navigation,
|
|
'homeLabel' => $homeLabel,
|
|
'pageTitle' => $pageTitle,
|
|
'metaDescription' => $metaDescription,
|
|
'pageCssUrl' => $pageCssUrl,
|
|
'pageCssHash' => $pageCssHash,
|
|
'socialImageUrl' => $socialImageUrl
|
|
], $ctx);
|
|
|
|
extract($templateVars);
|
|
|
|
// Wrap content with page template
|
|
ob_start();
|
|
require $ctx->templates->page;
|
|
$wrappedContent = ob_get_clean();
|
|
|
|
include $ctx->templates->base;
|
|
exit;
|
|
}
|