Remove language-specific content handling

Refactor to use plugin system for language support

Remove hardcoded language features from core

Move language handling to plugin system

Improve content file discovery

Simplify context creation

Add plugin system documentation

Implement hook system for extensibility

Add template variable hook

Add context storage for plugins

Improve error handling

Refactor rendering logic

Improve list view sorting

Add support for custom list templates

Improve metadata handling

Add plugin system reference documentation
This commit is contained in:
Ruben 2025-11-25 20:19:12 +01:00
parent 24ee209e17
commit a205f2cbd7
8 changed files with 524 additions and 315 deletions

View file

@ -2,12 +2,12 @@
function renderContentFile(string $filePath): string {
$ext = pathinfo($filePath, PATHINFO_EXTENSION);
ob_start();
if ($ext === 'md') {
require_once __DIR__ . '/cache.php';
$cached = getCachedMarkdown($filePath);
if ($cached !== null) {
echo $cached;
} else {
@ -25,13 +25,23 @@ function renderContentFile(string $filePath): string {
}
function renderTemplate(Context $ctx, string $content, int $statusCode = 200): void {
// Extract all necessary variables for base template
$currentLang = $ctx->currentLang;
global $GLOBALS;
// Get basic template vars
$navigation = $ctx->navigation;
$homeLabel = $ctx->homeLabel;
$translations = $ctx->translations;
$pageTitle = null; // No specific page title for error pages
$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;
@ -48,26 +58,22 @@ function renderFile(Context $ctx, string $filePath): void {
if (in_array($ext, CONTENT_EXTENSIONS)) {
$content = renderContentFile($realPath);
// Prepare template variables using property hooks
$currentLang = $ctx->currentLang;
$navigation = $ctx->navigation;
$homeLabel = $ctx->homeLabel;
$translations = $ctx->translations;
$pageDir = dirname($realPath);
$pageMetadata = loadMetadata($pageDir, $ctx->currentLang, $ctx->defaultLang);
$pageMetadata = loadMetadata($pageDir);
// Load page-level plugins
getPluginManager()->loadPagePlugins($pageMetadata);
$navigation = $ctx->navigation;
$homeLabel = $ctx->homeLabel;
$pageTitle = $pageMetadata['title'] ?? null;
$metaDescription = extractMetaDescription($pageDir, $pageMetadata, $ctx->currentLang, $ctx->defaultLang);
$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;
@ -77,54 +83,55 @@ function renderFile(Context $ctx, string $filePath): void {
$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();
include $ctx->templates->page;
$content = ob_get_clean();
require $ctx->templates->page;
$wrappedContent = ob_get_clean();
// Wrap with base template
include $ctx->templates->base;
exit;
}
// Serve other file types directly
header('Content-Type: ' . (mime_content_type($realPath) ?: 'application/octet-stream'));
readfile($realPath);
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 $filePaths, string $pageDir): void {
// Validate all files are safe
foreach ($filePaths as $filePath) {
$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);
}
function renderMultipleFiles(Context $ctx, array $files, string $pageDir): void {
$content = '';
foreach ($files as $file) {
$content .= renderContentFile($file);
}
// Render all content files in order
$content = implode('', array_map('renderContentFile', $filePaths));
// Prepare template variables using property hooks
$currentLang = $ctx->currentLang;
$navigation = $ctx->navigation;
$homeLabel = $ctx->homeLabel;
$translations = $ctx->translations;
$pageMetadata = loadMetadata($pageDir, $ctx->currentLang, $ctx->defaultLang);
$pageMetadata = loadMetadata($pageDir);
// Load page-level plugins
getPluginManager()->loadPagePlugins($pageMetadata);
$navigation = $ctx->navigation;
$homeLabel = $ctx->homeLabel;
$pageTitle = $pageMetadata['title'] ?? null;
$metaDescription = extractMetaDescription($pageDir, $pageMetadata, $ctx->currentLang, $ctx->defaultLang);
$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
// Check for cover image
$coverImage = findCoverImage($pageDir);
$socialImageUrl = null;
if ($coverImage) {
@ -133,12 +140,25 @@ function renderMultipleFiles(Context $ctx, array $filePaths, string $pageDir): v
$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();
include $ctx->templates->page;
$content = ob_get_clean();
require $ctx->templates->page;
$wrappedContent = ob_get_clean();
// Wrap with base template
include $ctx->templates->base;
exit;
}