Add page template with metadata display and copyright translation
Add support for language translations in footer Add page template to template resolution logic
This commit is contained in:
parent
19bb105303
commit
d937ca6166
3 changed files with 122 additions and 64 deletions
|
@ -23,7 +23,7 @@
|
||||||
<?= $content ?>
|
<?= $content ?>
|
||||||
</main>
|
</main>
|
||||||
<footer>
|
<footer>
|
||||||
<p>© <?= date('Y') ?></p>
|
<p>© <?= date('Y') ?> <?= htmlspecialchars($translations['footer_copyright'] ?? '') ?></p>
|
||||||
</footer>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
25
app/default/templates/page.php
Normal file
25
app/default/templates/page.php
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
<?= $content ?>
|
||||||
|
|
||||||
|
<?php if ($pageMetadata && (isset($pageMetadata['tags']) || isset($pageMetadata['categories']))): ?>
|
||||||
|
<aside class="metadata">
|
||||||
|
<?php if (!empty($pageMetadata['categories'])): ?>
|
||||||
|
<div class="categories">
|
||||||
|
<strong><?= htmlspecialchars($translations['categories'] ?? 'Categories') ?>:</strong>
|
||||||
|
<?php
|
||||||
|
$categories = array_map('trim', explode(',', $pageMetadata['categories']));
|
||||||
|
echo implode(', ', array_map('htmlspecialchars', $categories));
|
||||||
|
?>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if (!empty($pageMetadata['tags'])): ?>
|
||||||
|
<div class="tags">
|
||||||
|
<strong><?= htmlspecialchars($translations['tags'] ?? 'Tags') ?>:</strong>
|
||||||
|
<?php
|
||||||
|
$tags = array_map('trim', explode(',', $pageMetadata['tags']));
|
||||||
|
echo implode(', ', array_map('htmlspecialchars', $tags));
|
||||||
|
?>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</aside>
|
||||||
|
<?php endif; ?>
|
159
app/router.php
159
app/router.php
|
@ -1,7 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
// Load configuration
|
// Load configuration
|
||||||
$configFile = file_exists(__DIR__ . '/../custom/config.ini')
|
$configFile = file_exists(__DIR__ . '/../custom/config.ini')
|
||||||
? __DIR__ . '/../custom/config.ini'
|
? __DIR__ . '/../custom/config.ini'
|
||||||
: __DIR__ . '/config.ini';
|
: __DIR__ . '/config.ini';
|
||||||
$config = parse_ini_file($configFile, true);
|
$config = parse_ini_file($configFile, true);
|
||||||
|
|
||||||
|
@ -28,12 +28,17 @@ $isDocsRequest = str_starts_with($requestPath, 'docs');
|
||||||
// Use docs templates for /docs, otherwise use custom/default templates
|
// Use docs templates for /docs, otherwise use custom/default templates
|
||||||
if ($isDocsRequest) {
|
if ($isDocsRequest) {
|
||||||
$baseTemplate = __DIR__ . '/default/docs/templates/base.php';
|
$baseTemplate = __DIR__ . '/default/docs/templates/base.php';
|
||||||
|
$pageTemplate = __DIR__ . '/default/docs/templates/base.php';
|
||||||
$listTemplate = __DIR__ . '/default/docs/templates/list.php';
|
$listTemplate = __DIR__ . '/default/docs/templates/list.php';
|
||||||
} else {
|
} else {
|
||||||
$customBaseTemplate = dirname(__DIR__) . '/custom/templates/base.php';
|
$customBaseTemplate = dirname(__DIR__) . '/custom/templates/base.php';
|
||||||
$defaultBaseTemplate = __DIR__ . '/default/templates/base.php';
|
$defaultBaseTemplate = __DIR__ . '/default/templates/base.php';
|
||||||
$baseTemplate = file_exists($customBaseTemplate) ? $customBaseTemplate : $defaultBaseTemplate;
|
$baseTemplate = file_exists($customBaseTemplate) ? $customBaseTemplate : $defaultBaseTemplate;
|
||||||
|
|
||||||
|
$customPageTemplate = dirname(__DIR__) . '/custom/templates/page.php';
|
||||||
|
$defaultPageTemplate = __DIR__ . '/default/templates/page.php';
|
||||||
|
$pageTemplate = file_exists($customPageTemplate) ? $customPageTemplate : $defaultPageTemplate;
|
||||||
|
|
||||||
$customListTemplate = dirname(__DIR__) . '/custom/templates/list.php';
|
$customListTemplate = dirname(__DIR__) . '/custom/templates/list.php';
|
||||||
$defaultListTemplate = __DIR__ . '/default/templates/list.php';
|
$defaultListTemplate = __DIR__ . '/default/templates/list.php';
|
||||||
$listTemplate = file_exists($customListTemplate) ? $customListTemplate : $defaultListTemplate;
|
$listTemplate = file_exists($customListTemplate) ? $customListTemplate : $defaultListTemplate;
|
||||||
|
@ -43,7 +48,7 @@ if ($isDocsRequest) {
|
||||||
function buildFilePatterns(string $lang, string $defaultLang): array {
|
function buildFilePatterns(string $lang, string $defaultLang): array {
|
||||||
$extensions = ['php', 'html', 'md'];
|
$extensions = ['php', 'html', 'md'];
|
||||||
$patterns = ['page' => [], 'single' => []];
|
$patterns = ['page' => [], 'single' => []];
|
||||||
|
|
||||||
foreach ($extensions as $ext) {
|
foreach ($extensions as $ext) {
|
||||||
// Language-specific files first (if not default language)
|
// Language-specific files first (if not default language)
|
||||||
if ($lang !== $defaultLang) {
|
if ($lang !== $defaultLang) {
|
||||||
|
@ -52,14 +57,14 @@ function buildFilePatterns(string $lang, string $defaultLang): array {
|
||||||
$patterns['single'][] = "post.$lang.$ext";
|
$patterns['single'][] = "post.$lang.$ext";
|
||||||
$patterns['single'][] = "article.$lang.$ext";
|
$patterns['single'][] = "article.$lang.$ext";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default files
|
// Default files
|
||||||
$patterns['page'][] = "page.$ext";
|
$patterns['page'][] = "page.$ext";
|
||||||
$patterns['single'][] = "single.$ext";
|
$patterns['single'][] = "single.$ext";
|
||||||
$patterns['single'][] = "post.$ext";
|
$patterns['single'][] = "post.$ext";
|
||||||
$patterns['single'][] = "article.$ext";
|
$patterns['single'][] = "article.$ext";
|
||||||
}
|
}
|
||||||
|
|
||||||
return $patterns;
|
return $patterns;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,14 +82,14 @@ function resolveTranslatedPath(string $requestPath, string $contentDir, string $
|
||||||
if ($lang === $defaultLang) {
|
if ($lang === $defaultLang) {
|
||||||
return $requestPath;
|
return $requestPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
$parts = explode('/', trim($requestPath, '/'));
|
$parts = explode('/', trim($requestPath, '/'));
|
||||||
$resolvedParts = [];
|
$resolvedParts = [];
|
||||||
$currentPath = $contentDir;
|
$currentPath = $contentDir;
|
||||||
|
|
||||||
foreach ($parts as $segment) {
|
foreach ($parts as $segment) {
|
||||||
if (empty($segment)) continue;
|
if (empty($segment)) continue;
|
||||||
|
|
||||||
// Check all subdirectories for slug matches
|
// Check all subdirectories for slug matches
|
||||||
$found = false;
|
$found = false;
|
||||||
if (is_dir($currentPath)) {
|
if (is_dir($currentPath)) {
|
||||||
|
@ -92,7 +97,7 @@ function resolveTranslatedPath(string $requestPath, string $contentDir, string $
|
||||||
scandir($currentPath) ?: [],
|
scandir($currentPath) ?: [],
|
||||||
fn($item) => !in_array($item, ['.', '..']) && is_dir("$currentPath/$item")
|
fn($item) => !in_array($item, ['.', '..']) && is_dir("$currentPath/$item")
|
||||||
);
|
);
|
||||||
|
|
||||||
foreach ($subdirs as $dir) {
|
foreach ($subdirs as $dir) {
|
||||||
$metadata = loadMetadata("$currentPath/$dir", $lang, $defaultLang);
|
$metadata = loadMetadata("$currentPath/$dir", $lang, $defaultLang);
|
||||||
if ($metadata && isset($metadata['slug']) && $metadata['slug'] === $segment) {
|
if ($metadata && isset($metadata['slug']) && $metadata['slug'] === $segment) {
|
||||||
|
@ -103,14 +108,14 @@ function resolveTranslatedPath(string $requestPath, string $contentDir, string $
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If no slug match, use segment as-is
|
// If no slug match, use segment as-is
|
||||||
if (!$found) {
|
if (!$found) {
|
||||||
$resolvedParts[] = $segment;
|
$resolvedParts[] = $segment;
|
||||||
$currentPath .= "/$segment";
|
$currentPath .= "/$segment";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return implode('/', $resolvedParts);
|
return implode('/', $resolvedParts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,46 +123,46 @@ function parseRequestPath(string $requestPath, string $contentDir, array $patter
|
||||||
// Resolve translated slugs to actual directory names
|
// Resolve translated slugs to actual directory names
|
||||||
$resolvedPath = resolveTranslatedPath($requestPath, $contentDir, $lang, $defaultLang);
|
$resolvedPath = resolveTranslatedPath($requestPath, $contentDir, $lang, $defaultLang);
|
||||||
$contentPath = rtrim($contentDir, '/') . '/' . ltrim($resolvedPath, '/');
|
$contentPath = rtrim($contentDir, '/') . '/' . ltrim($resolvedPath, '/');
|
||||||
|
|
||||||
if (is_file($contentPath)) {
|
if (is_file($contentPath)) {
|
||||||
return ['type' => 'file', 'path' => realpath($contentPath)];
|
return ['type' => 'file', 'path' => realpath($contentPath)];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_dir($contentPath)) {
|
if (is_dir($contentPath)) {
|
||||||
if ($file = findMatchingFile($contentPath, $patterns['single']) ?: findMatchingFile($contentPath, $patterns['page'])) {
|
if ($file = findMatchingFile($contentPath, $patterns['single']) ?: findMatchingFile($contentPath, $patterns['page'])) {
|
||||||
return ['type' => 'file', 'path' => $file, 'needsSlash' => !$hasTrailingSlash];
|
return ['type' => 'file', 'path' => $file, 'needsSlash' => !$hasTrailingSlash];
|
||||||
}
|
}
|
||||||
return ['type' => 'directory', 'path' => realpath($contentPath)];
|
return ['type' => 'directory', 'path' => realpath($contentPath)];
|
||||||
}
|
}
|
||||||
|
|
||||||
return ['type' => 'not_found', 'path' => $contentPath];
|
return ['type' => 'not_found', 'path' => $contentPath];
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadMetadata(string $dirPath, string $lang, string $defaultLang): ?array {
|
function loadMetadata(string $dirPath, string $lang, string $defaultLang): ?array {
|
||||||
$metadataFile = "$dirPath/metadata.ini";
|
$metadataFile = "$dirPath/metadata.ini";
|
||||||
if (!file_exists($metadataFile)) return null;
|
if (!file_exists($metadataFile)) return null;
|
||||||
|
|
||||||
$metadata = parse_ini_file($metadataFile, true);
|
$metadata = parse_ini_file($metadataFile, true);
|
||||||
if (!$metadata) return null;
|
if (!$metadata) return null;
|
||||||
|
|
||||||
// Extract base metadata (non-section values)
|
// Extract base metadata (non-section values)
|
||||||
$baseMetadata = array_filter($metadata, fn($key) => !is_array($metadata[$key]), ARRAY_FILTER_USE_KEY);
|
$baseMetadata = array_filter($metadata, fn($key) => !is_array($metadata[$key]), ARRAY_FILTER_USE_KEY);
|
||||||
|
|
||||||
// If current language is not default, merge language-specific overrides
|
// If current language is not default, merge language-specific overrides
|
||||||
if ($lang !== $defaultLang && isset($metadata[$lang]) && is_array($metadata[$lang])) {
|
if ($lang !== $defaultLang && isset($metadata[$lang]) && is_array($metadata[$lang])) {
|
||||||
$baseMetadata = array_merge($baseMetadata, $metadata[$lang]);
|
$baseMetadata = array_merge($baseMetadata, $metadata[$lang]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $baseMetadata ?: null;
|
return $baseMetadata ?: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function extractTitle(string $filePath, array $patterns): ?string {
|
function extractTitle(string $filePath, array $patterns): ?string {
|
||||||
$file = findMatchingFile($filePath, $patterns['single']) ?: findMatchingFile($filePath, $patterns['page']);
|
$file = findMatchingFile($filePath, $patterns['single']) ?: findMatchingFile($filePath, $patterns['page']);
|
||||||
if (!$file) return null;
|
if (!$file) return null;
|
||||||
|
|
||||||
$ext = pathinfo($file, PATHINFO_EXTENSION);
|
$ext = pathinfo($file, PATHINFO_EXTENSION);
|
||||||
$content = file_get_contents($file);
|
$content = file_get_contents($file);
|
||||||
|
|
||||||
if ($ext === 'md' && preg_match('/^#\s+(.+)$/m', $content, $matches)) {
|
if ($ext === 'md' && preg_match('/^#\s+(.+)$/m', $content, $matches)) {
|
||||||
return trim($matches[1]);
|
return trim($matches[1]);
|
||||||
}
|
}
|
||||||
|
@ -195,28 +200,38 @@ function findCoverImage(string $dirPath): ?string {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function loadTranslations(string $lang): array {
|
||||||
|
$translationFile = dirname(__DIR__) . "/custom/languages/$lang.ini";
|
||||||
|
if (file_exists($translationFile)) {
|
||||||
|
return parse_ini_file($translationFile) ?: [];
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
function buildNavigation(string $contentDir, string $currentLang, string $defaultLang, array $pageFilePatterns): array {
|
function buildNavigation(string $contentDir, string $currentLang, string $defaultLang, array $pageFilePatterns): array {
|
||||||
$navItems = [];
|
$navItems = [];
|
||||||
|
|
||||||
// Scan top-level directories in content
|
// Scan top-level directories in content
|
||||||
$items = array_filter(
|
$items = array_filter(
|
||||||
scandir($contentDir) ?: [],
|
scandir($contentDir) ?: [],
|
||||||
fn($item) => !in_array($item, ['.', '..']) && is_dir("$contentDir/$item")
|
fn($item) => !in_array($item, ['.', '..']) && is_dir("$contentDir/$item")
|
||||||
);
|
);
|
||||||
|
|
||||||
foreach ($items as $item) {
|
foreach ($items as $item) {
|
||||||
$itemPath = "$contentDir/$item";
|
$itemPath = "$contentDir/$item";
|
||||||
$metadata = loadMetadata($itemPath, $currentLang, $defaultLang);
|
$metadata = loadMetadata($itemPath, $currentLang, $defaultLang);
|
||||||
|
|
||||||
// Check if this item should be in menu
|
// Check if this item should be in menu
|
||||||
if (!$metadata || empty($metadata['menu'])) {
|
if (!$metadata || empty($metadata['menu'])) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if content exists for current language
|
// Check if content exists for current language
|
||||||
if ($currentLang !== $defaultLang) {
|
if ($currentLang !== $defaultLang) {
|
||||||
$extensions = ['php', 'html', 'md'];
|
$extensions = ['php', 'html', 'md'];
|
||||||
$hasContent = false;
|
$hasContent = false;
|
||||||
|
|
||||||
|
// Check for language-specific content files
|
||||||
foreach ($extensions as $ext) {
|
foreach ($extensions as $ext) {
|
||||||
if (file_exists("$itemPath/single.$currentLang.$ext") ||
|
if (file_exists("$itemPath/single.$currentLang.$ext") ||
|
||||||
file_exists("$itemPath/post.$currentLang.$ext") ||
|
file_exists("$itemPath/post.$currentLang.$ext") ||
|
||||||
|
@ -226,56 +241,65 @@ function buildNavigation(string $contentDir, string $currentLang, string $defaul
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If no language-specific files, check if metadata has title for this language
|
||||||
|
if (!$hasContent && $metadata && isset($metadata['title'])) {
|
||||||
|
$hasContent = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (!$hasContent) continue;
|
if (!$hasContent) continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract title and build URL
|
// Extract title and build URL
|
||||||
$title = $metadata['title'] ?? extractTitle($itemPath, $pageFilePatterns) ?? $item;
|
$title = $metadata['title'] ?? extractTitle($itemPath, $pageFilePatterns) ?? ucfirst($item);
|
||||||
$langPrefix = $currentLang !== $defaultLang ? "/$currentLang" : '';
|
$langPrefix = $currentLang !== $defaultLang ? "/$currentLang" : '';
|
||||||
|
|
||||||
// Use translated slug if available
|
// Use translated slug if available
|
||||||
$urlSlug = ($currentLang !== $defaultLang && $metadata && isset($metadata['slug']))
|
$urlSlug = ($currentLang !== $defaultLang && $metadata && isset($metadata['slug']))
|
||||||
? $metadata['slug']
|
? $metadata['slug']
|
||||||
: $item;
|
: $item;
|
||||||
|
|
||||||
$navItems[] = [
|
$navItems[] = [
|
||||||
'title' => $title,
|
'title' => $title,
|
||||||
'url' => $langPrefix . '/' . urlencode($urlSlug) . '/',
|
'url' => $langPrefix . '/' . urlencode($urlSlug) . '/',
|
||||||
'order' => (int)($metadata['menu_order'] ?? 999)
|
'order' => (int)($metadata['menu_order'] ?? 999)
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort by menu_order
|
// Sort by menu_order
|
||||||
usort($navItems, fn($a, $b) => $a['order'] <=> $b['order']);
|
usort($navItems, fn($a, $b) => $a['order'] <=> $b['order']);
|
||||||
|
|
||||||
return $navItems;
|
return $navItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderTemplate(string $content, int $statusCode = 200): void {
|
function renderTemplate(string $content, int $statusCode = 200): void {
|
||||||
global $baseTemplate, $contentDir, $currentLang, $defaultLang, $pageFilePatterns;
|
global $baseTemplate, $contentDir, $currentLang, $defaultLang, $pageFilePatterns;
|
||||||
|
|
||||||
// Build navigation for templates
|
// Build navigation for templates
|
||||||
$navigation = buildNavigation($contentDir, $currentLang, $defaultLang, $pageFilePatterns);
|
$navigation = buildNavigation($contentDir, $currentLang, $defaultLang, $pageFilePatterns);
|
||||||
|
|
||||||
// Load frontpage metadata for home button label
|
// Load frontpage metadata for home button label
|
||||||
$frontpageMetadata = loadMetadata($contentDir, $currentLang, $defaultLang);
|
$frontpageMetadata = loadMetadata($contentDir, $currentLang, $defaultLang);
|
||||||
$homeLabel = $frontpageMetadata['slug'] ?? 'Home';
|
$homeLabel = $frontpageMetadata['slug'] ?? 'Home';
|
||||||
|
|
||||||
|
// Load translations
|
||||||
|
$translations = loadTranslations($currentLang);
|
||||||
|
|
||||||
http_response_code($statusCode);
|
http_response_code($statusCode);
|
||||||
include $baseTemplate;
|
include $baseTemplate;
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderFile(string $filePath): void {
|
function renderFile(string $filePath): void {
|
||||||
global $baseTemplate, $contentDir, $currentLang, $defaultLang, $pageFilePatterns;
|
global $baseTemplate, $pageTemplate, $contentDir, $currentLang, $defaultLang, $pageFilePatterns;
|
||||||
|
|
||||||
$realPath = realpath($filePath);
|
$realPath = realpath($filePath);
|
||||||
if (!$realPath || !str_starts_with($realPath, $contentDir) || !is_readable($realPath)) {
|
if (!$realPath || !str_starts_with($realPath, $contentDir) || !is_readable($realPath)) {
|
||||||
renderTemplate("<h1>403 Forbidden</h1><p>Access denied.</p>", 403);
|
renderTemplate("<article><h1>403 Forbidden</h1><p>Access denied.</p></article>", 403);
|
||||||
}
|
}
|
||||||
|
|
||||||
$ext = pathinfo($realPath, PATHINFO_EXTENSION);
|
$ext = pathinfo($realPath, PATHINFO_EXTENSION);
|
||||||
|
|
||||||
if (in_array($ext, ['php', 'html', 'md'])) {
|
if (in_array($ext, ['php', 'html', 'md'])) {
|
||||||
ob_start();
|
ob_start();
|
||||||
if ($ext === 'md') {
|
if ($ext === 'md') {
|
||||||
|
@ -287,23 +311,32 @@ function renderFile(string $filePath): void {
|
||||||
include $realPath;
|
include $realPath;
|
||||||
}
|
}
|
||||||
$content = ob_get_clean();
|
$content = ob_get_clean();
|
||||||
|
|
||||||
// Build navigation for templates
|
// Build navigation for templates
|
||||||
$navigation = buildNavigation($contentDir, $currentLang, $defaultLang, $pageFilePatterns);
|
$navigation = buildNavigation($contentDir, $currentLang, $defaultLang, $pageFilePatterns);
|
||||||
|
|
||||||
// Load metadata for current page/directory
|
// Load metadata for current page/directory
|
||||||
$pageDir = dirname($realPath);
|
$pageDir = dirname($realPath);
|
||||||
$pageMetadata = loadMetadata($pageDir, $currentLang, $defaultLang);
|
$pageMetadata = loadMetadata($pageDir, $currentLang, $defaultLang);
|
||||||
$pageTitle = $pageMetadata['title'] ?? null;
|
$pageTitle = $pageMetadata['title'] ?? null;
|
||||||
|
|
||||||
// Load frontpage metadata for home button label
|
// Load frontpage metadata for home button label
|
||||||
$frontpageMetadata = loadMetadata($contentDir, $currentLang, $defaultLang);
|
$frontpageMetadata = loadMetadata($contentDir, $currentLang, $defaultLang);
|
||||||
$homeLabel = $frontpageMetadata['slug'] ?? 'Home';
|
$homeLabel = $frontpageMetadata['slug'] ?? 'Home';
|
||||||
|
|
||||||
|
// Load translations
|
||||||
|
$translations = loadTranslations($currentLang);
|
||||||
|
|
||||||
|
// Wrap content with page template
|
||||||
|
ob_start();
|
||||||
|
include $pageTemplate;
|
||||||
|
$content = ob_get_clean();
|
||||||
|
|
||||||
|
// Wrap with base template
|
||||||
include $baseTemplate;
|
include $baseTemplate;
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Serve other file types directly
|
// Serve other file types directly
|
||||||
header('Content-Type: ' . (mime_content_type($realPath) ?: 'application/octet-stream'));
|
header('Content-Type: ' . (mime_content_type($realPath) ?: 'application/octet-stream'));
|
||||||
readfile($realPath);
|
readfile($realPath);
|
||||||
|
@ -319,7 +352,7 @@ if (empty($requestPath)) {
|
||||||
} elseif (file_exists("$contentDir/frontpage.php")) {
|
} elseif (file_exists("$contentDir/frontpage.php")) {
|
||||||
$frontPage = "$contentDir/frontpage.php";
|
$frontPage = "$contentDir/frontpage.php";
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($frontPage) {
|
if ($frontPage) {
|
||||||
renderFile($frontPage);
|
renderFile($frontPage);
|
||||||
}
|
}
|
||||||
|
@ -336,22 +369,22 @@ switch ($parsedPath['type']) {
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
renderFile($parsedPath['path']);
|
renderFile($parsedPath['path']);
|
||||||
|
|
||||||
case 'directory':
|
case 'directory':
|
||||||
$dir = $parsedPath['path'];
|
$dir = $parsedPath['path'];
|
||||||
if (file_exists("$dir/index.php")) {
|
if (file_exists("$dir/index.php")) {
|
||||||
renderFile("$dir/index.php");
|
renderFile("$dir/index.php");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default directory listing
|
// Default directory listing
|
||||||
$subdirs = array_filter(
|
$subdirs = array_filter(
|
||||||
scandir($dir) ?: [],
|
scandir($dir) ?: [],
|
||||||
fn($item) => !in_array($item, ['.', '..']) && is_dir("$dir/$item")
|
fn($item) => !in_array($item, ['.', '..']) && is_dir("$dir/$item")
|
||||||
);
|
);
|
||||||
|
|
||||||
$items = array_filter(array_map(function($item) use ($dir, $requestPath, $currentLang, $defaultLang, $pageFilePatterns) {
|
$items = array_filter(array_map(function($item) use ($dir, $requestPath, $currentLang, $defaultLang, $pageFilePatterns) {
|
||||||
$itemPath = "$dir/$item";
|
$itemPath = "$dir/$item";
|
||||||
|
|
||||||
// Check if content exists for current language
|
// Check if content exists for current language
|
||||||
if ($currentLang !== $defaultLang) {
|
if ($currentLang !== $defaultLang) {
|
||||||
// For non-default languages, only check language-specific files
|
// For non-default languages, only check language-specific files
|
||||||
|
@ -368,13 +401,13 @@ switch ($parsedPath['type']) {
|
||||||
}
|
}
|
||||||
if (!$hasContent) return null;
|
if (!$hasContent) return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build patterns for rendering (includes fallbacks)
|
// Build patterns for rendering (includes fallbacks)
|
||||||
$patterns = buildFilePatterns($currentLang, $defaultLang);
|
$patterns = buildFilePatterns($currentLang, $defaultLang);
|
||||||
|
|
||||||
$metadata = loadMetadata($itemPath, $currentLang, $defaultLang);
|
$metadata = loadMetadata($itemPath, $currentLang, $defaultLang);
|
||||||
$coverImage = findCoverImage($itemPath);
|
$coverImage = findCoverImage($itemPath);
|
||||||
|
|
||||||
$title = $metadata['title'] ?? extractTitle($itemPath, $patterns) ?? $item;
|
$title = $metadata['title'] ?? extractTitle($itemPath, $patterns) ?? $item;
|
||||||
$date = null;
|
$date = null;
|
||||||
if (isset($metadata['date'])) {
|
if (isset($metadata['date'])) {
|
||||||
|
@ -382,14 +415,14 @@ switch ($parsedPath['type']) {
|
||||||
} else {
|
} else {
|
||||||
$date = extractDateFromFolder($item) ?: date("F d, Y", filemtime($itemPath));
|
$date = extractDateFromFolder($item) ?: date("F d, Y", filemtime($itemPath));
|
||||||
}
|
}
|
||||||
|
|
||||||
$langPrefix = $currentLang !== $defaultLang ? "/$currentLang" : '';
|
$langPrefix = $currentLang !== $defaultLang ? "/$currentLang" : '';
|
||||||
|
|
||||||
// Use translated slug if available, otherwise use folder name
|
// Use translated slug if available, otherwise use folder name
|
||||||
$urlSlug = ($currentLang !== $defaultLang && $metadata && isset($metadata['slug']))
|
$urlSlug = ($currentLang !== $defaultLang && $metadata && isset($metadata['slug']))
|
||||||
? $metadata['slug']
|
? $metadata['slug']
|
||||||
: $item;
|
: $item;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'title' => $title,
|
'title' => $title,
|
||||||
'date' => $date,
|
'date' => $date,
|
||||||
|
@ -398,17 +431,17 @@ switch ($parsedPath['type']) {
|
||||||
'summary' => $metadata['summary'] ?? null
|
'summary' => $metadata['summary'] ?? null
|
||||||
];
|
];
|
||||||
}, $subdirs));
|
}, $subdirs));
|
||||||
|
|
||||||
ob_start();
|
ob_start();
|
||||||
include $listTemplate;
|
include $listTemplate;
|
||||||
$content = ob_get_clean();
|
$content = ob_get_clean();
|
||||||
|
|
||||||
// Build navigation for base template
|
// Build navigation for base template
|
||||||
$navigation = buildNavigation($contentDir, $currentLang, $defaultLang, $pageFilePatterns);
|
$navigation = buildNavigation($contentDir, $currentLang, $defaultLang, $pageFilePatterns);
|
||||||
|
|
||||||
include $baseTemplate;
|
include $baseTemplate;
|
||||||
exit;
|
exit;
|
||||||
|
|
||||||
case 'not_found':
|
case 'not_found':
|
||||||
renderTemplate("<h1>404 Not Found</h1><p>The requested resource was not found.</p>", 404);
|
renderTemplate("<h1>404 Not Found</h1><p>The requested resource was not found.</p>", 404);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue