Implement function to resolve slugs to actual folder paths Update path parsing to handle slug resolution Add language prefix support to navigation URLs
147 lines
4.7 KiB
PHP
147 lines
4.7 KiB
PHP
<?php
|
|
|
|
// Find all content files in a directory
|
|
function findAllContentFiles(string $dir): array {
|
|
if (!is_dir($dir)) return [];
|
|
|
|
$files = scandir($dir) ?: [];
|
|
$contentFiles = [];
|
|
|
|
foreach ($files as $file) {
|
|
if ($file === '.' || $file === '..' || $file === 'index.php') continue;
|
|
|
|
$ext = pathinfo($file, PATHINFO_EXTENSION);
|
|
if (!in_array($ext, CONTENT_EXTENSIONS)) continue;
|
|
|
|
$filePath = "$dir/$file";
|
|
if (!is_file($filePath)) continue;
|
|
|
|
$contentFiles[] = [
|
|
'path' => $filePath,
|
|
'name' => $file,
|
|
'ext' => $ext
|
|
];
|
|
}
|
|
|
|
// Let plugins filter content files (e.g., by language)
|
|
$contentFiles = Hooks::apply(Hook::PROCESS_CONTENT, $contentFiles, $dir);
|
|
|
|
// Sort by filename
|
|
usort($contentFiles, fn($a, $b) => strnatcmp($a['name'], $b['name']));
|
|
|
|
return array_column($contentFiles, 'path');
|
|
}
|
|
|
|
function resolveSlugToFolder(string $parentDir, string $slug): ?string {
|
|
if (!is_dir($parentDir)) return null;
|
|
|
|
$items = scandir($parentDir) ?: [];
|
|
foreach ($items as $item) {
|
|
if ($item === '.' || $item === '..' || !is_dir("$parentDir/$item")) continue;
|
|
|
|
// Check if folder name matches slug
|
|
if ($item === $slug) {
|
|
return $item;
|
|
}
|
|
|
|
// Check metadata for custom slug
|
|
$metadata = loadMetadata("$parentDir/$item");
|
|
if ($metadata && isset($metadata['slug']) && $metadata['slug'] === $slug) {
|
|
return $item;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
function parseRequestPath(Context $ctx): array {
|
|
$requestPath = $ctx->requestPath;
|
|
|
|
if (empty($requestPath)) {
|
|
return ['type' => 'frontpage', 'path' => $ctx->contentDir];
|
|
}
|
|
|
|
// Try resolving slug to actual folder path
|
|
$pathParts = explode('/', trim($requestPath, '/'));
|
|
$resolvedPath = $ctx->contentDir;
|
|
|
|
foreach ($pathParts as $part) {
|
|
$resolved = resolveSlugToFolder($resolvedPath, $part);
|
|
if ($resolved === null) {
|
|
// Slug not found, return not_found
|
|
return ['type' => 'not_found', 'path' => $ctx->contentDir . '/' . $requestPath];
|
|
}
|
|
$resolvedPath .= '/' . $resolved;
|
|
}
|
|
|
|
$contentPath = $resolvedPath;
|
|
|
|
// Check if it's a directory
|
|
if (is_dir($contentPath)) {
|
|
$items = scandir($contentPath) ?: [];
|
|
$subdirs = array_filter($items, fn($item) =>
|
|
$item !== '.' && $item !== '..' && is_dir("$contentPath/$item")
|
|
);
|
|
|
|
if (!empty($subdirs)) {
|
|
return ['type' => 'list', 'path' => $contentPath];
|
|
} else {
|
|
return ['type' => 'page', 'path' => $contentPath];
|
|
}
|
|
}
|
|
|
|
return ['type' => 'not_found', 'path' => $contentPath];
|
|
}
|
|
|
|
function loadMetadata(string $dirPath): ?array {
|
|
$metadataFile = "$dirPath/metadata.ini";
|
|
if (!file_exists($metadataFile)) return null;
|
|
|
|
$metadata = parse_ini_file($metadataFile, true);
|
|
if (!$metadata) return null;
|
|
|
|
// Get base metadata (non-array values)
|
|
$baseMetadata = array_filter($metadata, fn($key) => !is_array($metadata[$key]), ARRAY_FILTER_USE_KEY);
|
|
|
|
// Store full metadata for plugins to access
|
|
$baseMetadata['_raw'] = $metadata;
|
|
|
|
// Let plugins modify metadata (e.g., merge language sections)
|
|
return Hooks::apply(Hook::PROCESS_CONTENT, $baseMetadata, $dirPath, 'metadata');
|
|
}
|
|
|
|
function buildNavigation(Context $ctx): array {
|
|
$items = scandir($ctx->contentDir) ?: [];
|
|
$navItems = [];
|
|
$langPrefix = $ctx->get('langPrefix', '');
|
|
|
|
foreach ($items as $item) {
|
|
if ($item === '.' || $item === '..' || !is_dir($ctx->contentDir . "/$item")) continue;
|
|
|
|
$itemPath = "{$ctx->contentDir}/$item";
|
|
$metadata = loadMetadata($itemPath);
|
|
|
|
// Only include if explicitly marked as menu item
|
|
// parse_ini_file returns boolean true as 1, false as empty string, and "true"/"false" as strings
|
|
if (!$metadata || !isset($metadata['menu']) || !$metadata['menu']) {
|
|
continue;
|
|
}
|
|
|
|
// Extract title
|
|
$title = $metadata['title'] ?? extractTitle($itemPath) ?? ucfirst($item);
|
|
|
|
// Use slug if available, otherwise use folder name
|
|
$urlSlug = ($metadata && isset($metadata['slug'])) ? $metadata['slug'] : $item;
|
|
|
|
$navItems[] = [
|
|
'title' => $title,
|
|
'url' => $langPrefix . '/' . urlencode($urlSlug) . '/',
|
|
'order' => (int)($metadata['menu_order'] ?? 999)
|
|
];
|
|
}
|
|
|
|
// Sort by menu_order
|
|
usort($navItems, fn($a, $b) => $a['order'] <=> $b['order']);
|
|
|
|
return $navItems;
|
|
}
|