diff --git a/AGENTS.md b/AGENTS.md index 6673f05..df99184 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -13,7 +13,7 @@ ## Project Structuur ``` codepress/ -├── engine/ +├── cms/ # Core CMS engine │ ├── core/ │ │ ├── class/ │ │ │ ├── CodePressCMS.php # Hoofd CMS class @@ -25,16 +25,17 @@ codepress/ │ │ ├── config.php # Config loader (leest config.json) │ │ └── index.php # Bootstrap (autoloader, requires) │ ├── lang/ # Taalbestanden (nl.php, en.php) -│ └── templates/ # Mustache templates -│ ├── layout.mustache # Hoofd layout (bevat inline CSS) -│ ├── assets/ -│ │ ├── header.mustache -│ │ ├── navigation.mustache -│ │ └── footer.mustache -│ ├── markdown_content.mustache -│ ├── php_content.mustache -│ └── html_content.mustache -├── admin-console/ # Admin paneel +│ ├── templates/ # Mustache templates +│ │ ├── layout.mustache # Hoofd layout (bevat inline CSS) +│ │ ├── assets/ +│ │ │ ├── header.mustache +│ │ │ ├── navigation.mustache +│ │ │ └── footer.mustache +│ │ ├── markdown_content.mustache +│ │ ├── php_content.mustache +│ │ └── html_content.mustache +│ └── router.php # PHP dev server router +├── admin/ # Admin paneel │ ├── config/ │ │ ├── app.php # Admin app configuratie │ │ └── admin.json # Gebruikers & security (file-based) @@ -48,10 +49,18 @@ codepress/ │ │ ├── content.php │ │ ├── content-edit.php │ │ ├── content-new.php +│ │ ├── content-dir-form.php │ │ ├── config.php │ │ ├── plugins.php +│ │ ├── plugin-config.php │ │ └── users.php │ └── storage/logs/ # Admin logs +├── cli/ # CLI scripts & tests +│ └── test/ +│ ├── accessibility.sh # WCAG 2.1 AA test suite +│ ├── enhanced-suite.sh # Enhanced test suite +│ ├── functional/ # Functionele testen +│ └── pentest/ # Penetratietesten ├── plugins/ # CMS plugins │ ├── HTMLBlock/ │ └── MQTTTracker/ @@ -61,8 +70,8 @@ codepress/ │ └── admin.php # Admin entry point + router ├── content/ # Content bestanden ├── guide/ # Handleidingen (nl/en) +├── docs/ # Documentatie ├── config.json # Site configuratie -├── TODO.md # Openstaande verbeteringen └── AGENTS.md # Dit bestand ``` @@ -70,12 +79,12 @@ codepress/ - **PHP Standards**: Follow PSR-12. Use 4 spaces for indentation. - **Naming**: Classes `PascalCase` (e.g., `CodePressCMS`), methods `camelCase` (e.g., `renderMenu`), variables `camelCase`, config keys `snake_case`. - **Architecture**: - - Core CMS logic in `engine/core/class/CodePressCMS.php` - - Bootstrap/requires in `engine/core/index.php` - - Configuration loaded from `config.json` via `engine/core/config.php` + - Core CMS logic in `cms/core/class/CodePressCMS.php` + - Bootstrap/requires in `cms/core/index.php` + - Configuration loaded from `config.json` via `cms/core/config.php` - Public website entry point: `public/index.php` - Admin entry point + routing: `public/admin.php` - - Admin authenticatie: `admin-console/src/AdminAuth.php` + - Admin authenticatie: `admin/src/AdminAuth.php` - **Content**: Stored in `content/`. Supports `.md` (Markdown), `.php` (Dynamic), `.html` (Static). - **Templating**: Mustache-style `{{placeholder}}` in `templates/layout.mustache` via `SimpleTemplate.php`. - **Navigation**: Auto-generated from directory structure. Folders require an index file to be clickable in breadcrumbs. @@ -87,11 +96,11 @@ codepress/ - **Git**: `main` is the clean CMS core. `development` is de actieve development branch. `e.noorlander` bevat persoonlijke content. Niet mixen. ## Admin Console -- **File-based**: Geen database. Gebruikers opgeslagen in `admin-console/config/admin.json` +- **File-based**: Geen database. Gebruikers opgeslagen in `admin/config/admin.json` - **Routing**: Via `?route=` parameter in `public/admin.php` -- **Routes**: `login`, `logout`, `dashboard`, `content`, `content-edit`, `content-new`, `content-delete`, `config`, `plugins`, `users` +- **Routes**: `login`, `logout`, `dashboard`, `content`, `content-edit`, `content-new`, `content-delete`, `config`, `plugins`, `plugins-new`, `plugins-edit`, `plugins-config`, `plugins-toggle`, `plugins-delete`, `users` - **Auth**: Session-based. `AdminAuth` class handelt login, logout, CSRF, brute-force lockout af -- **Templates**: Pure PHP templates in `admin-console/templates/pages/`. Layout in `layout.php` +- **Templates**: Pure PHP templates in `admin/templates/pages/`. Layout in `layout.php` ## Important: Title vs File/Directory Name Logic - **CRITICAL**: When user asks for "title" corrections, they usually mean **FILE/DIRECTORY NAME WITHOUT LANGUAGE PREFIX AND EXTENSIONS**, not the HTML title from content! @@ -107,4 +116,4 @@ codepress/ - LSP errors over "Undefined function" in PHP files zijn vals-positief (standaard PHP functies worden niet herkend door de LSP). Negeer deze. - Zie `TODO.md` voor alle openstaande verbeteringen en nieuwe features. - `vendor/` map bevat Composer dependencies (CommonMark, Mustache). Niet handmatig wijzigen. -- `admin-console/config/admin.json` bevat wachtwoord-hashes. Niet committen met echte productie-wachtwoorden. +- `admin/config/admin.json` bevat wachtwoord-hashes. Niet committen met echte productie-wachtwoorden. diff --git a/README.en.md b/README.en.md index 7e71ba6..e9ec189 100644 --- a/README.en.md +++ b/README.en.md @@ -30,7 +30,7 @@ A lightweight, file-based content management system built with PHP. ``` codepress/ -├── engine/ +├── cms/ # Core CMS engine │ ├── core/ │ │ ├── class/ │ │ │ ├── CodePressCMS.php # Main CMS class @@ -48,27 +48,27 @@ codepress/ │ ├── markdown_content.mustache │ ├── php_content.mustache │ └── html_content.mustache -├── admin-console/ # Admin panel +├── admin/ # Admin panel │ ├── config/ │ │ ├── app.php # Admin configuration │ │ └── admin.json # Users & security │ ├── src/ │ │ └── AdminAuth.php # Authentication service │ └── templates/ # Admin templates +├── cli/ # CLI scripts & tests +│ └── test/ ├── public/ # Web root │ ├── assets/ │ │ ├── css/ │ │ ├── js/ │ │ └── favicon.svg -│ ├── content/ # Content files -│ │ ├── nl.homepage.md # Dutch homepage -│ │ ├── en.homepage.md # English homepage -│ │ └── [lang].[page].md # Multi-language pages │ ├── index.php # Website entry point │ └── admin.php # Admin entry point +├── content/ # Content files +├── plugins/ # CMS plugins +├── docs/ # Documentation ├── config.json # Configuration -├── version.php # Version tracking -└── README.md # This file +└── README.md ``` ## ⚙️ Configuration diff --git a/README.md b/README.md index 88a1b0f..021824a 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ Een lichtgewicht, file-based content management systeem gebouwd met PHP. ``` codepress/ -├── engine/ +├── cms/ # Core CMS engine │ ├── core/ │ │ ├── config.php # Configuratie loader │ │ └── index.php # CMS engine @@ -43,18 +43,17 @@ codepress/ │ ├── markdown_content.mustache │ ├── php_content.mustache │ └── html_content.mustache -├── content/ # Content bestanden -│ ├── map1/ -│ │ ├── pagina1.md -│ │ └── pagina2.php -│ └── homepage.md -├── admin-console/ # Admin paneel +├── admin/ # Admin paneel │ ├── config/ │ │ ├── app.php # Admin configuratie │ │ └── admin.json # Gebruikers & security │ ├── src/ │ │ └── AdminAuth.php # Authenticatie service │ └── templates/ # Admin templates +├── cli/ # CLI scripts & tests +│ └── test/ +├── content/ # Content bestanden +├── plugins/ # CMS plugins ├── public/ # Web root │ ├── assets/ │ │ ├── css/ @@ -62,6 +61,7 @@ codepress/ │ │ └── favicon.svg │ ├── index.php # Website entry point │ └── admin.php # Admin entry point +├── docs/ # Documentatie ├── config.json # Configuratie └── README.md ``` @@ -74,7 +74,7 @@ codepress/ { "site_title": "CodePress", "content_dir": "content", - "templates_dir": "engine/templates", + "templates_dir": "cms/templates", "default_page": "auto", "homepage": "homepage", "author": { diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..9033959 --- /dev/null +++ b/TODO.md @@ -0,0 +1,6 @@ +# TODO + +## ✅ Voltooid +- Elk thema zit in zijn eigen map in de thema's map (`themes/naam/theme.json`) +- In admin → content: alle bestanden kunnen hernoemd worden via de edit-pagina +- In admin → content: bestanden en mappen kunnen verplaatst worden diff --git a/admin/config/app.php b/admin/config/app.php index 5bebf66..6377267 100644 --- a/admin/config/app.php +++ b/admin/config/app.php @@ -12,6 +12,7 @@ return [ 'content_dir' => __DIR__ . '/../../content/', 'config_json' => __DIR__ . '/../../config.json', 'plugins_dir' => __DIR__ . '/../../plugins/', + 'assets_dir' => __DIR__ . '/../../content/-assets/', 'admin_config' => __DIR__ . '/admin.json', 'log_file' => __DIR__ . '/../storage/logs/admin.log', ]; diff --git a/admin/templates/layout.php b/admin/templates/layout.php index 6a7f3d5..148cf9a 100644 --- a/admin/templates/layout.php +++ b/admin/templates/layout.php @@ -137,6 +137,9 @@ case 'content-dir-rename': require __DIR__ . '/pages/content-dir-form.php'; break; + case 'content-move': + require __DIR__ . '/pages/content-move-form.php'; + break; case 'users': require __DIR__ . '/pages/users.php'; break; diff --git a/admin/templates/pages/content-dir-form.php b/admin/templates/pages/content-dir-form.php new file mode 100644 index 0000000..0c9922a --- /dev/null +++ b/admin/templates/pages/content-dir-form.php @@ -0,0 +1,26 @@ +

