From 03a14126ca82decef5ab937128e5eccf49406d9d Mon Sep 17 00:00:00 2001 From: Edwin Noorlander Date: Tue, 11 Aug 2026 17:04:27 +0200 Subject: [PATCH] Plugin sidebar order + directory layout from index.md - PluginManager: iterate allowedPlugins in user-defined order (frontmatter order) - content-edit.twig: plugin list with up/down arrows to set order - Directory listing: read layout/plugins from index.md if present - Directory default layout: full_content (no sidebar) unless index.md says otherwise --- .../default/views/pages/content-edit.twig | 62 ++++++++++++++-- cms/core/class/CodePressCMS.php | 15 +++- cms/core/plugin/PluginManager.php | 74 +++++++++++++------ plugins/HTMLBlock/HTMLBlock.php | 25 ++++++- 4 files changed, 143 insertions(+), 33 deletions(-) diff --git a/admin/theme/default/views/pages/content-edit.twig b/admin/theme/default/views/pages/content-edit.twig index c81a047..7d4396a 100644 --- a/admin/theme/default/views/pages/content-edit.twig +++ b/admin/theme/default/views/pages/content-edit.twig @@ -29,13 +29,33 @@ {% if availablePlugins is not empty %}
- -
- {% for plugin in availablePlugins %} - - + +
    + {% for plugin in selectedPlugins %} +
  • +
    + + +
    +
    + + +
    +
  • {% endfor %} -
+ {% for plugin in availablePlugins if plugin not in selectedPlugins %} +
  • +
    + + +
    +
    + + +
    +
  • + {% endfor %} +
    {% endif %} {% endif %} @@ -119,6 +139,36 @@ document.addEventListener('DOMContentLoaded', function () { } window.__onContentChange = markChanged; + + // Plugin order: move list items up/down + var pluginList = document.getElementById('plugin-order-list'); + if (pluginList) { + pluginList.addEventListener('click', function (e) { + var upBtn = e.target.closest('.plugin-up'); + var downBtn = e.target.closest('.plugin-down'); + if (!upBtn && !downBtn) return; + + var item = e.target.closest('li[data-plugin]'); + if (!item) return; + + if (upBtn && item.previousElementSibling) { + pluginList.insertBefore(item, item.previousElementSibling); + markChanged(); + } else if (downBtn && item.nextElementSibling) { + pluginList.insertBefore(item, item.nextElementSibling.nextElementSibling); + markChanged(); + } + }); + + // On form submit, reorder the checkboxes to match the visual order + var form = document.getElementById('editor-form'); + if (form) { + form.addEventListener('submit', function () { + // The DOM order of the
  • elements already determines the form submission order + // because the checkboxes are inside the
  • elements + }); + } + } }); {% endblock %} diff --git a/cms/core/class/CodePressCMS.php b/cms/core/class/CodePressCMS.php index 8f8c6e7..6a95e47 100644 --- a/cms/core/class/CodePressCMS.php +++ b/cms/core/class/CodePressCMS.php @@ -1141,9 +1141,22 @@ class CodePressCMS { $content .= '

    ' . $this->t('directory_empty') . '.

    '; } + // Check for index.md in this directory for layout/plugins metadata + $indexFile = $dirPath . '/index.md'; + $layout = 'full_content'; + $metadata = []; + if (file_exists($indexFile)) { + $indexContent = file_get_contents($indexFile); + $parsed = $this->parseMetadata($indexContent); + $metadata = $parsed['metadata']; + $layout = $metadata['layout'] ?? 'full_content'; + } + return [ 'title' => $title, - 'content' => $content + 'content' => $content, + 'layout' => $layout, + 'metadata' => $metadata, ]; } diff --git a/cms/core/plugin/PluginManager.php b/cms/core/plugin/PluginManager.php index 0d2241e..94bdbd9 100644 --- a/cms/core/plugin/PluginManager.php +++ b/cms/core/plugin/PluginManager.php @@ -140,28 +140,27 @@ class PluginManager public function getSidebarContent(?array $allowedPlugins = null): string { $sidebarContent = ''; - - foreach ($this->plugins as $pluginName => $plugin) { - if (!$this->isPluginViewable($plugin) || !method_exists($plugin, 'getSidebarContent')) { - continue; - } - - 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 .= ' + + // If allowedPlugins is specified, iterate in that order (user-defined order) + if ($allowedPlugins !== null) { + foreach ($allowedPlugins as $pluginName) { + $plugin = $this->plugins[$pluginName] ?? null; + if (!$plugin || !$this->isPluginViewable($plugin) || !method_exists($plugin, 'getSidebarContent')) { + 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) . '
    @@ -170,8 +169,37 @@ class PluginManager ' . $content . '
    '; + } + } else { + // No filter — show all viewable plugins in load order + foreach ($this->plugins as $pluginName => $plugin) { + if (!$this->isPluginViewable($plugin) || !method_exists($plugin, 'getSidebarContent')) { + 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/plugins/HTMLBlock/HTMLBlock.php b/plugins/HTMLBlock/HTMLBlock.php index 2dc4936..c8e13a3 100644 --- a/plugins/HTMLBlock/HTMLBlock.php +++ b/plugins/HTMLBlock/HTMLBlock.php @@ -22,6 +22,8 @@ class HTMLBlock $currentPage = $this->api ? $this->api->getCurrentPageTitle() : 'Onbekend'; $isHomepage = $this->api ? $this->api->isHomepage() : false; $currentLang = $this->api ? $this->api->getCurrentLanguage() : 'nl'; + $currentPath = $_GET['page'] ?? ''; + $currentPath = preg_replace('/\.(md|php|html)$/', '', $currentPath); $content = '

    Huidige pagina: ' . htmlspecialchars($currentPage) . '

    @@ -42,7 +44,7 @@ class HTMLBlock '; } - // Add quick navigation + // Add dynamic quick navigation $menu = $this->api->getMenu(); if (!empty($menu)) { $content .= ' @@ -51,8 +53,25 @@ class HTMLBlock foreach ($menu as $item) { if ($item['type'] === 'file') { - $url = $this->api->createUrl($item['path']); - $content .= '
  • 📄 ' . htmlspecialchars($item['title']) . '
  • '; + $url = '/' . $currentLang . '/' . $item['path']; + $isActive = ($item['path'] === $currentPath) ? ' fw-bold' : ''; + $content .= '
  • ' . htmlspecialchars($item['title'], ENT_QUOTES, 'UTF-8') . '
  • '; + } elseif ($item['type'] === 'folder' && !empty($item['children'])) { + $url = '/' . $currentLang . '/' . $item['path']; + $isActive = strpos($currentPath, $item['path']) === 0 ? ' fw-bold' : ''; + $content .= '
  • ' . htmlspecialchars($item['title'], ENT_QUOTES, 'UTF-8') . '
  • '; + // Show children if current page is in this folder + if (strpos($currentPath, $item['path']) === 0) { + $content .= ''; + } } }