requestPath; if (file_exists($assetPath) && is_file($assetPath)) { header('Content-Type: ' . (mime_content_type($assetPath) ?: 'application/octet-stream')); readfile($assetPath); exit; } // Check for assets in content directory (CSS, images, etc.) $contentAssetPath = $ctx->contentDir . '/' . $ctx->requestPath; if (file_exists($contentAssetPath) && is_file($contentAssetPath)) { $ext = pathinfo($contentAssetPath, PATHINFO_EXTENSION); // Define MIME types for asset files $mimeTypes = [ 'css' => 'text/css', 'jpg' => 'image/jpeg', 'jpeg' => 'image/jpeg', 'png' => 'image/png', 'gif' => 'image/gif', 'webp' => 'image/webp', 'svg' => 'image/svg+xml', 'pdf' => 'application/pdf', 'woff' => 'font/woff', 'woff2' => 'font/woff2', 'ttf' => 'font/ttf', 'otf' => 'font/otf', ]; $extLower = strtolower($ext); if (isset($mimeTypes[$extLower])) { header('Content-Type: ' . $mimeTypes[$extLower]); readfile($contentAssetPath); exit; } } // Handle frontpage if (empty($ctx->requestPath)) { $contentFiles = findAllContentFiles($ctx->contentDir); if (!empty($contentFiles)) { renderMultipleFiles($ctx, $contentFiles, $ctx->contentDir); } } // Parse and handle request $parsedPath = parseRequestPath($ctx); switch ($parsedPath['type']) { case 'page': $dir = $parsedPath['path']; // Redirect to add trailing slash if needed if (!$ctx->hasTrailingSlash) { header('Location: ' . rtrim($_SERVER['REQUEST_URI'], '/') . '/', true, 301); exit; } $contentFiles = findAllContentFiles($dir); if (!empty($contentFiles)) { renderMultipleFiles($ctx, $contentFiles, $dir); } break; case 'list': $dir = $parsedPath['path']; // Check for page content files in this directory $pageContent = null; $contentFiles = findAllContentFiles($dir); if (!empty($contentFiles)) { $pageContent = implode('', array_map('renderContentFile', $contentFiles)); } // Load metadata for this directory $metadata = loadMetadata($dir); // Check if hide_list is enabled - if so, treat as page if (isset($metadata['hide_list']) && $metadata['hide_list']) { if (!empty($contentFiles)) { renderMultipleFiles($ctx, $contentFiles, $dir); } break; } // Select list template based on metadata page_template $listTemplate = $ctx->templates->list; if (isset($metadata['page_template']) && !empty($metadata['page_template'])) { $templateName = $metadata['page_template']; if (!str_ends_with($templateName, '.php')) { $templateName .= ''; } $customTemplate = dirname(__DIR__) . "/custom/templates/$templateName.php"; $defaultTemplate = __DIR__ . "/default/templates/$templateName.php"; if (file_exists($customTemplate)) { $listTemplate = $customTemplate; } elseif (file_exists($defaultTemplate)) { $listTemplate = $defaultTemplate; } } // Build list items $subdirs = getSubdirectories($dir); $items = array_filter(array_map(function($item) use ($dir, $ctx) { $itemPath = "$dir/$item"; $metadata = loadMetadata($itemPath); $coverImage = findCoverImage($itemPath); $pdfFile = findPdfFile($itemPath); $title = $metadata['title'] ?? extractTitle($itemPath) ?? $item; $date = null; if (isset($metadata['date'])) { $date = $metadata['date']; // Let plugins format date $date = Hooks::apply(Hook::PROCESS_CONTENT, $date, 'date_format'); } else { $date = extractDateFromFolder($item) ?: date("F d, Y", filemtime($itemPath)); } // Use slug if available $urlSlug = ($metadata && isset($metadata['slug'])) ? $metadata['slug'] : $item; $baseUrl = '/' . trim($ctx->requestPath, '/') . '/' . urlencode($urlSlug); return [ 'title' => $title, 'url' => $baseUrl . '/', 'date' => $date, 'summary' => $metadata['summary'] ?? null, 'cover' => $coverImage ? "$baseUrl/$coverImage" : null, 'pdf' => $pdfFile ? "$baseUrl/$pdfFile" : null, 'redirect' => $metadata['redirect'] ?? null ]; }, $subdirs)); // Sort by date (newest first) if dates are present usort($items, fn($a, $b) => strcmp($b['date'] ?? '', $a['date'] ?? '')); // Prepare all variables for base template $navigation = $ctx->navigation; $homeLabel = $ctx->homeLabel; $pageTitle = $metadata['title'] ?? null; $metaDescription = extractMetaDescription($dir, $metadata); // Check for page-specific CSS $pageCss = findPageCss($dir, $ctx->contentDir); // Let plugins add template variables $templateVars = Hooks::apply(Hook::TEMPLATE_VARS, [ 'navigation' => $navigation, 'homeLabel' => $homeLabel, 'pageTitle' => $pageTitle, 'metaDescription' => $metaDescription, 'pageCss' => $pageCss, 'items' => $items, 'pageContent' => $pageContent ], $ctx); extract($templateVars); ob_start(); require $listTemplate; $content = ob_get_clean(); renderTemplate($ctx, $content); break; case 'not_found': http_response_code(404); renderTemplate($ctx, "
The requested page could not be found.
", 404); break; }