Map hernoemen

+ +
+ + +
+
+ +

+
+
+ + +
Alleen letters, cijfers, punten, underscores en streepjes.
+
+ +
+ +
+ + +
diff --git a/admin/templates/pages/content-edit.php b/admin/templates/pages/content-edit.php index 96e92b5..7785609 100644 --- a/admin/templates/pages/content-edit.php +++ b/admin/templates/pages/content-edit.php @@ -1,27 +1,309 @@ -
-

- - Terug - -
+

-
+ -
-
- - +
+
+ +
+ + . +
+ Alleen letters, cijfers, punten, underscores en streepjes.
- + +
+ + +
+ +
+ +
+ + > + + +
+
+ +
-
+ +
+
+ +
+ +
- Annuleren + Terug
+ + + + + + + + + diff --git a/admin/templates/pages/content-move-form.php b/admin/templates/pages/content-move-form.php new file mode 100644 index 0000000..1ab7221 --- /dev/null +++ b/admin/templates/pages/content-move-form.php @@ -0,0 +1,34 @@ +

verplaatsen

+ +
+ + +
+
+ +

+ + +

+
+
+ + +
Selecteer de map waar het item naartoe verplaatst moet worden.
+
+ +
+ +
+ + +
diff --git a/admin/templates/pages/content-new.php b/admin/templates/pages/content-new.php index c6ec3b2..2e4173d 100644 --- a/admin/templates/pages/content-new.php +++ b/admin/templates/pages/content-new.php @@ -1,13 +1,8 @@ -
-

