v2.6.1 (Lyra): Welcome page, 404 handling, installatie docs, opschoning

Nieuwe features:
- Welkomstpagina bij lege content-map (nieuwe installatie detectie)
- 404-afhandeling binnen actieve theme via admin/static/404.html
- HTTP 404 status bij onbekende pagina's en missende taalprefix

Opschoning:
- Verwijderd: package.json, src/scss/, root .htaccess, themes/demo/
- Verwijderde vendor packages: php-mqtt/client, mustache/mustache
- AGENTS.md samengevoegd naar root, development/AGENTS.md verwijderd
- .gitignore opgeschoond (NPM/node_modules/.sass-cache verwijderd)

Documentatie:
- Installatie instructies toegevoegd aan README (Apache2/Nginx/PHP/composer)
- README en guide versie referenties bijgewerkt naar 2.6.1
- Release notes: docs/release-notes/v2.6.1.md

Tests:
- Pentest: 30/30 geslaagd, 0 vulnerabilities
- WCAG 2.1 AA: 25/25 geslaagd, 100% compliance
- Test scripts gebruiken Apache-URL i.p.v. localhost:8080
This commit is contained in:
root
2026-08-17 14:48:46 +00:00
parent bd4fe54d09
commit c2cf08955b
53 changed files with 576 additions and 3964 deletions
+86 -3
View File
@@ -449,10 +449,29 @@ class CodePressCMS {
if (isset($_GET['guide']) || $pageCheck === 'guide') {
return $this->getGuidePage();
}
// Determine if the request has a valid language prefix
$availableLangs = array_keys($this->getAvailableLanguages());
$requestPath = parse_url($_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH) ?? '/';
$requestPath = ltrim($requestPath, '/');
$langFromUrl = '';
if ($requestPath !== '' && in_array(explode('/', $requestPath)[0], $availableLangs, true)) {
$langFromUrl = explode('/', $requestPath)[0];
}
// No language prefix and not the root → 404
if ($langFromUrl === '' && $requestPath !== '' && $requestPath !== 'favicon.ico') {
return $this->getError404();
}
// Check if content directory is empty
// Check if content directory is empty — show welcome page for new installations
if ($this->isContentDirEmpty()) {
return $this->getGuidePage();
$requestedPage = $_GET['page'] ?? '';
// Only show welcome page on the home URL; everything else is a 404
if (empty($requestedPage) || $requestedPage === $this->getEffectiveDefaultPage()) {
return $this->getWelcomePage();
}
return $this->getError404();
}
$page = $_GET['page'] ?? $this->getEffectiveDefaultPage();
@@ -1048,9 +1067,60 @@ class CodePressCMS {
$files = scandir($contentDir);
$files = array_diff($files, ['.', '..']);
// Filter out hidden files (e.g. .gitkeep) — only count visible content
$files = array_filter($files, function($f) {
return $f[0] !== '.';
});
return empty($files);
}
/**
* Get welcome page content for new installations (empty content directory)
*
* Shows a clear "new installation" message with next steps when the
* content directory has no content files yet.
*
* @return array Welcome page data
*/
private function getWelcomePage() {
$adminUrl = $this->buildAdminUrl();
$guideUrl = '/' . $this->currentLanguage . '/guide';
$content = '<div class="welcome-page">';
$content .= '<h1>' . htmlspecialchars($this->t('welcome_title')) . '</h1>';
$content .= '<p class="alert alert-info" role="alert">';
$content .= '<i class="bi bi-info-circle me-2" aria-hidden="true"></i>';
$content .= htmlspecialchars($this->t('welcome_intro'));
$content .= '</p>';
$content .= '<h2>' . htmlspecialchars($this->t('welcome_next_steps')) . '</h2>';
$content .= '<ol class="list-group list-group-numbered mb-4">';
$content .= '<li class="list-group-item">' . htmlspecialchars($this->t('welcome_step_1')) . '</li>';
$content .= '<li class="list-group-item">' . htmlspecialchars($this->t('welcome_step_2')) . '</li>';
$content .= '<li class="list-group-item">' . htmlspecialchars($this->t('welcome_step_3')) . '</li>';
$content .= '</ol>';
$content .= '<div class="d-flex flex-column flex-md-row gap-2 mb-4">';
$content .= '<a href="' . htmlspecialchars($adminUrl) . '" class="btn btn-primary">';
$content .= '<i class="bi bi-gear me-1" aria-hidden="true"></i> ';
$content .= htmlspecialchars($this->t('welcome_admin_link'));
$content .= '</a>';
$content .= '<a href="' . htmlspecialchars($guideUrl) . '" class="btn btn-outline-secondary">';
$content .= '<i class="bi bi-book me-1" aria-hidden="true"></i> ';
$content .= htmlspecialchars($this->t('welcome_guide_link'));
$content .= '</a>';
$content .= '</div>';
$content .= '</div>';
return [
'title' => $this->t('welcome_title'),
'content' => $content,
'layout' => 'full_content',
'metadata' => [],
];
}
/**
* Get guide page content based on user language
*
@@ -1228,9 +1298,17 @@ class CodePressCMS {
* @return array 404 page data
*/
private function getError404() {
$staticFile = __DIR__ . '/../../../admin/static/404.html';
$body = file_exists($staticFile)
? file_get_contents($staticFile)
: '<h1>404 - ' . $this->t('page_not_found') . '</h1><p>' . $this->t('page_not_found_text') . '</p>';
return [
'title' => $this->t('page_not_found'),
'content' => '<h1>404 - ' . $this->t('page_not_found') . '</h1><p>' . $this->t('page_not_found_text') . '</p>'
'content' => $body,
'layout' => 'full_content',
'metadata' => [],
'is_404' => true,
];
}
@@ -1252,6 +1330,11 @@ class CodePressCMS {
$page = $this->getPage();
$this->pluginManager->doAction('onPageLoad', $page);
$this->pluginManager->doAction('onBeforeRender');
// Set 404 status for not-found pages (rendered through the theme)
if (!empty($page['is_404'])) {
http_response_code(404);
}
$menu = $this->getMenu();