Fix unreachable index page and duplicate homepage entry in navigation

buildUrl() hardcoded 'index' as the homepage, so the menu link for
index.md pointed at /nl. With a different default_page that root URL
served another page, making index.md unreachable.

- Add getEffectiveDefaultPage(): resolves 'auto' to the detected page
  and caches the result
- buildUrl() now omits the page segment only for the effective default
  page instead of the literal string 'index'
- Route getPage(), generateBreadcrumb(), getContentType() and the
  render() template data (default_page, homepage, is_homepage,
  home_active_class, current_page, lang switch URLs) through it
- getHomepageTitle() returns t('home') so the home button no longer
  duplicates a menu item label
- Drop the now-redundant default_page skip in renderMenu() so every
  page stays reachable from the menu
- getAllContentDirs() also skips dot-directories (.git) in the move
  dropdown
This commit is contained in:
2026-07-28 16:09:44 +02:00
parent 842046ac82
commit 8fdbabf587
2 changed files with 36 additions and 29 deletions
+33 -27
View File
@@ -25,6 +25,7 @@ class CodePressCMS {
public $currentLanguage; public $currentLanguage;
public $searchResults = []; public $searchResults = [];
private $menu = []; private $menu = [];
private ?string $effectiveDefaultPage = null;
private $translations = []; private $translations = [];
private $pluginManager; private $pluginManager;
@@ -66,10 +67,12 @@ class CodePressCMS {
* @param array $params Additional query parameters * @param array $params Additional query parameters
* @return string Clean URL * @return string Clean URL
*/ */
public function buildUrl($page = 'index', $lang = null, $params = []) { public function buildUrl($page = null, $lang = null, $params = []) {
$lang = $lang ?: $this->currentLanguage; $lang = $lang ?: $this->currentLanguage;
$url = '/' . $lang; $url = '/' . $lang;
if ($page && $page !== 'index') { // Only omit the page segment for the actual homepage (default_page),
// not for a page that happens to be called 'index'
if ($page && $page !== $this->getEffectiveDefaultPage()) {
$url .= '/' . $page; $url .= '/' . $page;
} }
if (!empty($params)) { if (!empty($params)) {
@@ -78,6 +81,20 @@ class CodePressCMS {
return $url; return $url;
} }
/**
* Resolve the effective default page (handles 'auto' mode)
*
* @return string Page key that is served on the language root URL
*/
public function getEffectiveDefaultPage(): string
{
if ($this->effectiveDefaultPage === null) {
$page = $this->config['default_page'] ?? 'auto';
$this->effectiveDefaultPage = ($page === 'auto') ? $this->detectDefaultPage() : $page;
}
return $this->effectiveDefaultPage;
}
/** /**
* Build a clean admin URL * Build a clean admin URL
* *
@@ -353,10 +370,7 @@ class CodePressCMS {
return $this->getGuidePage(); return $this->getGuidePage();
} }
$page = $_GET['page'] ?? $this->config['default_page']; $page = $_GET['page'] ?? $this->getEffectiveDefaultPage();
if ($page === 'auto') {
$page = $this->detectDefaultPage();
}
// Limit length // Limit length
$page = substr($page, 0, 255); $page = substr($page, 0, 255);
// Only remove file extension at the end, not all dots // Only remove file extension at the end, not all dots
@@ -1057,11 +1071,11 @@ class CodePressCMS {
'search_query' => isset($_GET['search']) ? htmlspecialchars($_GET['search']) : '', 'search_query' => isset($_GET['search']) ? htmlspecialchars($_GET['search']) : '',
'menu' => $this->renderMenu($menu), 'menu' => $this->renderMenu($menu),
'breadcrumb' => $breadcrumb, 'breadcrumb' => $breadcrumb,
'default_page' => $this->config['default_page'], 'default_page' => $this->getEffectiveDefaultPage(),
'homepage' => $this->config['default_page'], 'homepage' => $this->getEffectiveDefaultPage(),
'homepage_title' => $homepageTitle, 'homepage_title' => $homepageTitle,
'is_homepage' => (!isset($_GET['page']) || $_GET['page'] === $this->config['default_page']), 'is_homepage' => (!isset($_GET['page']) || $_GET['page'] === $this->getEffectiveDefaultPage()),
'home_active_class' => (!isset($_GET['page']) || $_GET['page'] === $this->config['default_page']) ? 'active' : '', 'home_active_class' => (!isset($_GET['page']) || $_GET['page'] === $this->getEffectiveDefaultPage()) ? 'active' : '',
'is_guide_page' => isset($_GET['guide']), 'is_guide_page' => isset($_GET['guide']),
'lang_switch_url' => '', 'lang_switch_url' => '',
'author_name' => $this->config['author']['name'] ?? 'CodePress Developer', 'author_name' => $this->config['author']['name'] ?? 'CodePress Developer',
@@ -1084,11 +1098,11 @@ class CodePressCMS {
// Language // Language
'current_lang' => $this->currentLanguage, 'current_lang' => $this->currentLanguage,
'current_lang_upper' => strtoupper($this->currentLanguage), 'current_lang_upper' => strtoupper($this->currentLanguage),
'current_page' => $_GET['page'] ?? $this->config['default_page'], 'current_page' => $_GET['page'] ?? $this->getEffectiveDefaultPage(),
'available_langs' => array_map(function($lang) { 'available_langs' => array_map(function($lang) {
$lang['is_current'] = $lang['code'] === $this->currentLanguage; $lang['is_current'] = $lang['code'] === $this->currentLanguage;
$page = $_GET['page'] ?? $this->config['default_page']; $page = $_GET['page'] ?? $this->getEffectiveDefaultPage();
$lang['url'] = '/' . $lang['code'] . ($page !== $this->config['default_page'] ? '/' . $page : ''); $lang['url'] = '/' . $lang['code'] . ($page !== $this->getEffectiveDefaultPage() ? '/' . $page : '');
return $lang; return $lang;
}, $this->getAvailableLanguages()), }, $this->getAvailableLanguages()),
// Translations // Translations
@@ -1187,12 +1201,12 @@ class CodePressCMS {
return '<nav aria-label="breadcrumb"><ol class="breadcrumb">' . $sidebarToggle . '<li class="breadcrumb-item"><a href="/' . $this->currentLanguage . '"><i class="bi bi-house"></i></a></li><li class="breadcrumb-item"> > </li><li class="breadcrumb-item active">' . $this->t('search') . '</li></ol></nav>'; return '<nav aria-label="breadcrumb"><ol class="breadcrumb">' . $sidebarToggle . '<li class="breadcrumb-item"><a href="/' . $this->currentLanguage . '"><i class="bi bi-house"></i></a></li><li class="breadcrumb-item"> > </li><li class="breadcrumb-item active">' . $this->t('search') . '</li></ol></nav>';
} }
$page = $_GET['page'] ?? $this->config['default_page']; $page = $_GET['page'] ?? $this->getEffectiveDefaultPage();
$page = htmlspecialchars($page, ENT_QUOTES, 'UTF-8'); $page = htmlspecialchars($page, ENT_QUOTES, 'UTF-8');
$page = preg_replace('/\.[^.]+$/', '', $page); $page = preg_replace('/\.[^.]+$/', '', $page);
// Convert page to clean URL format for breadcrumb // Convert page to clean URL format for breadcrumb
if ($page === $this->config['default_page']) { if ($page === $this->getEffectiveDefaultPage()) {
return '<nav aria-label="breadcrumb"><ol class="breadcrumb">' . $sidebarToggle . '<li class="breadcrumb-item active"><i class="bi bi-house"></i></li></ol></nav>'; return '<nav aria-label="breadcrumb"><ol class="breadcrumb">' . $sidebarToggle . '<li class="breadcrumb-item active"><i class="bi bi-house"></i></li></ol></nav>';
} }
@@ -1274,11 +1288,6 @@ class CodePressCMS {
} else { } else {
// Show files in root as tabs, files in folders as dropdown items // Show files in root as tabs, files in folders as dropdown items
if ($level === 0) { if ($level === 0) {
// Don't show the homepage file as a separate tab since it's already the Home button
if ($item['path'] === $this->config['default_page']) {
continue;
}
$active = (isset($_GET['page']) && $_GET['page'] === $item['path']) ? 'active' : ''; $active = (isset($_GET['page']) && $_GET['page'] === $item['path']) ? 'active' : '';
$html .= '<li class="nav-item">'; $html .= '<li class="nav-item">';
$html .= '<a class="nav-link ' . $active . '" href="' . htmlspecialchars($item['url']) . '">'; $html .= '<a class="nav-link ' . $active . '" href="' . htmlspecialchars($item['url']) . '">';
@@ -1305,7 +1314,7 @@ class CodePressCMS {
*/ */
private function getContentType($page) { private function getContentType($page) {
// Try to determine content type from page request // Try to determine content type from page request
$pagePath = $_GET['page'] ?? $this->config['default_page']; $pagePath = $_GET['page'] ?? $this->getEffectiveDefaultPage();
$pagePath = preg_replace('/\.[^.]+$/', '', $pagePath); $pagePath = preg_replace('/\.[^.]+$/', '', $pagePath);
$filePath = $this->config['content_dir'] . '/' . $pagePath; $filePath = $this->config['content_dir'] . '/' . $pagePath;
@@ -1363,12 +1372,9 @@ class CodePressCMS {
* @return string Homepage title * @return string Homepage title
*/ */
private function getHomepageTitle() { private function getHomepageTitle() {
// Use formatted filename for homepage title in navigation // Use a generic "Home" label instead of the page name
$page = $this->config['default_page']; // to avoid duplication with the navigation menu
if ($page === 'auto') { return $this->t('home');
$page = $this->detectDefaultPage();
}
return $this->formatDisplayName($page);
} }
/** /**
+3 -2
View File
@@ -1675,8 +1675,9 @@ function getAllContentDirs(string $contentDir, string $realContentDir): array
if (strpos($realPath, $realContentDir) !== 0) continue; if (strpos($realPath, $realContentDir) !== 0) continue;
$relative = substr($realPath, strlen($realContentDir) + 1); $relative = substr($realPath, strlen($realContentDir) + 1);
if ($relative === false || $relative === '') continue; if ($relative === false || $relative === '') continue;
// Skip hidden directories (starting with -) // Skip hidden directories (starting with - or .)
if (strpos(basename($relative), '-') === 0) continue; $base = basename($relative);
if ($base[0] === '-' || $base[0] === '.') continue;
$dirs[] = $relative; $dirs[] = $relative;
} }