Nieuwe pagina

- - Terug - -
+

Nieuwe pagina

-
+
@@ -17,7 +12,7 @@
- @@ -29,18 +24,286 @@ Map:
-
- - +
+
+ + +
+ +
+ +
+ + + + +
+
+
-
- - Annuleren + Terug
+ + + + + diff --git a/admin/templates/pages/content.php b/admin/templates/pages/content.php index c0761bc..8085ed8 100644 --- a/admin/templates/pages/content.php +++ b/admin/templates/pages/content.php @@ -1,8 +1,34 @@

Content

- - Nieuw bestand - +
+ + + + Nieuw bestand + +
+
+ +
+
+
+
+ +
+ + + Toegestaan: JPG, PNG, GIF, WebP, SVG, PDF, ZIP, MP4, WebM, MP3, WAV +
+ +
+
+
@@ -39,7 +65,7 @@ Type Grootte Gewijzigd - Acties + Acties @@ -77,10 +103,26 @@ - + + + + + + + +
+ + +
+ + + +
+ + + diff --git a/admin/templates/pages/plugin-config.php b/admin/templates/pages/plugin-config.php new file mode 100644 index 0000000..1a69d16 --- /dev/null +++ b/admin/templates/pages/plugin-config.php @@ -0,0 +1,74 @@ +

Plugin Configuratie:

+ +
+ + +
+ +
Deze plugin heeft geen configureerbare instellingen.
+ + $value): ?> + + + +
+ + + + +
+ + + +'; + $html .= ''; + $html .= ''; + $html .= ''; + $html .= '
'; + } elseif (is_numeric($value)) { + $step = is_float($value) ? 'step="0.01"' : 'step="1"'; + $html .= '
'; + $html .= ''; + $html .= ''; + $html .= '
'; + } elseif (is_array($value)) { + $html .= '
'; + $html .= ''; + $html .= '
'; + $html .= '
'; + foreach ($value as $subKey => $subValue) { + $html .= renderConfigField($subKey, $subValue, $name); + } + $html .= '
'; + } else { + $html .= '
'; + $html .= ''; + + if (strlen($value) > 80 || str_contains($value, "\n")) { + $html .= ''; + } else { + $html .= ''; + } + + $html .= '
'; + } + + return $html; +} diff --git a/admin/templates/pages/plugins-edit.php b/admin/templates/pages/plugins-edit.php new file mode 100644 index 0000000..c2027f0 --- /dev/null +++ b/admin/templates/pages/plugins-edit.php @@ -0,0 +1,28 @@ +
+

Plugin bewerken:

+ + Terug + +
+ +
+
+
+ +
+ PHP + /.php +
+
+
+ +
+
+ + Annuleren +
+
+
+
diff --git a/admin/templates/pages/plugins-new.php b/admin/templates/pages/plugins-new.php new file mode 100644 index 0000000..77598c8 --- /dev/null +++ b/admin/templates/pages/plugins-new.php @@ -0,0 +1,40 @@ +

Nieuwe plugin aanmaken

+ +
+ + +
+ +
+ + +
+ + +
Alleen letters, cijfers en underscores. Begin met een hoofdletter. Wordt gebruikt als mapnaam, bestandsnaam en class naam.
+
+ +
+ + +
Wordt opgeslagen als README.md bij de plugin.
+
+ +
+ Wat wordt er aangemaakt? +
    +
  • plugins/PluginNaam/PluginNaam.php — Hoofdbestand met boilerplate
  • +
  • plugins/PluginNaam/config.json — Configuratiebestand
  • +
  • plugins/PluginNaam/README.md — Documentatie (alleen bij omschrijving)
  • +
+
+
+ + +
diff --git a/admin/templates/pages/plugins.php b/admin/templates/pages/plugins.php index af09503..045e326 100644 --- a/admin/templates/pages/plugins.php +++ b/admin/templates/pages/plugins.php @@ -1,4 +1,78 @@ -

Plugins

+
+

Plugins

+ + Nieuwe plugin + +
+ +
+
+
Plugin Ontwikkelaarshandleiding
+

Een plugin moet aan de volgende eisen voldoen om correct te werken:

+
+
+
+ +
+ Mapstructuur
+ plugins/Naam/Naam.php + Mapnaam en bestandsnaam moeten identiek zijn. +
+
+
+
+
+ +
+ Class naam
+ class PluginNaam + De class moet exact dezelfde naam hebben als de map. +
+
+
+
+
+ +
+ Optionele hooks
+ setAPI(CMSAPI) · getSidebarContent() + Voor CMS-toegang en sidebar-weergave. +
+
+
+
+
+ +
+ Configuratie (optioneel)
+ config.json + Wordt getoond met een configuratieformulier in de admin. +
+
+
+
+
+ +
+ Beveiliging
+ htmlspecialchars() + Altijd output escapen. Volg PSR-12. +
+
+
+
+
+ +
+ Documentatie (optioneel)
+ README.md + Aangeraden voor uitleg over de plugin. +
+
+
+
+
+
Geen plugins gevonden in de plugins map.
@@ -9,10 +83,10 @@
- - Actief + + Zichtbaar - Inactief + Systeem
@@ -36,6 +110,32 @@ +
+
+ + + + + +
+ + +
+ + + + + +
+
+ + +
+
diff --git a/admin/templates/pages/theme.php b/admin/templates/pages/theme.php new file mode 100644 index 0000000..79a8ab3 --- /dev/null +++ b/admin/templates/pages/theme.php @@ -0,0 +1,283 @@ + + + +
+

Bewerk thema:

+ + Terug + +
+ +
+
+
+ + + + +
+
+ + +
+
+ +
+
+
+
Header
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+
+
+
+
+
Navigatie
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+
+
+
+
+
Sidebar
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+
+
+
+ +
+
+
+
Hoogte balken
+
+
+ + +
+
+ + +
+
+
+
+
+
+
Header achtergrond afbeelding
+
+
+ + + Toegestaan: JPG, PNG, GIF, WebP, SVG +
+
+ +
+ +
+ +
+
+ Huidig: + +
+
+ + +
+
+ +
+
+ +
+ + % +
+ 100% = volledig zichtbaar, 50% = half doorzichtig, 0% = onzichtbaar +
+
+
+
+
+ +
+ + Annuleren +
+
+
+
+ + + + +
+

Thema's

+ +
+ +
+
+
+
+ + +
+ + +
+
+ +
+
+
+
+
+ +
+ $themeData): ?> +
+
+
+
+
+ + Actief + +
+ + +
+
+ Header: + + +
+
+ Navigatie: + + +
+
+ Sidebar: + + +
+
+ + +
+
+ Header: px · Navigatie: px +
+ +
+ Achtergrond: % zichtbaar + + + +
+ +
+ +
+ + Bewerken + + +
+ + + + +
+ + +
+ + + + +
+ +
+
+
+
+ +
+ + + + diff --git a/cli/test/functional/function-test.md b/cli/test/functional/function-test.md index acb4516..86ade96 100644 --- a/cli/test/functional/function-test.md +++ b/cli/test/functional/function-test.md @@ -333,7 +333,7 @@ This document outlines comprehensive functional tests for CodePress CMS to verif **Steps:** 1. Try accessing `/content/` directly -2. Try accessing `/engine/` files +2. Try accessing `/cms/` files 3. Try accessing `config.php` 4. Try accessing `/vendor/` diff --git a/cli/test/pentest/pentest.sh b/cli/test/pentest/pentest.sh index e50737a..0812320 100755 --- a/cli/test/pentest/pentest.sh +++ b/cli/test/pentest/pentest.sh @@ -133,7 +133,7 @@ test_vulnerability \ test_vulnerability \ "Path traversal - config access" \ - "$TARGET/?page=../engine/core/config" \ + "$TARGET/?page=../cms/core/config" \ "content_dir" \ "true" diff --git a/cms/core/class/CodePressCMS.php b/cms/core/class/CodePressCMS.php index 785ccf9..f6337d9 100644 --- a/cms/core/class/CodePressCMS.php +++ b/cms/core/class/CodePressCMS.php @@ -45,7 +45,7 @@ class CodePressCMS { $this->currentLanguage = $this->getCurrentLanguage(); $this->translations = $this->loadTranslations($this->currentLanguage); - // Initialize plugin manager (files already loaded in engine/core/index.php) + // Initialize plugin manager (files already loaded in cms/core/index.php) $this->pluginManager = new PluginManager(__DIR__ . '/../../../plugins'); $api = new CMSAPI($this); $this->pluginManager->setAPI($api); @@ -182,7 +182,10 @@ class CodePressCMS { $result = []; foreach ($items as $item) { - if ($item[0] === '.') continue; + if ($item[0] === '.' || $item[0] === '-') continue; + + // Skip assets directory (old name, kept for safety) + if ($item === 'assets' && is_dir($dir . '/' . $item)) continue; // Skip language-specific content that doesn't match current language $availableLangs = array_keys($this->getAvailableLanguages()); @@ -640,6 +643,12 @@ class CodePressCMS { * @return string Formatted display name */ private function formatDisplayName($filename) { + // Preserve leading dash before processing + $hasLeadingDash = $filename[0] === '-'; + if ($hasLeadingDash) { + $filename = substr($filename, 1); + } + // Remove language prefixes dynamically based on available languages $availableLangs = array_keys($this->getAvailableLanguages()); $langPattern = '/^(' . implode('|', $availableLangs) . ')\.(.+)$/'; @@ -656,11 +665,12 @@ class CodePressCMS { 'ict' => 'ICT', ]; if (isset($specialCases[strtolower($filename)])) { - return $specialCases[strtolower($filename)]; + return ($hasLeadingDash ? '- ' : '') . $specialCases[strtolower($filename)]; } // Replace hyphens and underscores with spaces, then title case $name = str_replace(['-', '_'], ' ', $filename); + $name = trim($name); $name = ucwords(strtolower($name)); // Post-process special cases in compound names @@ -668,7 +678,7 @@ class CodePressCMS { $name = str_ireplace(ucfirst($lower), $correct, $name); } - return $name; + return ($hasLeadingDash ? '- ' : '') . $name; } /** @@ -983,8 +993,12 @@ private function getGuidePage() { // Get homepage title $homepageTitle = $this->getHomepageTitle(); - // Get sidebar content from plugins - $sidebarContent = $this->pluginManager->getSidebarContent(); + // Get sidebar content from plugins (filtered per-page if specified in frontmatter) + $allowedPlugins = null; + if (!empty($page['metadata']['plugins'])) { + $allowedPlugins = array_map('trim', explode(',', $page['metadata']['plugins'])); + } + $sidebarContent = $this->pluginManager->getSidebarContent($allowedPlugins); // Get layout from page metadata $layout = $page['layout'] ?? 'sidebar-content'; @@ -994,7 +1008,7 @@ private function getGuidePage() { 'site_title' => $this->config['site_title'], 'page_title' => htmlspecialchars($page['title']), - 'content' => $page['content'], + 'content' => $this->processContent($page['content']), 'sidebar_content' => $sidebarContent, 'layout' => $layout, 'page_metadata' => $page['metadata'] ?? [], @@ -1017,10 +1031,14 @@ private function getGuidePage() { // Theme colors 'header_color' => $this->config['theme']['header_color'] ?? '#0d6efd', 'header_font_color' => $this->config['theme']['header_font_color'] ?? '#ffffff', + 'header_height' => $this->config['theme']['header_height'] ?? '56', 'navigation_color' => $this->config['theme']['navigation_color'] ?? '#f8f9fa', 'navigation_font_color' => $this->config['theme']['navigation_font_color'] ?? '#000000', + 'nav_height' => $this->config['theme']['nav_height'] ?? '42', 'sidebar_background' => $this->config['theme']['sidebar_background'] ?? '#f8f9fa', 'sidebar_border' => $this->config['theme']['sidebar_border'] ?? '#dee2e6', + 'background_image_css' => $this->getBackgroundImageCss(), + 'background_image_opacity' => $this->getBackgroundImageOpacity(), // Language 'current_lang' => $this->currentLanguage, 'current_lang_upper' => strtoupper($this->currentLanguage), @@ -1286,4 +1304,27 @@ private function getGuidePage() { } return false; } + + private function getBackgroundImageCss(): string + { + $bg = $this->config['theme']['background_image'] ?? ''; + if (empty($bg)) { + return 'none'; + } + if (str_starts_with($bg, 'http')) { + return 'url(' . $bg . ')'; + } + return 'url(/themes/' . $bg . ')'; + } + + private function getBackgroundImageOpacity(): int + { + $opacity = intval($this->config['theme']['background_image_opacity'] ?? 100); + return max(0, min(100, $opacity)); + } + + private function processContent(string $content): string + { + return str_replace('-/assets/', '/-assets/', $content); + } } \ No newline at end of file diff --git a/cms/core/config.php b/cms/core/config.php index b5ab40c..d799131 100644 --- a/cms/core/config.php +++ b/cms/core/config.php @@ -17,6 +17,17 @@ if (file_exists($configJsonPath)) { $config['templates_dir'] = $projectRoot . $config['templates_dir']; } + // Load active theme + $activeTheme = $config['active_theme'] ?? 'default'; + $themeDir = __DIR__ . '/../../themes/' . $activeTheme; + $themeFile = $themeDir . '/theme.json'; + if (file_exists($themeFile)) { + $themeConfig = json_decode(file_get_contents($themeFile), true); + $config['theme'] = $themeConfig; + } else { + $config['theme'] = []; + } + return $config; } } diff --git a/cms/core/plugin/PluginManager.php b/cms/core/plugin/PluginManager.php index c753aa8..04c45a8 100644 --- a/cms/core/plugin/PluginManager.php +++ b/cms/core/plugin/PluginManager.php @@ -16,7 +16,6 @@ class PluginManager { $this->api = $api; - // Inject API into all plugins that have setAPI method foreach ($this->plugins as $plugin) { if (method_exists($plugin, 'setAPI')) { $plugin->setAPI($api); @@ -43,7 +42,6 @@ class PluginManager if (class_exists($className)) { $this->plugins[$pluginName] = new $className(); - // Inject API if already available if ($this->api && method_exists($this->plugins[$pluginName], 'setAPI')) { $this->plugins[$pluginName]->setAPI($this->api); } @@ -62,14 +60,49 @@ class PluginManager return $this->plugins; } - public function getSidebarContent(): string + public function isPluginViewable(object $plugin): bool + { + if (method_exists($plugin, 'getConfig')) { + $config = $plugin->getConfig(); + return !isset($config['viewable']) || $config['viewable'] !== false; + } + return true; + } + + public function getSidebarContent(?array $allowedPlugins = null): string { $sidebarContent = ''; - foreach ($this->plugins as $plugin) { - if (method_exists($plugin, 'getSidebarContent')) { - $sidebarContent .= $plugin->getSidebarContent(); + foreach ($this->plugins as $pluginName => $plugin) { + if (!$this->isPluginViewable($plugin) || !method_exists($plugin, 'getSidebarContent')) { + continue; } + + // Filter by allowed plugins for this page + if ($allowedPlugins !== null && !in_array($pluginName, $allowedPlugins, true)) { + continue; + } + + $content = $plugin->getSidebarContent(); + if (trim($content) === '') { + continue; + } + + $title = 'Plugin'; + if (method_exists($plugin, 'getConfig')) { + $config = $plugin->getConfig(); + $title = $config['title'] ?? 'Plugin'; + } + + $sidebarContent .= ' +
+
+
' . htmlspecialchars($title) . '
+
+
+ ' . $content . ' +
+
'; } return $sidebarContent; diff --git a/cms/templates/assets/header.mustache b/cms/templates/assets/header.mustache index 5d06f95..b4b9bed 100644 --- a/cms/templates/assets/header.mustache +++ b/cms/templates/assets/header.mustache @@ -1,4 +1,4 @@ -