Update all guides (NL + EN) for CodePress 2.5.2 features
- Admin guide: RBAC roles, role-based dashboard, plugin types (content/system) - CodePress developer guide: plugin types, admin plugin API, SCSS compilation, asset serving - Theme developer guide: SCSS sole CSS source, css_compiled read-only, guide layout - Content manager guide: layout selection from theme.json, plugin order in frontmatter - Both NL and EN updated with identical structure - 35 files updated
This commit is contained in:
@@ -2,14 +2,14 @@
|
|||||||
|
|
||||||
The admin manager guide contains the following topics:
|
The admin manager guide contains the following topics:
|
||||||
|
|
||||||
- **Dashboard** - Website overview
|
- **Dashboard** - Role-based overview of the website (Admin, Content Manager, BI Manager, Site Admin)
|
||||||
- **Content management** - Managing files and pages
|
- **Content management** - Managing files and pages with layout selection and plugins
|
||||||
- **Configuration** - Site settings
|
- **Configuration** - Site settings (title, language, author, analytics, logging)
|
||||||
- **Theme management** - Managing and creating themes
|
- **Theme management** - Managing, activating and creating themes (SCSS compilation)
|
||||||
- **Security** - Bot protection and sessions
|
- **Security** - Bot protection, rate limiting and session settings
|
||||||
- **Plugins** - Managing and creating plugins
|
- **Plugins** - Managing plugins: content (sidebar) and system (admin menu/API)
|
||||||
- **Users** - Adding and removing users
|
- **Users** - User management with roles (Admin, Content Manager, BI Manager, Site Admin)
|
||||||
- **Statistics** - Viewing visitor statistics
|
- **Statistics** - Viewing and exporting visitor statistics
|
||||||
- **Logs** - Viewing and filtering log files
|
- **Logs** - Viewing and filtering log files
|
||||||
|
|
||||||
Select a topic from the navigation on the left.
|
Select a topic from the navigation on the left.
|
||||||
@@ -2,16 +2,45 @@
|
|||||||
|
|
||||||
## Managing files
|
## Managing files
|
||||||
|
|
||||||
- **Upload** - Upload media files
|
- **New folder** — Create folder structure
|
||||||
- **New folder** - Create folder structure
|
- **New file** — Create a page (`.md`, `.php`, `.html`)
|
||||||
- **New file** - Create a page
|
- **Edit** — Modify existing content in the CodeMirror editor
|
||||||
- **Edit** - Modify existing content
|
- **Rename** — Change file or folder names
|
||||||
- **Rename** - Change file names
|
- **Move** — Move content to another folder
|
||||||
- **Move** - Move content
|
- **Delete** — Remove content
|
||||||
- **Delete** - Remove content
|
- **Rename folder** — Change a folder name
|
||||||
|
|
||||||
## Editor
|
## Editor (content-edit)
|
||||||
|
|
||||||
- CodeMirror with syntax highlighting
|
- **CodeMirror** with syntax highlighting (Markdown, PHP, HTML)
|
||||||
- Toolbar for Markdown formatting
|
- **Toolbar** for quickly inserting Markdown
|
||||||
- Shortcuts: Ctrl+S (save), Ctrl+N (new)
|
- **Shortcuts**: Ctrl+S (save), Ctrl+N (new)
|
||||||
|
|
||||||
|
## Layout selection
|
||||||
|
|
||||||
|
On the content-edit page you can choose the layout from the layouts defined in `theme.json` (template mapping). The selected layout is stored in the frontmatter `layout:` key.
|
||||||
|
|
||||||
|
## Plugins on pages
|
||||||
|
|
||||||
|
- Content plugins (from `plugin.json` with `type: "content"`) appear in the plugin selection
|
||||||
|
- Choose which plugins appear in the sidebar
|
||||||
|
- **Order is adjustable** with up/down buttons
|
||||||
|
- The plugin order is stored in the frontmatter `plugins:` key
|
||||||
|
- Plugins are **hidden** when the chosen layout has no sidebar (e.g. `full_content`)
|
||||||
|
|
||||||
|
## Frontmatter
|
||||||
|
|
||||||
|
The editor updates the frontmatter live when layout or plugin selection changes:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
---
|
||||||
|
layout: left_sidebar
|
||||||
|
plugins:
|
||||||
|
- HTMLBlock
|
||||||
|
- Navigation
|
||||||
|
---
|
||||||
|
|
||||||
|
# Page title
|
||||||
|
|
||||||
|
Content...
|
||||||
|
```
|
||||||
@@ -1,10 +1,32 @@
|
|||||||
# Dashboard
|
# Dashboard
|
||||||
|
|
||||||
The dashboard shows an overview of:
|
The dashboard shows a **role-based overview** of the website. Which widgets are visible depends on the role of the logged-in user.
|
||||||
|
|
||||||
- Views (30 days)
|
## Roles and widgets
|
||||||
- Unique visitors
|
|
||||||
|
### Admin
|
||||||
|
- Views (30 days) and unique visitors
|
||||||
- Number of pages and folders
|
- Number of pages and folders
|
||||||
- Active plugins
|
- Active plugins
|
||||||
- Recent activity
|
- Recent activity
|
||||||
- Quick actions
|
- System information
|
||||||
|
- Quick actions (new page, plugin, theme)
|
||||||
|
|
||||||
|
### Content Manager
|
||||||
|
- Number of pages and folders
|
||||||
|
- Recent content changes
|
||||||
|
- Quick actions (new page, folder)
|
||||||
|
|
||||||
|
### BI Manager
|
||||||
|
- Views (30 days) and unique visitors
|
||||||
|
- Top pages
|
||||||
|
- Recent visits
|
||||||
|
|
||||||
|
### Site Admin
|
||||||
|
- Active plugins and themes
|
||||||
|
- System information
|
||||||
|
- Quick actions (theme, plugin, update)
|
||||||
|
|
||||||
|
## Access
|
||||||
|
|
||||||
|
The dashboard is the default page after login (`/admin/dashboard`). All roles have access to the dashboard.
|
||||||
@@ -1,13 +1,40 @@
|
|||||||
# Users
|
# Users
|
||||||
|
|
||||||
## Add user
|
Users are stored in `admin/config/admin.json` (file-based, no database). Each user has a **role** that determines which admin routes and sidebar items are visible.
|
||||||
|
|
||||||
|
## Roles
|
||||||
|
|
||||||
|
CodePress has four roles, defined in `AdminAuth::ROLE_PERMISSIONS`:
|
||||||
|
|
||||||
|
| Role | Label | Permissions |
|
||||||
|
|------|-------|-------------|
|
||||||
|
| `admin` | Admin | Everything (`*`) |
|
||||||
|
| `content-manager` | Content Manager | Content management, guide |
|
||||||
|
| `bi-manager` | BI Manager | Statistics, logs, guide |
|
||||||
|
| `site-admin` | Site Admin | Theme, plugins, statistics, logs, update, guide |
|
||||||
|
|
||||||
|
Roles are displayed with their label via `AdminAuth::ROLE_LABELS`.
|
||||||
|
|
||||||
|
## Adding a user
|
||||||
|
|
||||||
1. Go to **Users**
|
1. Go to **Users**
|
||||||
2. Enter username
|
2. Enter username
|
||||||
3. Choose password
|
3. Choose password (stored as bcrypt hash)
|
||||||
4. Click **Add**
|
4. Select a role
|
||||||
|
5. Click **Add**
|
||||||
|
|
||||||
## Delete user
|
## Editing a user
|
||||||
|
|
||||||
- Cannot delete own account
|
- Change password (new bcrypt hash)
|
||||||
|
- Change role (immediately affects visible routes and sidebar items)
|
||||||
|
|
||||||
|
## Deleting a user
|
||||||
|
|
||||||
|
- Not possible for own account
|
||||||
- Confirm with password
|
- Confirm with password
|
||||||
|
|
||||||
|
## Access control
|
||||||
|
|
||||||
|
- Route access is checked in `public/admin.php` via `AdminAuth::hasPermission()`
|
||||||
|
- Unauthorized routes return a **403 error**
|
||||||
|
- Sidebar items are conditionally shown via the `has_permission()` Twig function in `admin.twig`
|
||||||
@@ -1,15 +1,49 @@
|
|||||||
# Plugins
|
# Plugins
|
||||||
|
|
||||||
|
## Plugin types
|
||||||
|
|
||||||
|
CodePress has two kinds of plugins, determined by the `type` field in `plugin.json`:
|
||||||
|
|
||||||
|
- **Content plugins** (`type: "content"`) — Appear in the sidebar and in the plugin selection on content-edit pages. Provide sidebar content via `getSidebarContent()`.
|
||||||
|
- **System plugins** (`type: "system"`) — Are loaded by PluginManager but do NOT appear in the sidebar. Provide functionality via admin menu, routes and the CMSAPI. Registered via `getAdminMenu()` and `getAdminRoutes()`.
|
||||||
|
|
||||||
|
When no `type` field is present, `content` is assumed.
|
||||||
|
|
||||||
|
## Essential plugins
|
||||||
|
|
||||||
|
Essential plugins are defined in `getProtectedPlugins()` in `public/admin.php`. Current essential plugin: **Navigation**.
|
||||||
|
|
||||||
|
These plugins:
|
||||||
|
- Cannot be deactivated
|
||||||
|
- Cannot be edited
|
||||||
|
- Cannot be deleted
|
||||||
|
|
||||||
|
On the plugins page they get an **Essential** badge instead of the action buttons.
|
||||||
|
|
||||||
## Managing plugins
|
## Managing plugins
|
||||||
|
|
||||||
- **Enable/Disable** - Turn plugins on/off
|
- **Activate/Deactivate** — Turn a plugin on/off (not for essential plugins)
|
||||||
- **Edit** - Modify plugin code
|
- **Edit** — Modify plugin code in CodeMirror (not for essential plugins)
|
||||||
- **Configuration** - Plugin settings
|
- **Configuration** — Edit plugin settings
|
||||||
- **Delete** - Remove plugin
|
- **Delete** — Remove the plugin folder (not for essential plugins)
|
||||||
|
|
||||||
## New plugin
|
The admin plugins page shows a **Content** or **System** badge per plugin.
|
||||||
|
|
||||||
|
## Creating a new plugin
|
||||||
|
|
||||||
1. Go to **Plugins** → **New plugin**
|
1. Go to **Plugins** → **New plugin**
|
||||||
2. Enter a name (e.g. `MyPlugin`)
|
2. Enter a name (e.g. `MyPlugin`) — this becomes the folder name
|
||||||
3. Edit `plugin.php`
|
3. Choose the type: **Content** or **System**
|
||||||
4. Enable the plugin
|
4. The file `MyPlugin.php` is created (NOT `plugin.php`)
|
||||||
|
5. Edit the plugin code in CodeMirror
|
||||||
|
6. Activate the plugin
|
||||||
|
|
||||||
|
## Plugin filename
|
||||||
|
|
||||||
|
Plugin PHP files are named `<PluginName>.php` (e.g. `Navigation.php`, `HTMLBlock.php`). `PluginManager` loads `$pluginDir . '/' . $pluginName . '.php'`.
|
||||||
|
|
||||||
|
## Plugin CSS
|
||||||
|
|
||||||
|
- Content and system plugins can have their own CSS in `assets/scss/` and `assets/css/`
|
||||||
|
- Plugin CSS is automatically loaded after theme CSS (in `base.twig`), so themes can override plugin styling
|
||||||
|
- Plugin assets are served via `cms/router.php` at URL `/plugins/<Name>/assets/...`
|
||||||
@@ -2,20 +2,65 @@
|
|||||||
|
|
||||||
## Managing themes
|
## Managing themes
|
||||||
|
|
||||||
1. Go to **Theme** in admin menu
|
1. Go to **Theme** in the admin menu
|
||||||
2. **Activate** - Choose active theme
|
2. **Activate** — Choose the active theme (stored in `config.json`)
|
||||||
3. **Compile SCSS** - Process SCSS to CSS
|
3. **Compile SCSS** — Process SCSS to CSS (forced)
|
||||||
4. **New theme** - Create custom theme
|
4. **New theme** — Create a custom theme via admin or manually
|
||||||
|
|
||||||
## Theme structure
|
## Theme structure
|
||||||
|
|
||||||
```
|
```
|
||||||
themes/default/
|
themes/default/
|
||||||
├── theme.json # Theme configuration
|
├── theme.json # { title, config.default_template, template: layout→.twig }
|
||||||
├── base.twig # Main layout
|
├── base.twig # Main layout (head, header, nav, breadcrumb, footer)
|
||||||
├── full_content.twig # Layouts
|
├── full_content.twig # Layout: full width
|
||||||
├── left_sidebar.twig
|
├── left_sidebar.twig # Layout: sidebar on the left
|
||||||
├── right_sidebar.twig
|
├── right_sidebar.twig # Layout: sidebar on the right
|
||||||
├── partials/ # Header, nav, footer
|
├── custom1.twig # Layout: custom
|
||||||
└── assets/ # CSS, JS, images
|
├── guide.twig # Layout: guide with sidebar (Navigation plugin)
|
||||||
|
├── partials/ # header.twig, navigation.twig, footer.twig
|
||||||
|
└── assets/
|
||||||
|
├── scss/theme.scss # SCSS source (only CSS source — manual css/theme.css must not exist)
|
||||||
|
├── css_compiled/ # Generated by scssphp (read-only, do not edit manually)
|
||||||
|
├── css/ # External CSS (bootstrap.min.css, bootstrap-icons.css, mobile.css)
|
||||||
|
├── js/ # app.js, bootstrap.bundle.min.js
|
||||||
|
├── fonts/ # bootstrap-icons.woff, woff2
|
||||||
|
└── img/ # favicon, icon, world-map
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## theme.json
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"title": "default",
|
||||||
|
"config": {
|
||||||
|
"default_template": "full_content"
|
||||||
|
},
|
||||||
|
"template": {
|
||||||
|
"full_content": "full_content.twig",
|
||||||
|
"left_sidebar": "left_sidebar.twig",
|
||||||
|
"right_sidebar": "right_sidebar.twig",
|
||||||
|
"custom1": "custom1.twig",
|
||||||
|
"guide": "guide.twig"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- `title` — Display name in admin
|
||||||
|
- `config.default_template` — Default layout for pages without a `layout:` frontmatter
|
||||||
|
- `template` — Mapping from layout name to `.twig` file
|
||||||
|
|
||||||
|
## SCSS compilation
|
||||||
|
|
||||||
|
- `ThemeManager` compiles `assets/scss/theme.scss` at runtime to `assets/css_compiled/theme.css` via scssphp
|
||||||
|
- `css_compiled/` is **read-only** — do not edit manually
|
||||||
|
- `assets/css/theme.css` must **not** exist; otherwise `ThemeManager::getCssUrl()` ignores the SCSS
|
||||||
|
- After SCSS changes: remove `assets/css_compiled/theme.css` and `.mtime` to force recompilation
|
||||||
|
|
||||||
|
## Layouts
|
||||||
|
|
||||||
|
Layouts are chosen via the frontmatter `layout:` key in content files. Unknown layouts fall back to `config.default_template` from `theme.json`.
|
||||||
|
|
||||||
|
## guide.twig
|
||||||
|
|
||||||
|
Special layout for guides. Injects the Navigation plugin into the sidebar for sidebar navigation. Automatically used for pages in the `guide/` folder.
|
||||||
@@ -2,13 +2,20 @@
|
|||||||
|
|
||||||
The CodePress developer guide contains the following topics:
|
The CodePress developer guide contains the following topics:
|
||||||
|
|
||||||
- **Architecture** - CMS architecture and folder structure
|
- **Architecture** — CMS architecture and folder structure
|
||||||
- **Core classes** - CodePressCMS, ThemeManager, PluginManager
|
- **Core classes** — CodePressCMS, ThemeManager, PluginManager, AdminAuth
|
||||||
- **Plugin development** - Developing plugins
|
- **Plugin development** — Plugin types (content/system), structure, API
|
||||||
- **Routing** - Frontend and admin routing
|
- **Routing** — Frontend, admin and plugin admin routing
|
||||||
- **Security** - XSS, CSRF, path traversal
|
- **Security** — XSS, CSRF, path traversal, RBAC
|
||||||
- **Testing** - Penetration, accessibility and functional tests
|
- **Testing** — Penetration, accessibility and functional tests
|
||||||
- **Debugging** - Logging and cache
|
- **Debugging** — Logging and cache
|
||||||
- **Performance** - OPcache and SCSS caching
|
- **Performance** — OPcache and SCSS caching
|
||||||
|
|
||||||
|
Important concepts in CodePress 2.5.2:
|
||||||
|
|
||||||
|
- **Plugin types** — Content plugins (sidebar) and system plugins (admin menu, routes, API)
|
||||||
|
- **Admin plugin API** — System plugins can register admin menu items and routes
|
||||||
|
- **SCSS compilation** — `ThemeManager` compiles SCSS to `css_compiled/` via scssphp (read-only)
|
||||||
|
- **Asset serving** — `public/asset.php` serves themes/, admin/assets/ and plugins/ on Apache (instead of PHP dev router)
|
||||||
|
|
||||||
Select a topic from the navigation on the left.
|
Select a topic from the navigation on the left.
|
||||||
@@ -1,11 +1,84 @@
|
|||||||
# CMS Architecture
|
# CMS Architecture
|
||||||
|
|
||||||
|
CodePress is a file-based CMS without a database. Content, configuration and users are stored in files.
|
||||||
|
|
||||||
|
## Folder structure
|
||||||
|
|
||||||
```
|
```
|
||||||
codepress/
|
codepress/
|
||||||
├── cms/core/ # Core engine
|
├── cms/ # Core CMS engine
|
||||||
├── admin/ # Admin console
|
│ ├── core/
|
||||||
├── themes/ # Themes
|
│ │ ├── class/
|
||||||
├── plugins/ # Plugins
|
│ │ │ ├── CodePressCMS.php # Main CMS class (routing, rendering, breadcrumb)
|
||||||
├── content/ # Content
|
│ │ │ ├── ThemeManager.php # Theme resolver + Twig render + SCSS compile
|
||||||
└── public/ # Web root
|
│ │ │ ├── ContentAPI.php # Read-only API for PHP content
|
||||||
|
│ │ │ ├── ContentSecurityPolicy.php # CSP header management
|
||||||
|
│ │ │ ├── Analytics.php # Visitor statistics
|
||||||
|
│ │ │ ├── BotGuard.php # Bot/AI detection
|
||||||
|
│ │ │ ├── Cache.php # Cache system
|
||||||
|
│ │ │ ├── GeoIP.php # GeoIP lookup (country, flag)
|
||||||
|
│ │ │ ├── Logger.php # Basic logging
|
||||||
|
│ │ │ ├── LogManager.php # Dynamic logging (SQLite/syslog)
|
||||||
|
│ │ │ ├── RateLimiter.php # Rate limiting per IP
|
||||||
|
│ │ │ ├── RequestLogger.php # Request logging + visitor info
|
||||||
|
│ │ │ ├── SearchEngine.php # Full text search
|
||||||
|
│ │ │ └── AccessibilityManager.php # Accessibility features
|
||||||
|
│ │ ├── plugin/
|
||||||
|
│ │ │ ├── PluginManager.php # Plugin loader (hooks, filters, sidebar, admin routes)
|
||||||
|
│ │ │ └── CMSAPI.php # API for plugins (getPage, getConfig, etc.)
|
||||||
|
│ │ ├── config.php # Config loader (reads config.json)
|
||||||
|
│ │ └── index.php # Bootstrap (autoloader, requires)
|
||||||
|
│ ├── lang/ # Language files (nl.php, en.php)
|
||||||
|
│ └── router.php # PHP dev server router
|
||||||
|
├── themes/ # Dynamic themes
|
||||||
|
│ └── default/ # Default theme (views + assets)
|
||||||
|
│ ├── theme.json # { title, config.default_template, template: layout→.twig }
|
||||||
|
│ ├── base.twig # Main layout
|
||||||
|
│ ├── *.twig # Layout templates
|
||||||
|
│ ├── partials/ # header.twig, navigation.twig, footer.twig
|
||||||
|
│ └── assets/
|
||||||
|
│ ├── scss/theme.scss # SCSS source (only CSS source)
|
||||||
|
│ ├── css_compiled/ # Generated by scssphp (read-only)
|
||||||
|
│ ├── css/ # External CSS (bootstrap.min.css, etc.)
|
||||||
|
│ ├── js/ # JavaScript
|
||||||
|
│ └── img/ # Images
|
||||||
|
├── admin/ # Admin panel
|
||||||
|
│ ├── config/
|
||||||
|
│ │ ├── app.php # Admin app configuration
|
||||||
|
│ │ └── admin.json # Users & security (file-based, .gitignore'd)
|
||||||
|
│ ├── src/
|
||||||
|
│ │ └── AdminAuth.php # Authentication + RBAC
|
||||||
|
│ ├── theme/default/ # Admin theme (views + assets)
|
||||||
|
│ │ ├── theme.json
|
||||||
|
│ │ ├── assets/ # CSS, JS, CodeMirror, fonts
|
||||||
|
│ │ └── views/ # login.twig, layouts/, pages/
|
||||||
|
│ └── storage/ # Logs, cache, geoip
|
||||||
|
├── plugins/ # CMS plugins
|
||||||
|
│ ├── Navigation/ # Essential navigation plugin (protected)
|
||||||
|
│ │ ├── Navigation.php # Plugin code (NOT plugin.php)
|
||||||
|
│ │ ├── plugin.json # Metadata with type field
|
||||||
|
│ │ └── assets/ # SCSS + CSS
|
||||||
|
│ └── HTMLBlock/ # Example sidebar plugin
|
||||||
|
├── content/ # Website content (.md, .php, .html) — .gitignore'd
|
||||||
|
├── guide/ # Guides (nl/en)
|
||||||
|
├── public/ # Web root
|
||||||
|
│ ├── index.php # Website entry point
|
||||||
|
│ ├── admin.php # Admin entry point + routing
|
||||||
|
│ ├── asset.php # Asset server for Apache (themes/, admin/assets/, plugins/)
|
||||||
|
│ ├── .htaccess # Forwards asset URLs to asset.php
|
||||||
|
│ ├── favicon.ico
|
||||||
|
│ └── robots.txt
|
||||||
|
├── var/ # Cache (twig) — .gitignore'd
|
||||||
|
├── config.json # Site configuration — .gitignore'd
|
||||||
|
├── composer.json # PHP dependencies (CommonMark, Twig, scssphp)
|
||||||
|
└── version.php # Version information (2.5.2)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Principles
|
||||||
|
|
||||||
|
- **No database** — Everything in files (content in `content/`, users in `admin/config/admin.json`, config in `config.json`)
|
||||||
|
- **File-based auth** — `AdminAuth` uses bcrypt hashes in `admin.json`, sessions for login
|
||||||
|
- **Twig templating** — Themes use Twig; `ThemeManager` renders via Twig
|
||||||
|
- **SCSS compilation** — `assets/scss/theme.scss` → `assets/css_compiled/theme.css` via scssphp (read-only output)
|
||||||
|
- **Plugin system** — `PluginManager` loads content and system plugins with hooks/filters
|
||||||
|
- **Asset serving** — PHP dev router (`cms/router.php`) or Apache (`.htaccess` → `public/asset.php`)
|
||||||
@@ -10,6 +10,13 @@ $cms->init();
|
|||||||
$cms->renderPage($pagePath);
|
$cms->renderPage($pagePath);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Responsibilities:
|
||||||
|
- Routing and page rendering
|
||||||
|
- Breadcrumb generation (dynamic: Home > [subfolders] > [page])
|
||||||
|
- Loading guide pages (`getGuidePage()`)
|
||||||
|
- Title extraction from H1 (`getTitleFromFile()`)
|
||||||
|
- Display name processing (`formatDisplayName()`)
|
||||||
|
|
||||||
## ThemeManager.php
|
## ThemeManager.php
|
||||||
|
|
||||||
Theme management in `cms/core/class/ThemeManager.php`:
|
Theme management in `cms/core/class/ThemeManager.php`:
|
||||||
@@ -19,14 +26,84 @@ $themeManager = new ThemeManager($config);
|
|||||||
$themeManager->getActiveTheme();
|
$themeManager->getActiveTheme();
|
||||||
$themeManager->renderTwig($template, $data);
|
$themeManager->renderTwig($template, $data);
|
||||||
$themeManager->compileCss($force);
|
$themeManager->compileCss($force);
|
||||||
|
$themeManager->getCssUrl();
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Responsibilities:
|
||||||
|
- Resolving the active theme from `config.json`
|
||||||
|
- Loading `theme.json` (title, config.default_template, template mapping)
|
||||||
|
- Building the Twig environment (rooted in the theme folder)
|
||||||
|
- **SCSS compilation** — compiles `assets/scss/theme.scss` to `assets/css_compiled/theme.css` via scssphp
|
||||||
|
- Resolving the layout to a `.twig` template (fallback to `config.default_template`)
|
||||||
|
|
||||||
|
`getCssUrl()` priority: 1) `assets/css/theme.css` (manual), 2) `assets/css_compiled/theme.css` (compiled).
|
||||||
|
|
||||||
## PluginManager.php
|
## PluginManager.php
|
||||||
|
|
||||||
Plugin system in `cms/core/class/PluginManager.php`:
|
Plugin system in `cms/core/plugin/PluginManager.php`:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
$pluginManager = new PluginManager();
|
$pluginManager = new PluginManager($pluginsPath, $enabledPlugins);
|
||||||
$pluginManager->loadPlugins($enabledPlugins);
|
$pluginManager->getSidebarContent($allowedPlugins);
|
||||||
|
$pluginManager->getPluginCssUrls();
|
||||||
$pluginManager->executeHook($name, $params);
|
$pluginManager->executeHook($name, $params);
|
||||||
|
$pluginManager->getAdminMenuItems();
|
||||||
|
$pluginManager->handleAdminRoute($route);
|
||||||
|
$pluginManager->getPluginType($pluginName);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Responsibilities:
|
||||||
|
- Loading plugins from `plugins/` folders (only enabled plugins)
|
||||||
|
- Plugin file: `<PluginName>.php` (NOT `plugin.php`)
|
||||||
|
- Hooks and filters system (`doAction`, `applyFilters`)
|
||||||
|
- Collecting sidebar content from content plugins (`getSidebarContent`)
|
||||||
|
- Collecting plugin CSS URLs (`getPluginCssUrls`)
|
||||||
|
- **Admin menu items** from system plugins (`getAdminMenuItems`)
|
||||||
|
- **Admin routes** handled via system plugins (`handleAdminRoute`)
|
||||||
|
- Determining the **plugin type** (`getPluginType` — `content` or `system`)
|
||||||
|
- `isPluginViewable` — system plugins do not appear in the sidebar
|
||||||
|
|
||||||
|
## AdminAuth.php
|
||||||
|
|
||||||
|
Authentication and RBAC in `admin/src/AdminAuth.php`:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$auth = new AdminAuth($appConfig);
|
||||||
|
$auth->login($username, $password);
|
||||||
|
$auth->logout();
|
||||||
|
$auth->hasPermission($route);
|
||||||
|
$auth->verifyCsrf($token);
|
||||||
|
```
|
||||||
|
|
||||||
|
Constants:
|
||||||
|
- `ROLE_PERMISSIONS` — Mapping of role → allowed route prefixes. `admin` has wildcard `*`.
|
||||||
|
- `ROLE_LABELS` — Human-readable labels per role.
|
||||||
|
|
||||||
|
Roles:
|
||||||
|
|
||||||
|
| Role | Label | Permissions |
|
||||||
|
|------|-------|-------------|
|
||||||
|
| `admin` | Admin | Everything (`*`) |
|
||||||
|
| `content-manager` | Content Manager | Content management, guide |
|
||||||
|
| `bi-manager` | BI Manager | Statistics, logs, guide |
|
||||||
|
| `site-admin` | Site Admin | Theme, plugins, statistics, logs, update, guide |
|
||||||
|
|
||||||
|
Responsibilities:
|
||||||
|
- Session-based authentication
|
||||||
|
- bcrypt password hashing
|
||||||
|
- CSRF tokens (`verifyCsrf`)
|
||||||
|
- Brute-force lockout (login attempts tracking)
|
||||||
|
- RBAC via `hasPermission($route)` — checks the route against `ROLE_PERMISSIONS`
|
||||||
|
|
||||||
|
## CMSAPI.php
|
||||||
|
|
||||||
|
Plugin API in `cms/core/plugin/CMSAPI.php`:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$api = PluginManager::getAPI();
|
||||||
|
$config = $api->getConfig();
|
||||||
|
$page = $api->getPage($path);
|
||||||
|
$content = $api->getContent();
|
||||||
|
```
|
||||||
|
|
||||||
|
Provides read-only access for plugins to CMS data (config, pages, content).
|
||||||
@@ -1,43 +1,144 @@
|
|||||||
# Plugin Development
|
# Plugin Development
|
||||||
|
|
||||||
|
## Plugin types
|
||||||
|
|
||||||
|
CodePress has two kinds of plugins, determined by the `type` field in `plugin.json`:
|
||||||
|
|
||||||
|
- **Content plugins** (`type: "content"`) — Appear in the sidebar and in the plugin selection on content-edit pages. Provide sidebar content via `getSidebarContent()`.
|
||||||
|
- **System plugins** (`type: "system"`) — Are loaded by PluginManager but do NOT appear in the sidebar. Provide functionality via admin menu, routes and the CMSAPI.
|
||||||
|
|
||||||
|
When no `type` field is present, `content` is assumed.
|
||||||
|
|
||||||
## Plugin structure
|
## Plugin structure
|
||||||
|
|
||||||
```
|
```
|
||||||
plugins/MyPlugin/
|
plugins/MyPlugin/
|
||||||
├── plugin.json # Plugin metadata
|
├── MyPlugin.php # Plugin code (NOT plugin.php)
|
||||||
├── plugin.php # Plugin code
|
├── plugin.json # Metadata with type field
|
||||||
└── config.json # Optional configuration
|
├── config.json # Optional configuration
|
||||||
|
└── assets/
|
||||||
|
├── scss/myplugin.scss # SCSS source (optional)
|
||||||
|
└── css/myplugin.css # CSS (manually maintained)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Plugin files are named `<PluginName>.php` (e.g. `Navigation.php`, `HTMLBlock.php`). `PluginManager` loads `$pluginDir . '/' . $pluginName . '.php'`.
|
||||||
|
|
||||||
## plugin.json
|
## plugin.json
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"name": "My Plugin",
|
"name": "My Plugin",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"author": "Your Name",
|
"author": "Your Name",
|
||||||
"description": "Description"
|
"description": "Description",
|
||||||
|
"type": "content"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## plugin.php example
|
- `name` — Display name
|
||||||
|
- `type` — `"content"` or `"system"` (default: `content`)
|
||||||
|
|
||||||
|
## Content plugin example
|
||||||
|
|
||||||
```php
|
```php
|
||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* Plugin: MyPlugin
|
* Plugin: MyPlugin (content)
|
||||||
*/
|
*/
|
||||||
|
class MyPlugin
|
||||||
|
{
|
||||||
|
public function getConfig(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'title' => 'My Plugin',
|
||||||
|
'type' => 'content',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
echo '<div class="my-plugin">Hello World</div>';
|
public function getSidebarContent(): string
|
||||||
|
{
|
||||||
|
return '<p>Hello World</p>';
|
||||||
|
}
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## System plugin example
|
||||||
|
|
||||||
|
```php
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Plugin: MySystem (system)
|
||||||
|
*/
|
||||||
|
class MySystem
|
||||||
|
{
|
||||||
|
public function getConfig(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'title' => 'My System',
|
||||||
|
'type' => 'system',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAdminMenu(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['label' => 'My System', 'route' => 'my-system', 'icon' => 'bi-gear'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAdminRoutes(): array
|
||||||
|
{
|
||||||
|
return ['my-system'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handleAdminRoute(string $route): void
|
||||||
|
{
|
||||||
|
echo '<h1>My System page</h1>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
System plugins are shown in the admin sidebar via `PluginManager::getAdminMenuItems()` and handled via `PluginManager::handleAdminRoute()`.
|
||||||
|
|
||||||
## Using CMSAPI
|
## Using CMSAPI
|
||||||
|
|
||||||
```php
|
```php
|
||||||
<?php
|
<?php
|
||||||
require_once '../../cms/core/class/PluginManager.php';
|
|
||||||
|
|
||||||
$api = PluginManager::getAPI();
|
$api = PluginManager::getAPI();
|
||||||
$config = $api->getConfig();
|
$config = $api->getConfig();
|
||||||
$content = $api->getContent();
|
$page = $api->getPage($path);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
`setAPI()` is called automatically by `PluginManager` if the plugin has the method.
|
||||||
|
|
||||||
|
## Plugin CSS
|
||||||
|
|
||||||
|
- Plugin CSS in `assets/css/` is manually maintained (SCSS compilation for plugins is not yet automatic)
|
||||||
|
- Plugin CSS is automatically loaded after theme CSS (in `base.twig`), so themes can override plugin styling
|
||||||
|
- Plugin assets are served via `cms/router.php` at URL `/plugins/<Name>/assets/...`
|
||||||
|
- Implement `getCssUrl()` in the plugin class to return the CSS URL
|
||||||
|
|
||||||
|
```php
|
||||||
|
public function getCssUrl(): string
|
||||||
|
{
|
||||||
|
return '/plugins/MyPlugin/assets/css/myplugin.css';
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Hooks and filters
|
||||||
|
|
||||||
|
PluginManager auto-registers these methods as hooks/filters:
|
||||||
|
|
||||||
|
- **Hooks**: `onPageLoad`, `onBeforeRender`, `onAfterRender`, `onSearch`, `onMenuBuild`
|
||||||
|
- **Filters**: `onContentFilter`, `onTitleFilter`, `onMenuFilter`
|
||||||
|
|
||||||
|
```php
|
||||||
|
public function onPageLoad($page) { /* ... */ }
|
||||||
|
public function onContentFilter($content) { return $content; }
|
||||||
|
```
|
||||||
|
|
||||||
|
## Essential plugins
|
||||||
|
|
||||||
|
Essential plugins are defined in `getProtectedPlugins()` in `public/admin.php`. Current essential plugin: **Navigation**.
|
||||||
|
|
||||||
|
These plugins cannot be deactivated, edited or deleted. Always add the `isProtectedPlugin()` check to new plugin handlers.
|
||||||
@@ -2,18 +2,60 @@
|
|||||||
|
|
||||||
## Frontend routing
|
## Frontend routing
|
||||||
|
|
||||||
Via `cms/router.php` for PHP dev server:
|
Frontend routing goes through `cms/router.php` (PHP dev server) or `.htaccess` (Apache). Both provide clean URLs.
|
||||||
|
|
||||||
```php
|
### PHP dev server
|
||||||
// Clean URLs: /nl/page
|
|
||||||
// Query: ?page=page&lang=nl
|
Start the server with:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
php -S localhost:8080 cms/router.php
|
||||||
```
|
```
|
||||||
|
|
||||||
|
`cms/router.php` serves:
|
||||||
|
- Clean URLs: `/nl/page` → `public/index.php?page=page&lang=nl`
|
||||||
|
- `themes/` assets
|
||||||
|
- `admin/assets/` assets
|
||||||
|
- `plugins/` assets
|
||||||
|
|
||||||
|
### Apache (live server)
|
||||||
|
|
||||||
|
`public/.htaccess` rewrites URLs to `public/index.php`. Asset URLs (`/themes/`, `/admin/assets/`, `/plugins/`) are forwarded to `public/asset.php`.
|
||||||
|
|
||||||
|
`public/asset.php` serves files from the correct folders with the correct MIME type:
|
||||||
|
- `/themes/<name>/assets/...` → `themes/<name>/assets/...`
|
||||||
|
- `/admin/assets/...` → `admin/theme/default/assets/...`
|
||||||
|
- `/plugins/<name>/assets/...` → `plugins/<name>/assets/...`
|
||||||
|
|
||||||
## Admin routing
|
## Admin routing
|
||||||
|
|
||||||
Via `public/admin.php`:
|
Admin routing goes through `public/admin.php` with clean URLs:
|
||||||
|
|
||||||
|
```
|
||||||
|
/admin/dashboard → ?route=dashboard
|
||||||
|
/admin/content → ?route=content
|
||||||
|
/admin/plugins → ?route=plugins
|
||||||
|
```
|
||||||
|
|
||||||
|
`cms/router.php` or `.htaccess` converts `/admin/<route>` to `?route=<route>`.
|
||||||
|
|
||||||
|
### Route access control (RBAC)
|
||||||
|
|
||||||
|
Each route is checked via `AdminAuth::hasPermission($route)`:
|
||||||
|
- The `admin` role has wildcard `*` access
|
||||||
|
- Other roles have an explicit list of allowed routes in `ROLE_PERMISSIONS`
|
||||||
|
- Unauthorized routes return a **403 error**
|
||||||
|
|
||||||
|
## Plugin admin routing
|
||||||
|
|
||||||
|
System plugins can register admin routes. These are handled by `PluginManager::handleAdminRoute($route)`:
|
||||||
|
|
||||||
|
1. The system plugin registers routes via `getAdminRoutes()`
|
||||||
|
2. `PluginManager::getAdminMenuItems()` collects admin menu items via `getAdminMenu()`
|
||||||
|
3. On an admin request `PluginManager::handleAdminRoute($route)` finds a plugin that handles the route
|
||||||
|
4. The plugin method `handleAdminRoute($route)` renders the page content
|
||||||
|
|
||||||
```php
|
```php
|
||||||
// Routes: /admin/dashboard, /admin/content, etc.
|
// PluginManager calls this for /admin/my-system
|
||||||
// Query parameter: ?route=dashboard
|
$plugin->handleAdminRoute('my-system');
|
||||||
```
|
```
|
||||||
@@ -4,28 +4,48 @@ Content is stored in the `content/` folder without a database.
|
|||||||
|
|
||||||
## Supported file formats
|
## Supported file formats
|
||||||
|
|
||||||
- `.md` - Markdown (recommended)
|
- `.md` — Markdown (recommended)
|
||||||
- `.php` - Dynamic PHP pages
|
- `.php` — Dynamic PHP pages
|
||||||
- `.html` - Static HTML pages
|
- `.html` — Static HTML pages
|
||||||
|
|
||||||
## File name conventions
|
## File name conventions
|
||||||
|
|
||||||
```
|
```
|
||||||
en.page-name.md # English page
|
nl.pagina-naam.md # Dutch page
|
||||||
nl.pagina-naam.md # Dutch page
|
en.page-name.md # English page
|
||||||
|
nl.folder/ # Dutch folder (requires an index file to be clickable)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The language prefix is dynamically removed based on available languages via `getAvailableLanguages()`.
|
||||||
|
|
||||||
## Frontmatter
|
## Frontmatter
|
||||||
|
|
||||||
Markdown files can contain frontmatter metadata:
|
Markdown files can contain frontmatter metadata:
|
||||||
|
|
||||||
```markdown
|
```markdown
|
||||||
---
|
---
|
||||||
layout: full_content
|
layout: left_sidebar
|
||||||
plugins: HTMLBlock
|
plugins:
|
||||||
|
- HTMLBlock
|
||||||
|
- Navigation
|
||||||
---
|
---
|
||||||
|
|
||||||
# Page title
|
# Page title
|
||||||
|
|
||||||
Content...
|
Content...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Frontmatter fields
|
||||||
|
|
||||||
|
- `layout` — Layout name (must exist in the `theme.json` template mapping; fallback to `config.default_template`)
|
||||||
|
- `plugins` — List of content plugins that appear in the sidebar
|
||||||
|
|
||||||
|
### plugins field
|
||||||
|
|
||||||
|
The `plugins` field determines:
|
||||||
|
- **Which plugins** appear in the sidebar (only content plugins, not system plugins)
|
||||||
|
- **The order** of the plugins in the sidebar (top to bottom)
|
||||||
|
|
||||||
|
The order in the frontmatter is the order in which the plugins are shown. In the admin content-edit page you can adjust the order with up/down buttons; the frontmatter is updated live.
|
||||||
|
|
||||||
|
Plugins are not shown when the chosen layout has no sidebar (e.g. `full_content`).
|
||||||
@@ -5,12 +5,44 @@
|
|||||||
1. Login at `/admin`
|
1. Login at `/admin`
|
||||||
2. Go to **Content**
|
2. Go to **Content**
|
||||||
3. Choose a folder or create a new page
|
3. Choose a folder or create a new page
|
||||||
4. Edit content in the editor
|
4. Edit content in the CodeMirror editor
|
||||||
5. Save with Ctrl+S
|
5. Save with Ctrl+S
|
||||||
|
|
||||||
## Editor features
|
## Editor features
|
||||||
|
|
||||||
- **CodeMirror** editor with syntax highlighting
|
- **CodeMirror** editor with syntax highlighting (Markdown, PHP, HTML)
|
||||||
- **Toolbar** for quick Markdown insertion
|
- **Toolbar** for quick Markdown insertion
|
||||||
- **Live preview** via button
|
- **Shortcuts**: Ctrl+S (save), Ctrl+N (new)
|
||||||
- **Auto-save** backups in `.bak/` folder
|
- **Auto-save** backups in `.bak/` folder
|
||||||
|
|
||||||
|
## Layout selection
|
||||||
|
|
||||||
|
On the content-edit page you can choose the layout from the layouts defined in `theme.json` (template mapping). The selected layout is stored in the frontmatter `layout:` key.
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
---
|
||||||
|
layout: left_sidebar
|
||||||
|
---
|
||||||
|
```
|
||||||
|
|
||||||
|
Unknown layouts fall back to `config.default_template` from `theme.json`.
|
||||||
|
|
||||||
|
## Plugin selection and order
|
||||||
|
|
||||||
|
On the content-edit page you can choose content plugins for the sidebar:
|
||||||
|
|
||||||
|
- **Selection** — Only content plugins (from `plugin.json` with `type: "content"`) appear in the plugin selection
|
||||||
|
- **Order** — Adjust the order with up/down buttons
|
||||||
|
- **Frontmatter update** — The frontmatter `plugins:` key is updated live on changes
|
||||||
|
- **Layout without sidebar** — Plugins are hidden when the chosen layout has no sidebar (e.g. `full_content`)
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
---
|
||||||
|
layout: left_sidebar
|
||||||
|
plugins:
|
||||||
|
- HTMLBlock
|
||||||
|
- Navigation
|
||||||
|
---
|
||||||
|
```
|
||||||
|
|
||||||
|
The order in the frontmatter determines the order of the plugins in the sidebar (top to bottom).
|
||||||
@@ -1,3 +1,12 @@
|
|||||||
# Manual
|
# Manual
|
||||||
|
|
||||||
|
Welcome to the CodePress CMS manual (version 2.5.2). CodePress is a file-based CMS without a database — content, configuration and users are stored in files.
|
||||||
|
|
||||||
|
The manual is divided into four sections:
|
||||||
|
|
||||||
|
- **Admin Manager** — Managing the website: dashboard, content, configuration, themes, security, plugins (content and system), users with roles, statistics and logs
|
||||||
|
- **Content Manager** — Managing content: structure, managing pages (layout selection, plugin order), media and the Content API
|
||||||
|
- **Theme Developer** — Developing themes: structure, `theme.json`, Twig templates, SCSS styling (only CSS source), layouts and new themes
|
||||||
|
- **CodePress Developer** — Core development: architecture, core classes, plugin development (content/system), routing, security (RBAC), testing, debugging and performance
|
||||||
|
|
||||||
Select a topic from the navigation on the left.
|
Select a topic from the navigation on the left.
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
The theme developer guide contains the following topics:
|
The theme developer guide contains the following topics:
|
||||||
|
|
||||||
- **Theme structure** - Folder structure of a theme
|
- **Theme structure** - Folder structure of a theme
|
||||||
- **theme.json** - Theme configuration
|
- **theme.json** - Configuration of a theme
|
||||||
- **Twig templates** - Twig syntax, variables and blocks
|
- **Twig templates** - Twig syntax, variables and blocks
|
||||||
- **SCSS styling** - Compiling and writing SCSS
|
- **SCSS styling** - Compiling and writing SCSS
|
||||||
- **Layouts** - Defining and using layouts
|
- **Layouts** - Defining and using layouts
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
# Layouts
|
# Layouts
|
||||||
|
|
||||||
|
Layouts define the page structure (left sidebar, full width, etc.). Layouts are defined in `theme.json` and chosen via frontmatter in content files.
|
||||||
|
|
||||||
## Choosing a layout in content
|
## Choosing a layout in content
|
||||||
|
|
||||||
```markdown
|
```markdown
|
||||||
@@ -14,14 +16,58 @@ Content...
|
|||||||
|
|
||||||
## Layouts in theme.json
|
## Layouts in theme.json
|
||||||
|
|
||||||
|
Layouts are defined in the `template` mapping. The `config.default_template` is the fallback for pages without a `layout:` frontmatter or with an unknown layout:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"default_layout": "full_content",
|
"config": {
|
||||||
"layouts": {
|
"default_template": "full_content"
|
||||||
"full_content": "full_content.twig",
|
},
|
||||||
"left_sidebar": "left_sidebar.twig",
|
"template": {
|
||||||
"right_sidebar": "right_sidebar.twig",
|
"full_content": "full_content.twig",
|
||||||
"custom1": "custom1.twig"
|
"left_sidebar": "left_sidebar.twig",
|
||||||
}
|
"right_sidebar": "right_sidebar.twig",
|
||||||
|
"custom1": "custom1.twig",
|
||||||
|
"guide": "guide.twig"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Layout template
|
||||||
|
|
||||||
|
A layout template extends `base.twig` and fills the `content` block:
|
||||||
|
|
||||||
|
```twig
|
||||||
|
{% extends 'base.twig' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="container">
|
||||||
|
{{ content|raw }}
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Layouts with sidebar
|
||||||
|
|
||||||
|
Layouts with a sidebar can show plugin content:
|
||||||
|
|
||||||
|
```twig
|
||||||
|
{% extends 'base.twig' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="row">
|
||||||
|
<main class="col-md-8">
|
||||||
|
{{ content|raw }}
|
||||||
|
</main>
|
||||||
|
<aside class="col-md-4">
|
||||||
|
{{ sidebar_content|raw }}
|
||||||
|
</aside>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
```
|
||||||
|
|
||||||
|
If a page has no plugins or the layout has no sidebar, `sidebar_content` is empty.
|
||||||
|
|
||||||
|
## Guide layout
|
||||||
|
|
||||||
|
The `guide` layout (`guide.twig`) is special for guides. It injects the Navigation plugin into the sidebar for sidebar navigation. Automatically used for pages in the `guide/` folder.
|
||||||
@@ -2,20 +2,49 @@
|
|||||||
|
|
||||||
```
|
```
|
||||||
themes/my-theme/
|
themes/my-theme/
|
||||||
├── theme.json # Theme configuration
|
├── theme.json # { title, config.default_template, template: layout→.twig }
|
||||||
├── base.twig # Main layout
|
├── base.twig # Main layout (head, header, nav, breadcrumb, footer)
|
||||||
├── full_content.twig # Layout: full-width
|
├── full_content.twig # Layout: full width
|
||||||
├── left_sidebar.twig # Layout: left sidebar
|
├── left_sidebar.twig # Layout: sidebar on the left
|
||||||
├── right_sidebar.twig # Layout: right sidebar
|
├── right_sidebar.twig # Layout: sidebar on the right
|
||||||
├── custom.twig # Layout: custom
|
├── custom1.twig # Layout: custom
|
||||||
|
├── guide.twig # Layout: guide with sidebar (Navigation plugin)
|
||||||
├── partials/
|
├── partials/
|
||||||
│ ├── header.twig
|
│ ├── header.twig
|
||||||
│ ├── navigation.twig
|
│ ├── navigation.twig
|
||||||
│ └── footer.twig
|
│ └── footer.twig
|
||||||
└── assets/
|
└── assets/
|
||||||
├── scss/theme.scss # SCSS source
|
├── scss/theme.scss # SCSS source (the only CSS source)
|
||||||
├── css/ # CSS files
|
├── css_compiled/ # Generated by scssphp (read-only, do not edit manually)
|
||||||
├── js/theme.js # JavaScript
|
├── css/ # External CSS (bootstrap.min.css, bootstrap-icons.css, mobile.css)
|
||||||
├── fonts/ # Fonts
|
├── js/ # app.js, bootstrap.bundle.min.js
|
||||||
└── img/ # Images
|
├── fonts/ # bootstrap-icons.woff, woff2
|
||||||
|
└── img/ # favicon, icon, world-map
|
||||||
|
```
|
||||||
|
|
||||||
|
## SCSS is the only CSS source
|
||||||
|
|
||||||
|
- **ALWAYS** edit `assets/scss/theme.scss` — this is the only CSS source
|
||||||
|
- `ThemeManager` compiles SCSS at runtime to `assets/css_compiled/theme.css` via scssphp
|
||||||
|
- `assets/css_compiled/` is **read-only** — do not edit manually
|
||||||
|
- **NEVER** create or edit `assets/css/theme.css` manually; this file must not exist
|
||||||
|
- `ThemeManager::getCssUrl()` priority: 1) `assets/css/theme.css` (manual), 2) `assets/css_compiled/theme.css` (compiled). If `theme.css` exists, the SCSS is ignored.
|
||||||
|
- After SCSS changes: remove `assets/css_compiled/theme.css` and `.mtime` to force recompilation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
rm themes/my-theme/assets/css_compiled/theme.css themes/my-theme/assets/css_compiled/.mtime
|
||||||
|
```
|
||||||
|
|
||||||
|
## guide.twig
|
||||||
|
|
||||||
|
Special layout for guides. Injects the Navigation plugin into the sidebar for sidebar navigation. Automatically used for pages in the `guide/` folder.
|
||||||
|
|
||||||
|
## Plugin CSS loading
|
||||||
|
|
||||||
|
Plugin CSS is automatically loaded after theme CSS in `base.twig`, so themes can override plugin styling:
|
||||||
|
|
||||||
|
```twig
|
||||||
|
{% for cssUrl in plugin_css_urls|default([]) %}
|
||||||
|
<link href="{{ cssUrl }}" rel="stylesheet">
|
||||||
|
{% endfor %}
|
||||||
```
|
```
|
||||||
@@ -2,20 +2,45 @@
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"title": "My Theme",
|
"title": "My Theme",
|
||||||
"default_layout": "full_content",
|
"config": {
|
||||||
"header_color": "#0a369d",
|
"default_template": "full_content"
|
||||||
"layouts": {
|
},
|
||||||
"full_content": "full_content.twig",
|
"template": {
|
||||||
"left_sidebar": "left_sidebar.twig",
|
"full_content": "full_content.twig",
|
||||||
"right_sidebar": "right_sidebar.twig"
|
"left_sidebar": "left_sidebar.twig",
|
||||||
}
|
"right_sidebar": "right_sidebar.twig",
|
||||||
|
"custom1": "custom1.twig",
|
||||||
|
"guide": "guide.twig"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Fields
|
## Fields
|
||||||
|
|
||||||
- `title` - Display name in admin
|
- `title` — Display name in admin
|
||||||
- `default_layout` - Default layout for new pages
|
- `config.default_template` — Default layout for pages without a `layout:` frontmatter (fallback for unknown layouts)
|
||||||
- `header_color` - Admin sidebar color
|
- `template` — Mapping from layout name to `.twig` file
|
||||||
- `layouts` - Mapping of layout names to .twig files
|
|
||||||
|
## Template mapping
|
||||||
|
|
||||||
|
The `template` mapping defines which layouts are available. Each key is a layout name, each value is the `.twig` file:
|
||||||
|
|
||||||
|
| Layout name | Twig file | Description |
|
||||||
|
|-------------|-----------|-------------|
|
||||||
|
| `full_content` | `full_content.twig` | Full width, no sidebar |
|
||||||
|
| `left_sidebar` | `left_sidebar.twig` | Sidebar on the left |
|
||||||
|
| `right_sidebar` | `right_sidebar.twig` | Sidebar on the right |
|
||||||
|
| `custom1` | `custom1.twig` | Custom layout |
|
||||||
|
| `guide` | `guide.twig` | Guide with sidebar (Navigation plugin) |
|
||||||
|
|
||||||
|
## Layout selection
|
||||||
|
|
||||||
|
- Layouts are chosen via the frontmatter `layout:` key in content files
|
||||||
|
- Unknown layouts fall back to `config.default_template`
|
||||||
|
- `ThemeManager::getTemplates()` returns the template mapping
|
||||||
|
- `ThemeManager::getConfig()` returns the config section (including `default_template`)
|
||||||
|
|
||||||
|
## Guide layout
|
||||||
|
|
||||||
|
The `guide` layout is special for guides. `getGuidePage()` in `CodePressCMS.php` automatically injects the Navigation plugin into the metadata for sidebar navigation.
|
||||||
@@ -2,14 +2,14 @@
|
|||||||
|
|
||||||
De admin beheerder handleiding bevat de volgende onderwerpen:
|
De admin beheerder handleiding bevat de volgende onderwerpen:
|
||||||
|
|
||||||
- **Dashboard** - Overzicht van de website
|
- **Dashboard** - Role-based overzicht van de website (Admin, Content Beheerder, BI Beheerder, Site Admin)
|
||||||
- **Content beheer** - Bestanden en pagina's beheren
|
- **Content beheer** - Bestanden en pagina's beheren met layout selectie en plugins
|
||||||
- **Configuratie** - Site instellingen
|
- **Configuratie** - Site instellingen (titel, taal, auteur, analytics, logging)
|
||||||
- **Thema beheer** - Thema's beheren en aanmaken
|
- **Thema beheer** - Thema's beheren, activeren en aanmaken (SCSS compilatie)
|
||||||
- **Beveiliging** - Bot bescherming en sessies
|
- **Beveiliging** - Bot bescherming, rate limiting en sessie instellingen
|
||||||
- **Plugins** - Plugins beheren en aanmaken
|
- **Plugins** - Plugins beheren: content (sidebar) en systeem (admin menu/API)
|
||||||
- **Gebruikers** - Gebruikers toevoegen en verwijderen
|
- **Gebruikers** - Gebruikersbeheer met rollen (Admin, Content Beheerder, BI Beheerder, Site Admin)
|
||||||
- **Statistieken** - Bezoekersstatistieken bekijken
|
- **Statistieken** - Bezoekersstatistieken bekijken en exporteren
|
||||||
- **Logs** - Logbestanden bekijken en filteren
|
- **Logs** - Logbestanden bekijken en filteren
|
||||||
|
|
||||||
Selecteer een onderwerp uit de navigatie aan de linkerkant.
|
Selecteer een onderwerp uit de navigatie aan de linkerkant.
|
||||||
@@ -2,16 +2,45 @@
|
|||||||
|
|
||||||
## Bestanden beheren
|
## Bestanden beheren
|
||||||
|
|
||||||
- **Uploaden** - Media bestanden uploaden
|
- **Nieuwe map** — Mappen structuur aanmaken
|
||||||
- **Nieuwe map** - Mappen structuur aanmaken
|
- **Nieuw bestand** — Pagina aanmaken (`.md`, `.php`, `.html`)
|
||||||
- **Nieuw bestand** - Pagina aanmaken
|
- **Bewerken** — Bestaande content wijzigen in CodeMirror editor
|
||||||
- **Bewerken** - Bestaande content wijzigen
|
- **Hernoemen** — Bestands- of mapnamen aanpassen
|
||||||
- **Hernoemen** - Bestandsnamen aanpassen
|
- **Verplaatsen** — Content verplaatsen naar andere map
|
||||||
- **Verplaatsen** - Content verplaatsen
|
- **Verwijderen** — Content verwijderen
|
||||||
- **Verwijderen** - Content verwijderen
|
- **Map hernoemen** — Map naam wijzigen
|
||||||
|
|
||||||
## Editor
|
## Editor (content-edit)
|
||||||
|
|
||||||
- CodeMirror met syntax highlighting
|
- **CodeMirror** met syntax highlighting (Markdown, PHP, HTML)
|
||||||
- Toolbar voor Markdown formatting
|
- **Toolbar** voor snel Markdown invoeren
|
||||||
- Sneltoetsen: Ctrl+S (opslaan), Ctrl+N (nieuw)
|
- **Sneltoetsen**: Ctrl+S (opslaan), Ctrl+N (nieuw)
|
||||||
|
|
||||||
|
## Layout selectie
|
||||||
|
|
||||||
|
Op de content-edit pagina kun je de layout kiezen uit de layouts gedefinieerd in `theme.json` (template mapping). De geselecteerde layout wordt opgeslagen in de frontmatter `layout:` key.
|
||||||
|
|
||||||
|
## Plugins op pagina's
|
||||||
|
|
||||||
|
- Content plugins (uit `plugin.json` met `type: "content"`) verschijnen in de plugin selectie
|
||||||
|
- Kies welke plugins in de sidebar verschijnen
|
||||||
|
- **Volgorde aanpasbaar** met up/down knoppen
|
||||||
|
- De plugin volgorde wordt opgeslagen in de frontmatter `plugins:` key
|
||||||
|
- Plugins worden **verbergen** als de gekozen layout geen sidebar heeft (bijv. `full_content`)
|
||||||
|
|
||||||
|
## Frontmatter
|
||||||
|
|
||||||
|
De editor werkt de frontmatter live bij bij wijzigingen van layout of plugin selectie:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
---
|
||||||
|
layout: left_sidebar
|
||||||
|
plugins:
|
||||||
|
- HTMLBlock
|
||||||
|
- Navigation
|
||||||
|
---
|
||||||
|
|
||||||
|
# Pagina titel
|
||||||
|
|
||||||
|
Content...
|
||||||
|
```
|
||||||
@@ -1,10 +1,32 @@
|
|||||||
# Dashboard
|
# Dashboard
|
||||||
|
|
||||||
Het dashboard toont een overzicht van:
|
Het dashboard toont een **role-based overzicht** van de website. Welke widgets zichtbaar zijn, hangt af van de rol van de ingelogde gebruiker.
|
||||||
|
|
||||||
- Weergaven (30 dagen)
|
## Rollen en widgets
|
||||||
- Unieke bezoekers
|
|
||||||
|
### Admin
|
||||||
|
- Weergaven (30 dagen) en unieke bezoekers
|
||||||
- Aantal pagina's en mappen
|
- Aantal pagina's en mappen
|
||||||
- Actieve plugins
|
- Actieve plugins
|
||||||
- Recente activiteit
|
- Recente activiteit
|
||||||
- Snelle acties
|
- Systeem informatie
|
||||||
|
- Snelle acties (nieuwe pagina, plugin, thema)
|
||||||
|
|
||||||
|
### Content Beheerder
|
||||||
|
- Aantal pagina's en mappen
|
||||||
|
- Recente content wijzigingen
|
||||||
|
- Snelle acties (nieuwe pagina, map)
|
||||||
|
|
||||||
|
### BI Beheerder
|
||||||
|
- Weergaven (30 dagen) en unieke bezoekers
|
||||||
|
- Top pagina's
|
||||||
|
- Recente bezoeken
|
||||||
|
|
||||||
|
### Site Admin
|
||||||
|
- Actieve plugins en thema's
|
||||||
|
- Systeem informatie
|
||||||
|
- Snelle acties (thema, plugin, update)
|
||||||
|
|
||||||
|
## Toegang
|
||||||
|
|
||||||
|
Het dashboard is de standaard pagina na login (`/admin/dashboard`). Alle rollen hebben toegang tot het dashboard.
|
||||||
@@ -1,13 +1,40 @@
|
|||||||
# Gebruikers
|
# Gebruikers
|
||||||
|
|
||||||
|
Gebruikers worden opgeslagen in `admin/config/admin.json` (file-based, geen database). Elke gebruiker heeft een **rol** die bepaalt welke admin routes en sidebar items zichtbaar zijn.
|
||||||
|
|
||||||
|
## Rollen
|
||||||
|
|
||||||
|
CodePress kent vier rollen, gedefinieerd in `AdminAuth::ROLE_PERMISSIONS`:
|
||||||
|
|
||||||
|
| Rol | Label | Permissies |
|
||||||
|
|-----|-------|-----------|
|
||||||
|
| `admin` | Admin | Alles (`*`) |
|
||||||
|
| `content-manager` | Content Beheerder | Content beheer, handleiding |
|
||||||
|
| `bi-manager` | BI Beheerder | Statistieken, logs, handleiding |
|
||||||
|
| `site-admin` | Site Admin | Thema, plugins, statistieken, logs, update, handleiding |
|
||||||
|
|
||||||
|
Rollen worden getoond met hun label via `AdminAuth::ROLE_LABELS`.
|
||||||
|
|
||||||
## Gebruiker toevoegen
|
## Gebruiker toevoegen
|
||||||
|
|
||||||
1. Ga naar **Gebruikers**
|
1. Ga naar **Gebruikers**
|
||||||
2. Vul gebruikersnaam in
|
2. Vul gebruikersnaam in
|
||||||
3. Kies wachtwoord
|
3. Kies wachtwoord (opgeslagen als bcrypt hash)
|
||||||
4. Klik **Toevoegen**
|
4. Selecteer een rol
|
||||||
|
5. Klik **Toevoegen**
|
||||||
|
|
||||||
|
## Gebruiker bewerken
|
||||||
|
|
||||||
|
- Wachtwoord wijzigen (nieuwe bcrypt hash)
|
||||||
|
- Rol wijzigen (beïnvloedt direct zichtbare routes en sidebar items)
|
||||||
|
|
||||||
## Gebruiker verwijderen
|
## Gebruiker verwijderen
|
||||||
|
|
||||||
- Kan niet voor eigen account
|
- Kan niet voor eigen account
|
||||||
- Bevestig met wachtwoord
|
- Bevestig met wachtwoord
|
||||||
|
|
||||||
|
## Toegangscontrole
|
||||||
|
|
||||||
|
- Route access wordt gecontroleerd in `public/admin.php` via `AdminAuth::hasPermission()`
|
||||||
|
- Onbevoegde routes geven een **403 error**
|
||||||
|
- Sidebar items worden conditioneel getoond via de `has_permission()` Twig function in `admin.twig`
|
||||||
@@ -1,15 +1,49 @@
|
|||||||
# Plugins
|
# Plugins
|
||||||
|
|
||||||
|
## Plugin types
|
||||||
|
|
||||||
|
CodePress kent twee soorten plugins, bepaald door het `type` veld in `plugin.json`:
|
||||||
|
|
||||||
|
- **Content plugins** (`type: "content"`) — Verschijnen in de sidebar en in de plugin selectie op content-edit pagina's. Bieden sidebar content via `getSidebarContent()`.
|
||||||
|
- **Systeem plugins** (`type: "system"`) — Worden geladen door PluginManager maar verschijnen NIET in de sidebar. Bieden functionaliteit via admin menu, routes en de CMSAPI. Geregistreerd via `getAdminMenu()` en `getAdminRoutes()`.
|
||||||
|
|
||||||
|
Bij afwezigheid van een `type` veld wordt `content` aangenomen.
|
||||||
|
|
||||||
|
## Essentiële plugins
|
||||||
|
|
||||||
|
Essentiële plugins zijn gedefinieerd in `getProtectedPlugins()` in `public/admin.php`. Huidige essentiële plugin: **Navigation**.
|
||||||
|
|
||||||
|
Deze plugins:
|
||||||
|
- Kunnen NIET worden gedeactiveerd
|
||||||
|
- Kunnen NIET worden bewerkt
|
||||||
|
- Kunnen NIET worden verwijderd
|
||||||
|
|
||||||
|
Op de plugins pagina krijgen ze een **Essentieel** badge i.p.v. de actieknoppen.
|
||||||
|
|
||||||
## Plugins beheren
|
## Plugins beheren
|
||||||
|
|
||||||
- **Activeren/Deactiveren** - Plugins aan/uit
|
- **Activeren/Deactiveren** — Plugin aan/uit zetten (niet voor essentiële plugins)
|
||||||
- **Bewerken** - Plugin code aanpassen
|
- **Bewerken** — Plugin code aanpassen in CodeMirror (niet voor essentiële plugins)
|
||||||
- **Configuratie** - Plugin instellingen
|
- **Configuratie** — Plugin instellingen bewerken
|
||||||
- **Verwijderen** - Plugin verwijderen
|
- **Verwijderen** — Plugin map verwijderen (niet voor essentiële plugins)
|
||||||
|
|
||||||
## Nieuwe plugin
|
De admin plugins pagina toont een **Content** of **Systeem** badge per plugin.
|
||||||
|
|
||||||
|
## Nieuwe plugin aanmaken
|
||||||
|
|
||||||
1. Ga naar **Plugins** → **Nieuwe plugin**
|
1. Ga naar **Plugins** → **Nieuwe plugin**
|
||||||
2. Geef naam op (bijv. `MijnPlugin`)
|
2. Geef naam op (bijv. `MijnPlugin`) — dit wordt de mapnaam
|
||||||
3. Bewerk `plugin.php`
|
3. Kies het type: **Content** of **Systeem**
|
||||||
4. Activeer de plugin
|
4. Het bestand `MijnPlugin.php` wordt aangemaakt (NIET `plugin.php`)
|
||||||
|
5. Bewerk de plugin code in CodeMirror
|
||||||
|
6. Activeer de plugin
|
||||||
|
|
||||||
|
## Plugin bestandsnaam
|
||||||
|
|
||||||
|
Plugin PHP bestanden heten `<PluginName>.php` (bijv. `Navigation.php`, `HTMLBlock.php`). `PluginManager` laadt `$pluginDir . '/' . $pluginName . '.php'`.
|
||||||
|
|
||||||
|
## Plugin CSS
|
||||||
|
|
||||||
|
- Content en systeem plugins kunnen eigen CSS hebben in `assets/scss/` en `assets/css/`
|
||||||
|
- Plugin CSS wordt automatisch geladen ná theme CSS (in `base.twig`), zodat thema's plugin styling kunnen overschrijven
|
||||||
|
- Plugin assets worden geserveerd via `cms/router.php` op URL `/plugins/<Name>/assets/...`
|
||||||
@@ -3,17 +3,64 @@
|
|||||||
## Thema's beheren
|
## Thema's beheren
|
||||||
|
|
||||||
1. Ga naar **Thema** in admin menu
|
1. Ga naar **Thema** in admin menu
|
||||||
2. **Activeren** - Kies actief thema
|
2. **Activeren** — Kies actief thema (wordt opgeslagen in `config.json`)
|
||||||
3. **SCSS compileren** - Verwerk SCSS naar CSS
|
3. **SCSS compileren** — Verwerk SCSS naar CSS (geforceerd)
|
||||||
4. **Nieuw thema** - Eigen thema aanmaken
|
4. **Nieuw thema** — Eigen thema aanmaken via admin of handmatig
|
||||||
|
|
||||||
## Thema structuur
|
## Thema structuur
|
||||||
|
|
||||||
```
|
```
|
||||||
themes/default/
|
themes/default/
|
||||||
├── theme.json # Thema configuratie
|
├── theme.json # { title, config.default_template, template: layout→.twig }
|
||||||
├── base.twig # Hoofd layout
|
├── base.twig # Hoofd layout (head, header, nav, breadcrumb, footer)
|
||||||
├── full_content.twig # Layouts
|
├── full_content.twig # Layout: volledige breedte
|
||||||
├── partials/ # Header, nav, footer
|
├── left_sidebar.twig # Layout: sidebar links
|
||||||
└── assets/ # CSS, JS, afbeeldingen
|
├── right_sidebar.twig # Layout: sidebar rechts
|
||||||
|
├── custom1.twig # Layout: custom
|
||||||
|
├── guide.twig # Layout: handleiding met sidebar (Navigation plugin)
|
||||||
|
├── partials/ # header.twig, navigation.twig, footer.twig
|
||||||
|
└── assets/
|
||||||
|
├── scss/theme.scss # SCSS bron (enige CSS bron — handmatige css/theme.css mag niet bestaan)
|
||||||
|
├── css_compiled/ # Gegenereerd door scssphp (read-only, niet handmatig aanpassen)
|
||||||
|
├── css/ # Externe CSS (bootstrap.min.css, bootstrap-icons.css, mobile.css)
|
||||||
|
├── js/ # app.js, bootstrap.bundle.min.js
|
||||||
|
├── fonts/ # bootstrap-icons.woff, woff2
|
||||||
|
└── img/ # favicon, icon, world-map
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## theme.json
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"title": "default",
|
||||||
|
"config": {
|
||||||
|
"default_template": "full_content"
|
||||||
|
},
|
||||||
|
"template": {
|
||||||
|
"full_content": "full_content.twig",
|
||||||
|
"left_sidebar": "left_sidebar.twig",
|
||||||
|
"right_sidebar": "right_sidebar.twig",
|
||||||
|
"custom1": "custom1.twig",
|
||||||
|
"guide": "guide.twig"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- `title` — Weergavenaam in admin
|
||||||
|
- `config.default_template` — Standaard layout voor pagina's zonder `layout:` frontmatter
|
||||||
|
- `template` — Mapping van layout naam naar `.twig` bestand
|
||||||
|
|
||||||
|
## SCSS compilatie
|
||||||
|
|
||||||
|
- `ThemeManager` compileert `assets/scss/theme.scss` runtime naar `assets/css_compiled/theme.css` via scssphp
|
||||||
|
- `css_compiled/` is **read-only** — niet handmatig aanpassen
|
||||||
|
- `assets/css/theme.css` mag **niet** bestaan; anders negeert `ThemeManager::getCssUrl()` de SCSS
|
||||||
|
- Na SCSS wijzigingen: verwijder `assets/css_compiled/theme.css` en `.mtime` om te forceren
|
||||||
|
|
||||||
|
## Layouts
|
||||||
|
|
||||||
|
Layouts worden gekozen via frontmatter `layout:` key in content bestanden. Onbekende layouts vallen terug op `config.default_template` uit `theme.json`.
|
||||||
|
|
||||||
|
## guide.twig
|
||||||
|
|
||||||
|
Speciale layout voor handleidingen. Injecteert de Navigation plugin in de sidebar voor zijbalk navigatie. Wordt automatisch gebruikt voor pagina's in de `guide/` map.
|
||||||
@@ -2,13 +2,20 @@
|
|||||||
|
|
||||||
De CodePress developer handleiding bevat de volgende onderwerpen:
|
De CodePress developer handleiding bevat de volgende onderwerpen:
|
||||||
|
|
||||||
- **Architectuur** - CMS architectuur en mappenstructuur
|
- **Architectuur** — CMS architectuur en mappenstructuur
|
||||||
- **Core classes** - CodePressCMS, ThemeManager, PluginManager
|
- **Core classes** — CodePressCMS, ThemeManager, PluginManager, AdminAuth
|
||||||
- **Plugin development** - Plugins ontwikkelen
|
- **Plugin development** — Plugin types (content/systeem), structuur, API
|
||||||
- **Routing** - Frontend en admin routing
|
- **Routing** — Frontend, admin en plugin admin routing
|
||||||
- **Beveiliging** - XSS, CSRF, path traversal
|
- **Beveiliging** — XSS, CSRF, path traversal, RBAC
|
||||||
- **Testing** - Penetratie, accessibility en functionele tests
|
- **Testing** — Penetratie, accessibility en functionele tests
|
||||||
- **Debugging** - Logging en cache
|
- **Debugging** — Logging en cache
|
||||||
- **Performance** - OPcache en SCSS caching
|
- **Performance** — OPcache en SCSS caching
|
||||||
|
|
||||||
|
Belangrijke concepten in CodePress 2.5.2:
|
||||||
|
|
||||||
|
- **Plugin types** — Content plugins (sidebar) en systeem plugins (admin menu, routes, API)
|
||||||
|
- **Admin plugin API** — Systeem plugins kunnen admin menu items en routes registreren
|
||||||
|
- **SCSS compilatie** — `ThemeManager` compileert SCSS naar `css_compiled/` via scssphp (read-only)
|
||||||
|
- **Asset serving** — `public/asset.php` serveert themes/, admin/assets/ en plugins/ op Apache (i.p.v. PHP dev router)
|
||||||
|
|
||||||
Selecteer een onderwerp uit de navigatie aan de linkerkant.
|
Selecteer een onderwerp uit de navigatie aan de linkerkant.
|
||||||
@@ -1,11 +1,84 @@
|
|||||||
# CMS Architectuur
|
# CMS Architectuur
|
||||||
|
|
||||||
|
CodePress is een file-based CMS zonder database. Content, configuratie en gebruikers worden opgeslagen in bestanden.
|
||||||
|
|
||||||
|
## Mappenstructuur
|
||||||
|
|
||||||
```
|
```
|
||||||
codepress/
|
codepress/
|
||||||
├── cms/core/ # Core engine
|
├── cms/ # Core CMS engine
|
||||||
├── admin/ # Admin console
|
│ ├── core/
|
||||||
├── themes/ # Thema's
|
│ │ ├── class/
|
||||||
├── plugins/ # Plugins
|
│ │ │ ├── CodePressCMS.php # Hoofd CMS class (routing, rendering, breadcrumb)
|
||||||
├── content/ # Content
|
│ │ │ ├── ThemeManager.php # Thema-resolver + Twig render + SCSS compile
|
||||||
└── public/ # Web root
|
│ │ │ ├── ContentAPI.php # Read-only API voor PHP content
|
||||||
|
│ │ │ ├── ContentSecurityPolicy.php # CSP header management
|
||||||
|
│ │ │ ├── Analytics.php # Bezoekersstatistieken
|
||||||
|
│ │ │ ├── BotGuard.php # Bot/AI detectie
|
||||||
|
│ │ │ ├── Cache.php # Cache systeem
|
||||||
|
│ │ │ ├── GeoIP.php # GeoIP lookup (land, vlag)
|
||||||
|
│ │ │ ├── Logger.php # Basis logging
|
||||||
|
│ │ │ ├── LogManager.php # Dynamisch logging (SQLite/syslog)
|
||||||
|
│ │ │ ├── RateLimiter.php # Rate limiting per IP
|
||||||
|
│ │ │ ├── RequestLogger.php # Request logging + visitor info
|
||||||
|
│ │ │ ├── SearchEngine.php # Volledige tekst zoekfunctie
|
||||||
|
│ │ │ └── AccessibilityManager.php # Accessibility features
|
||||||
|
│ │ ├── plugin/
|
||||||
|
│ │ │ ├── PluginManager.php # Plugin loader (hooks, filters, sidebar, admin routes)
|
||||||
|
│ │ │ └── CMSAPI.php # API voor plugins (getPage, getConfig, etc.)
|
||||||
|
│ │ ├── config.php # Config loader (leest config.json)
|
||||||
|
│ │ └── index.php # Bootstrap (autoloader, requires)
|
||||||
|
│ ├── lang/ # Taalbestanden (nl.php, en.php)
|
||||||
|
│ └── router.php # PHP dev server router
|
||||||
|
├── themes/ # Dynamische thema's
|
||||||
|
│ └── default/ # Standaard thema (views + assets)
|
||||||
|
│ ├── theme.json # { title, config.default_template, template: layout→.twig }
|
||||||
|
│ ├── base.twig # Hoofd layout
|
||||||
|
│ ├── *.twig # Layout templates
|
||||||
|
│ ├── partials/ # header.twig, navigation.twig, footer.twig
|
||||||
|
│ └── assets/
|
||||||
|
│ ├── scss/theme.scss # SCSS bron (enige CSS bron)
|
||||||
|
│ ├── css_compiled/ # Gegenereerd door scssphp (read-only)
|
||||||
|
│ ├── css/ # Externe CSS (bootstrap.min.css, etc.)
|
||||||
|
│ ├── js/ # JavaScript
|
||||||
|
│ └── img/ # Afbeeldingen
|
||||||
|
├── admin/ # Admin paneel
|
||||||
|
│ ├── config/
|
||||||
|
│ │ ├── app.php # Admin app configuratie
|
||||||
|
│ │ └── admin.json # Gebruikers & security (file-based, .gitignore'd)
|
||||||
|
│ ├── src/
|
||||||
|
│ │ └── AdminAuth.php # Authenticatie + RBAC
|
||||||
|
│ ├── theme/default/ # Admin thema (views + assets)
|
||||||
|
│ │ ├── theme.json
|
||||||
|
│ │ ├── assets/ # CSS, JS, CodeMirror, fonts
|
||||||
|
│ │ └── views/ # login.twig, layouts/, pages/
|
||||||
|
│ └── storage/ # Logs, cache, geoip
|
||||||
|
├── plugins/ # CMS plugins
|
||||||
|
│ ├── Navigation/ # Essentiële navigatie plugin (beschermd)
|
||||||
|
│ │ ├── Navigation.php # Plugin code (NIET plugin.php)
|
||||||
|
│ │ ├── plugin.json # Metadata met type veld
|
||||||
|
│ │ └── assets/ # SCSS + CSS
|
||||||
|
│ └── HTMLBlock/ # Voorbeeld sidebar plugin
|
||||||
|
├── content/ # Website content (.md, .php, .html) — .gitignore'd
|
||||||
|
├── guide/ # Handleidingen (nl/en)
|
||||||
|
├── public/ # Web root
|
||||||
|
│ ├── index.php # Website entry point
|
||||||
|
│ ├── admin.php # Admin entry point + routing
|
||||||
|
│ ├── asset.php # Asset server voor Apache (themes/, admin/assets/, plugins/)
|
||||||
|
│ ├── .htaccess # Stuurt asset URLs door naar asset.php
|
||||||
|
│ ├── favicon.ico
|
||||||
|
│ └── robots.txt
|
||||||
|
├── var/ # Cache (twig) — .gitignore'd
|
||||||
|
├── config.json # Site configuratie — .gitignore'd
|
||||||
|
├── composer.json # PHP dependencies (CommonMark, Twig, scssphp)
|
||||||
|
└── version.php # Versie informatie (2.5.2)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Principes
|
||||||
|
|
||||||
|
- **Geen database** — Alles in bestanden (content in `content/`, gebruikers in `admin/config/admin.json`, config in `config.json`)
|
||||||
|
- **File-based auth** — `AdminAuth` gebruikt bcrypt hashes in `admin.json`, sessies voor login
|
||||||
|
- **Twig templating** — Themes gebruiken Twig; `ThemeManager` rendert via Twig
|
||||||
|
- **SCSS compilatie** — `assets/scss/theme.scss` → `assets/css_compiled/theme.css` via scssphp (read-only output)
|
||||||
|
- **Plugin systeem** — `PluginManager` laadt content en systeem plugins met hooks/filters
|
||||||
|
- **Asset serving** — PHP dev router (`cms/router.php`) of Apache (`.htaccess` → `public/asset.php`)
|
||||||
@@ -10,6 +10,13 @@ $cms->init();
|
|||||||
$cms->renderPage($pagePath);
|
$cms->renderPage($pagePath);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Verantwoordelijkheden:
|
||||||
|
- Routing en pagina rendering
|
||||||
|
- Breadcrumb generatie (dynamisch: Home > [submappen] > [pagina])
|
||||||
|
- Guide pagina's laden (`getGuidePage()`)
|
||||||
|
- Titel extractie uit H1 (`getTitleFromFile()`)
|
||||||
|
- Weergavenaam verwerking (`formatDisplayName()`)
|
||||||
|
|
||||||
## ThemeManager.php
|
## ThemeManager.php
|
||||||
|
|
||||||
Themabeheer in `cms/core/class/ThemeManager.php`:
|
Themabeheer in `cms/core/class/ThemeManager.php`:
|
||||||
@@ -19,14 +26,84 @@ $themeManager = new ThemeManager($config);
|
|||||||
$themeManager->getActiveTheme();
|
$themeManager->getActiveTheme();
|
||||||
$themeManager->renderTwig($template, $data);
|
$themeManager->renderTwig($template, $data);
|
||||||
$themeManager->compileCss($force);
|
$themeManager->compileCss($force);
|
||||||
|
$themeManager->getCssUrl();
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Verantwoordelijkheden:
|
||||||
|
- Actief thema resolveren vanuit `config.json`
|
||||||
|
- `theme.json` laden (title, config.default_template, template mapping)
|
||||||
|
- Twig environment bouwen (geroot in thema map)
|
||||||
|
- **SCSS compilatie** — compileert `assets/scss/theme.scss` naar `assets/css_compiled/theme.css` via scssphp
|
||||||
|
- Layout resolveren naar `.twig` template (fallback op `config.default_template`)
|
||||||
|
|
||||||
|
`getCssUrl()` prioriteit: 1) `assets/css/theme.css` (handmatig), 2) `assets/css_compiled/theme.css` (gecompileerd).
|
||||||
|
|
||||||
## PluginManager.php
|
## PluginManager.php
|
||||||
|
|
||||||
Plugin systeem in `cms/core/class/PluginManager.php`:
|
Plugin systeem in `cms/core/plugin/PluginManager.php`:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
$pluginManager = new PluginManager();
|
$pluginManager = new PluginManager($pluginsPath, $enabledPlugins);
|
||||||
$pluginManager->loadPlugins($enabledPlugins);
|
$pluginManager->getSidebarContent($allowedPlugins);
|
||||||
|
$pluginManager->getPluginCssUrls();
|
||||||
$pluginManager->executeHook($name, $params);
|
$pluginManager->executeHook($name, $params);
|
||||||
|
$pluginManager->getAdminMenuItems();
|
||||||
|
$pluginManager->handleAdminRoute($route);
|
||||||
|
$pluginManager->getPluginType($pluginName);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Verantwoordelijkheden:
|
||||||
|
- Plugins laden vanuit `plugins/` mappen (alleen ingeschakelde plugins)
|
||||||
|
- Plugin bestand: `<PluginName>.php` (NIET `plugin.php`)
|
||||||
|
- Hooks en filters systeem (`doAction`, `applyFilters`)
|
||||||
|
- Sidebar content verzamelen van content plugins (`getSidebarContent`)
|
||||||
|
- Plugin CSS URLs verzamelen (`getPluginCssUrls`)
|
||||||
|
- **Admin menu items** van systeem plugins (`getAdminMenuItems`)
|
||||||
|
- **Admin routes** afhandelen via systeem plugins (`handleAdminRoute`)
|
||||||
|
- **Plugin type** bepalen (`getPluginType` — `content` of `system`)
|
||||||
|
- `isPluginViewable` — systeem plugins verschijnen niet in sidebar
|
||||||
|
|
||||||
|
## AdminAuth.php
|
||||||
|
|
||||||
|
Authenticatie en RBAC in `admin/src/AdminAuth.php`:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$auth = new AdminAuth($appConfig);
|
||||||
|
$auth->login($username, $password);
|
||||||
|
$auth->logout();
|
||||||
|
$auth->hasPermission($route);
|
||||||
|
$auth->verifyCsrf($token);
|
||||||
|
```
|
||||||
|
|
||||||
|
Constanten:
|
||||||
|
- `ROLE_PERMISSIONS` — Mapping van rol → toegestane route prefixes. `admin` heeft wildcard `*`.
|
||||||
|
- `ROLE_LABELS` — Human-readable labels per rol.
|
||||||
|
|
||||||
|
Rollen:
|
||||||
|
|
||||||
|
| Rol | Label | Permissies |
|
||||||
|
|-----|-------|-----------|
|
||||||
|
| `admin` | Admin | Alles (`*`) |
|
||||||
|
| `content-manager` | Content Beheerder | Content beheer, handleiding |
|
||||||
|
| `bi-manager` | BI Beheerder | Statistieken, logs, handleiding |
|
||||||
|
| `site-admin` | Site Admin | Thema, plugins, statistieken, logs, update, handleiding |
|
||||||
|
|
||||||
|
Verantwoordelijkheden:
|
||||||
|
- Session-based authenticatie
|
||||||
|
- bcrypt password hashing
|
||||||
|
- CSRF tokens (`verifyCsrf`)
|
||||||
|
- Brute-force lockout (login attempts tracking)
|
||||||
|
- RBAC via `hasPermission($route)` — checkt route tegen `ROLE_PERMISSIONS`
|
||||||
|
|
||||||
|
## CMSAPI.php
|
||||||
|
|
||||||
|
Plugin API in `cms/core/plugin/CMSAPI.php`:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$api = PluginManager::getAPI();
|
||||||
|
$config = $api->getConfig();
|
||||||
|
$page = $api->getPage($path);
|
||||||
|
$content = $api->getContent();
|
||||||
|
```
|
||||||
|
|
||||||
|
Biedt read-only toegang aan plugins tot CMS data (config, pagina's, content).
|
||||||
@@ -1,43 +1,144 @@
|
|||||||
# Plugin Development
|
# Plugin Development
|
||||||
|
|
||||||
|
## Plugin types
|
||||||
|
|
||||||
|
CodePress kent twee soorten plugins, bepaald door het `type` veld in `plugin.json`:
|
||||||
|
|
||||||
|
- **Content plugins** (`type: "content"`) — Verschijnen in de sidebar en in de plugin selectie op content-edit pagina's. Bieden sidebar content via `getSidebarContent()`.
|
||||||
|
- **Systeem plugins** (`type: "system"`) — Worden geladen door PluginManager maar verschijnen NIET in de sidebar. Bieden functionaliteit via admin menu, routes en de CMSAPI.
|
||||||
|
|
||||||
|
Bij afwezigheid van een `type` veld wordt `content` aangenomen.
|
||||||
|
|
||||||
## Plugin structuur
|
## Plugin structuur
|
||||||
|
|
||||||
```
|
```
|
||||||
plugins/MijnPlugin/
|
plugins/MijnPlugin/
|
||||||
├── plugin.json # Plugin metadata
|
├── MijnPlugin.php # Plugin code (NIET plugin.php)
|
||||||
├── plugin.php # Plugin code
|
├── plugin.json # Metadata met type veld
|
||||||
└── config.json # Optionele configuratie
|
├── config.json # Optionele configuratie
|
||||||
|
└── assets/
|
||||||
|
├── scss/mijnplugin.scss # SCSS bron (optioneel)
|
||||||
|
└── css/mijnplugin.css # CSS (handmatig onderhouden)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Plugin bestanden heten `<PluginName>.php` (bijv. `Navigation.php`, `HTMLBlock.php`). `PluginManager` laadt `$pluginDir . '/' . $pluginName . '.php'`.
|
||||||
|
|
||||||
## plugin.json
|
## plugin.json
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"name": "Mijn Plugin",
|
"name": "Mijn Plugin",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"author": "Jouw Naam",
|
"author": "Jouw Naam",
|
||||||
"description": "Beschrijving"
|
"description": "Beschrijving",
|
||||||
|
"type": "content"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## plugin.php voorbeeld
|
- `name` — Weergavenaam
|
||||||
|
- `type` — `"content"` of `"system"` (default: `content`)
|
||||||
|
|
||||||
|
## Content plugin voorbeeld
|
||||||
|
|
||||||
```php
|
```php
|
||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* Plugin: MijnPlugin
|
* Plugin: MijnPlugin (content)
|
||||||
*/
|
*/
|
||||||
|
class MijnPlugin
|
||||||
|
{
|
||||||
|
public function getConfig(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'title' => 'Mijn Plugin',
|
||||||
|
'type' => 'content',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
echo '<div class="mijn-plugin">Hello World</div>';
|
public function getSidebarContent(): string
|
||||||
|
{
|
||||||
|
return '<p>Hello World</p>';
|
||||||
|
}
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Systeem plugin voorbeeld
|
||||||
|
|
||||||
|
```php
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Plugin: MijnSysteem (system)
|
||||||
|
*/
|
||||||
|
class MijnSysteem
|
||||||
|
{
|
||||||
|
public function getConfig(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'title' => 'Mijn Systeem',
|
||||||
|
'type' => 'system',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAdminMenu(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['label' => 'Mijn Systeem', 'route' => 'mijn-systeem', 'icon' => 'bi-gear'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAdminRoutes(): array
|
||||||
|
{
|
||||||
|
return ['mijn-systeem'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handleAdminRoute(string $route): void
|
||||||
|
{
|
||||||
|
echo '<h1>Mijn Systeem pagina</h1>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Systeem plugins worden via `PluginManager::getAdminMenuItems()` in de admin sidebar getoond en via `PluginManager::handleAdminRoute()` afgehandeld.
|
||||||
|
|
||||||
## CMSAPI gebruiken
|
## CMSAPI gebruiken
|
||||||
|
|
||||||
```php
|
```php
|
||||||
<?php
|
<?php
|
||||||
require_once '../../cms/core/class/PluginManager.php';
|
|
||||||
|
|
||||||
$api = PluginManager::getAPI();
|
$api = PluginManager::getAPI();
|
||||||
$config = $api->getConfig();
|
$config = $api->getConfig();
|
||||||
$content = $api->getContent();
|
$page = $api->getPage($path);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
`setAPI()` wordt automatisch aangeroepen door `PluginManager` als de plugin de methode heeft.
|
||||||
|
|
||||||
|
## Plugin CSS
|
||||||
|
|
||||||
|
- Plugin CSS in `assets/css/` is handmatig te onderhouden (SCSS compilatie voor plugins is nog niet automatisch)
|
||||||
|
- Plugin CSS wordt automatisch geladen ná theme CSS (in `base.twig`), zodat thema's plugin styling kunnen overschrijven
|
||||||
|
- Plugin assets worden geserveerd via `cms/router.php` op URL `/plugins/<Name>/assets/...`
|
||||||
|
- Implementeer `getCssUrl()` in de plugin klasse om de CSS URL terug te geven
|
||||||
|
|
||||||
|
```php
|
||||||
|
public function getCssUrl(): string
|
||||||
|
{
|
||||||
|
return '/plugins/MijnPlugin/assets/css/mijnplugin.css';
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Hooks en filters
|
||||||
|
|
||||||
|
PluginManager auto-registert deze methoden als hooks/filters:
|
||||||
|
|
||||||
|
- **Hooks**: `onPageLoad`, `onBeforeRender`, `onAfterRender`, `onSearch`, `onMenuBuild`
|
||||||
|
- **Filters**: `onContentFilter`, `onTitleFilter`, `onMenuFilter`
|
||||||
|
|
||||||
|
```php
|
||||||
|
public function onPageLoad($page) { /* ... */ }
|
||||||
|
public function onContentFilter($content) { return $content; }
|
||||||
|
```
|
||||||
|
|
||||||
|
## Essentiële plugins
|
||||||
|
|
||||||
|
Essentiële plugins zijn gedefinieerd in `getProtectedPlugins()` in `public/admin.php`. Huidige essentiële plugin: **Navigation**.
|
||||||
|
|
||||||
|
Deze plugins kunnen niet worden gedeactiveerd, bewerkt of verwijderd. Voeg altijd de `isProtectedPlugin()` check toe aan nieuwe plugin handlers.
|
||||||
@@ -2,18 +2,60 @@
|
|||||||
|
|
||||||
## Frontend routing
|
## Frontend routing
|
||||||
|
|
||||||
Via `cms/router.php` voor PHP dev server:
|
Frontend routing verloopt via `cms/router.php` (PHP dev server) of `.htaccess` (Apache). Beide zorgen voor clean URLs.
|
||||||
|
|
||||||
```php
|
### PHP dev server
|
||||||
// Schone URLs: /nl/pagina
|
|
||||||
// Query: ?page=pagina&lang=nl
|
Start de server met:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
php -S localhost:8080 cms/router.php
|
||||||
```
|
```
|
||||||
|
|
||||||
|
`cms/router.php` serveert:
|
||||||
|
- Schone URLs: `/nl/pagina` → `public/index.php?page=pagina&lang=nl`
|
||||||
|
- `themes/` assets
|
||||||
|
- `admin/assets/` assets
|
||||||
|
- `plugins/` assets
|
||||||
|
|
||||||
|
### Apache (live server)
|
||||||
|
|
||||||
|
`public/.htaccess` herschrijft URLs naar `public/index.php`. Asset URLs (`/themes/`, `/admin/assets/`, `/plugins/`) worden doorgestuurd naar `public/asset.php`.
|
||||||
|
|
||||||
|
`public/asset.php` serveert bestanden vanuit de juiste mappen met het juiste MIME-type:
|
||||||
|
- `/themes/<name>/assets/...` → `themes/<name>/assets/...`
|
||||||
|
- `/admin/assets/...` → `admin/theme/default/assets/...`
|
||||||
|
- `/plugins/<name>/assets/...` → `plugins/<name>/assets/...`
|
||||||
|
|
||||||
## Admin routing
|
## Admin routing
|
||||||
|
|
||||||
Via `public/admin.php`:
|
Admin routing verloopt via `public/admin.php` met clean URLs:
|
||||||
|
|
||||||
|
```
|
||||||
|
/admin/dashboard → ?route=dashboard
|
||||||
|
/admin/content → ?route=content
|
||||||
|
/admin/plugins → ?route=plugins
|
||||||
|
```
|
||||||
|
|
||||||
|
`cms/router.php` of `.htaccess` zet `/admin/<route>` om naar `?route=<route>`.
|
||||||
|
|
||||||
|
### Route access control (RBAC)
|
||||||
|
|
||||||
|
Elke route wordt gecontroleerd via `AdminAuth::hasPermission($route)`:
|
||||||
|
- `admin` rol heeft wildcard `*` toegang
|
||||||
|
- Andere rollen hebben een expliciete lijst van toegestane routes in `ROLE_PERMISSIONS`
|
||||||
|
- Onbevoegde routes geven een **403 error**
|
||||||
|
|
||||||
|
## Plugin admin routing
|
||||||
|
|
||||||
|
Systeem plugins kunnen admin routes registreren. Deze worden afgehandeld door `PluginManager::handleAdminRoute($route)`:
|
||||||
|
|
||||||
|
1. Systeem plugin registreert routes via `getAdminRoutes()`
|
||||||
|
2. `PluginManager::getAdminMenuItems()` verzamelt admin menu items via `getAdminMenu()`
|
||||||
|
3. Bij een admin request zoekt `PluginManager::handleAdminRoute($route)` een plugin die de route afhandelt
|
||||||
|
4. De plugin methode `handleAdminRoute($route)` rendert de pagina inhoud
|
||||||
|
|
||||||
```php
|
```php
|
||||||
// Routes: /admin/dashboard, /admin/content, etc.
|
// PluginManager roept deze aan voor /admin/mijn-systeem
|
||||||
// Query parameter: ?route=dashboard
|
$plugin->handleAdminRoute('mijn-systeem');
|
||||||
```
|
```
|
||||||
@@ -4,28 +4,48 @@ Content wordt opgeslagen in de `content/` map zonder database.
|
|||||||
|
|
||||||
## Ondersteunde bestandsformaten
|
## Ondersteunde bestandsformaten
|
||||||
|
|
||||||
- `.md` - Markdown (aanbevolen)
|
- `.md` — Markdown (aanbevolen)
|
||||||
- `.php` - Dynamische PHP pagina's
|
- `.php` — Dynamische PHP pagina's
|
||||||
- `.html` - Statische HTML pagina's
|
- `.html` — Statische HTML pagina's
|
||||||
|
|
||||||
## Bestandsnaam conventies
|
## Bestandsnaam conventies
|
||||||
|
|
||||||
```
|
```
|
||||||
nl.pagina-naam.md # Nederlandse pagina
|
nl.pagina-naam.md # Nederlandse pagina
|
||||||
en.page-name.md # Engelse pagina
|
en.page-name.md # Engelse pagina
|
||||||
|
nl.map/ # Nederlandse map (vereist index bestand om klikbaar te zijn)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Taalprefix wordt dynamisch verwijderd op basis van beschikbare talen via `getAvailableLanguages()`.
|
||||||
|
|
||||||
## Frontmatter
|
## Frontmatter
|
||||||
|
|
||||||
Markdown bestanden kunnen frontmatter metadata bevatten:
|
Markdown bestanden kunnen frontmatter metadata bevatten:
|
||||||
|
|
||||||
```markdown
|
```markdown
|
||||||
---
|
---
|
||||||
layout: full_content
|
layout: left_sidebar
|
||||||
plugins: HTMLBlock
|
plugins:
|
||||||
|
- HTMLBlock
|
||||||
|
- Navigation
|
||||||
---
|
---
|
||||||
|
|
||||||
# Pagina titel
|
# Pagina titel
|
||||||
|
|
||||||
Content...
|
Content...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Frontmatter velden
|
||||||
|
|
||||||
|
- `layout` — Layout naam (moet voorkomen in `theme.json` template mapping; fallback op `config.default_template`)
|
||||||
|
- `plugins` — Lijst van content plugins die in de sidebar verschijnen
|
||||||
|
|
||||||
|
### plugins veld
|
||||||
|
|
||||||
|
Het `plugins` veld bepaalt:
|
||||||
|
- **Welke plugins** in de sidebar verschijnen (alleen content plugins, niet systeem plugins)
|
||||||
|
- **De volgorde** van de plugins in de sidebar (top tot onder)
|
||||||
|
|
||||||
|
De volgorde in de frontmatter is de volgorde waarin de plugins worden getoond. In de admin content-edit pagina kun je de volgorde aanpassen met up/down knoppen; de frontmatter wordt live bijgewerkt.
|
||||||
|
|
||||||
|
Plugins worden niet getoond als de gekozen layout geen sidebar heeft (bijv. `full_content`).
|
||||||
@@ -5,12 +5,44 @@
|
|||||||
1. Login op `/admin`
|
1. Login op `/admin`
|
||||||
2. Ga naar **Content**
|
2. Ga naar **Content**
|
||||||
3. Kies een map of maak een nieuwe pagina
|
3. Kies een map of maak een nieuwe pagina
|
||||||
4. Bewerk content in de editor
|
4. Bewerk content in de CodeMirror editor
|
||||||
5. Sla op met Ctrl+S
|
5. Sla op met Ctrl+S
|
||||||
|
|
||||||
## Editor functies
|
## Editor functies
|
||||||
|
|
||||||
- **CodeMirror** editor met syntax highlighting
|
- **CodeMirror** editor met syntax highlighting (Markdown, PHP, HTML)
|
||||||
- **Toolbar** voor snel Markdown invoegen
|
- **Toolbar** voor snel Markdown invoegen
|
||||||
- **Live preview** via knop
|
- **Sneltoetsen**: Ctrl+S (opslaan), Ctrl+N (nieuw)
|
||||||
- **Auto-save** backups in `.bak/` map
|
- **Auto-save** backups in `.bak/` map
|
||||||
|
|
||||||
|
## Layout selectie
|
||||||
|
|
||||||
|
Op de content-edit pagina kun je de layout kiezen uit de layouts gedefinieerd in `theme.json` (template mapping). De geselecteerde layout wordt opgeslagen in de frontmatter `layout:` key.
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
---
|
||||||
|
layout: left_sidebar
|
||||||
|
---
|
||||||
|
```
|
||||||
|
|
||||||
|
Onbekende layouts vallen terug op `config.default_template` uit `theme.json`.
|
||||||
|
|
||||||
|
## Plugin selectie en volgorde
|
||||||
|
|
||||||
|
Op de content-edit pagina kun je content plugins kiezen voor de sidebar:
|
||||||
|
|
||||||
|
- **Selectie** — Alleen content plugins (uit `plugin.json` met `type: "content"`) verschijnen in de plugin selectie
|
||||||
|
- **Volgorde** — Pas de volgorde aan met up/down knoppen
|
||||||
|
- **Frontmatter update** — De frontmatter `plugins:` key wordt live bijgewerkt bij wijzigingen
|
||||||
|
- **Layout zonder sidebar** — Plugins worden verborgen als de gekozen layout geen sidebar heeft (bijv. `full_content`)
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
---
|
||||||
|
layout: left_sidebar
|
||||||
|
plugins:
|
||||||
|
- HTMLBlock
|
||||||
|
- Navigation
|
||||||
|
---
|
||||||
|
```
|
||||||
|
|
||||||
|
De volgorde in de frontmatter bepaalt de volgorde van de plugins in de sidebar (top tot onder).
|
||||||
@@ -1,3 +1,12 @@
|
|||||||
# Handleiding
|
# Handleiding
|
||||||
|
|
||||||
|
Welkom bij de CodePress CMS handleiding (versie 2.5.2). CodePress is een file-based CMS zonder database — content, configuratie en gebruikers worden opgeslagen in bestanden.
|
||||||
|
|
||||||
|
De handleiding is verdeeld in vier secties:
|
||||||
|
|
||||||
|
- **Admin Beheerder** — Beheer van de website: dashboard, content, configuratie, thema's, beveiliging, plugins (content en systeem), gebruikers met rollen, statistieken en logs
|
||||||
|
- **Content Beheerder** — Content beheren: structuur, pagina's beheren (layout selectie, plugin volgorde), media en de Content API
|
||||||
|
- **Theme Developer** — Thema's ontwikkelen: structuur, `theme.json`, Twig templates, SCSS styling (enige CSS bron), layouts en nieuwe thema's
|
||||||
|
- **CodePress Developer** — Core ontwikkeling: architectuur, core classes, plugin development (content/systeem), routing, beveiliging (RBAC), testing, debugging en performance
|
||||||
|
|
||||||
Selecteer een onderwerp uit de navigatie aan de linkerkant.
|
Selecteer een onderwerp uit de navigatie aan de linkerkant.
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
# Layouts
|
# Layouts
|
||||||
|
|
||||||
|
Layouts definiëren de pagina structuur (sidebar links, volledige breedte, etc.). Layouts worden gedefinieerd in `theme.json` en gekozen via frontmatter in content bestanden.
|
||||||
|
|
||||||
## Layout kiezen in content
|
## Layout kiezen in content
|
||||||
|
|
||||||
```markdown
|
```markdown
|
||||||
@@ -14,14 +16,58 @@ Content...
|
|||||||
|
|
||||||
## Layouts in theme.json
|
## Layouts in theme.json
|
||||||
|
|
||||||
|
Layouts worden gedefinieerd in de `template` mapping. De `config.default_template` is de fallback voor pagina's zonder `layout:` frontmatter of met een onbekende layout:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"default_layout": "full_content",
|
"config": {
|
||||||
"layouts": {
|
"default_template": "full_content"
|
||||||
"full_content": "full_content.twig",
|
},
|
||||||
"left_sidebar": "left_sidebar.twig",
|
"template": {
|
||||||
"right_sidebar": "right_sidebar.twig",
|
"full_content": "full_content.twig",
|
||||||
"custom1": "custom1.twig"
|
"left_sidebar": "left_sidebar.twig",
|
||||||
}
|
"right_sidebar": "right_sidebar.twig",
|
||||||
|
"custom1": "custom1.twig",
|
||||||
|
"guide": "guide.twig"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Layout template
|
||||||
|
|
||||||
|
Een layout template extends `base.twig` en vult het `content` block:
|
||||||
|
|
||||||
|
```twig
|
||||||
|
{% extends 'base.twig' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="container">
|
||||||
|
{{ content|raw }}
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Layouts met sidebar
|
||||||
|
|
||||||
|
Layouts met sidebar kunnen plugin content tonen:
|
||||||
|
|
||||||
|
```twig
|
||||||
|
{% extends 'base.twig' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="row">
|
||||||
|
<main class="col-md-8">
|
||||||
|
{{ content|raw }}
|
||||||
|
</main>
|
||||||
|
<aside class="col-md-4">
|
||||||
|
{{ sidebar_content|raw }}
|
||||||
|
</aside>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
```
|
||||||
|
|
||||||
|
Als een pagina geen plugins heeft of de layout geen sidebar bevat, is `sidebar_content` leeg.
|
||||||
|
|
||||||
|
## Guide layout
|
||||||
|
|
||||||
|
De `guide` layout (`guide.twig`) is speciaal voor handleidingen. Het injecteert de Navigation plugin in de sidebar voor zijbalk navigatie. Wordt automatisch gebruikt voor pagina's in de `guide/` map.
|
||||||
@@ -2,20 +2,49 @@
|
|||||||
|
|
||||||
```
|
```
|
||||||
themes/mijn-thema/
|
themes/mijn-thema/
|
||||||
├── theme.json # Thema configuratie
|
├── theme.json # { title, config.default_template, template: layout→.twig }
|
||||||
├── base.twig # Hoofd layout
|
├── base.twig # Hoofd layout (head, header, nav, breadcrumb, footer)
|
||||||
├── full_content.twig # Layout: full-width
|
├── full_content.twig # Layout: volledige breedte
|
||||||
├── left_sidebar.twig # Layout: sidebar links
|
├── left_sidebar.twig # Layout: sidebar links
|
||||||
├── right_sidebar.twig # Layout: sidebar rechts
|
├── right_sidebar.twig # Layout: sidebar rechts
|
||||||
├── custom.twig # Layout: custom
|
├── custom1.twig # Layout: custom
|
||||||
|
├── guide.twig # Layout: handleiding met sidebar (Navigation plugin)
|
||||||
├── partials/
|
├── partials/
|
||||||
│ ├── header.twig
|
│ ├── header.twig
|
||||||
│ ├── navigation.twig
|
│ ├── navigation.twig
|
||||||
│ └── footer.twig
|
│ └── footer.twig
|
||||||
└── assets/
|
└── assets/
|
||||||
├── scss/theme.scss # SCSS bron
|
├── scss/theme.scss # SCSS bron (de enige CSS bron)
|
||||||
├── css/ # CSS bestanden
|
├── css_compiled/ # Gegenereerd door scssphp (read-only, niet handmatig aanpassen)
|
||||||
├── js/theme.js # JavaScript
|
├── css/ # Externe CSS (bootstrap.min.css, bootstrap-icons.css, mobile.css)
|
||||||
├── fonts/ # Lettertypes
|
├── js/ # app.js, bootstrap.bundle.min.js
|
||||||
└── img/ # Afbeeldingen
|
├── fonts/ # bootstrap-icons.woff, woff2
|
||||||
|
└── img/ # favicon, icon, world-map
|
||||||
|
```
|
||||||
|
|
||||||
|
## SCSS is de enige CSS bron
|
||||||
|
|
||||||
|
- **ALTIJD** `assets/scss/theme.scss` aanpassen — dit is de enige CSS bron
|
||||||
|
- `ThemeManager` compileert SCSS runtime naar `assets/css_compiled/theme.css` via scssphp
|
||||||
|
- `assets/css_compiled/` is **read-only** — niet handmatig aanpassen
|
||||||
|
- **NOOIT** `assets/css/theme.css` handmatig aanmaken of aanpassen; dit bestand mag niet bestaan
|
||||||
|
- `ThemeManager::getCssUrl()` prioriteit: 1) `assets/css/theme.css` (handmatig), 2) `assets/css_compiled/theme.css` (gecompileerd). Als `theme.css` bestaat, wordt de SCSS negeren.
|
||||||
|
- Na SCSS wijzigingen: verwijder `assets/css_compiled/theme.css` en `.mtime` om te forceren
|
||||||
|
|
||||||
|
```bash
|
||||||
|
rm themes/mijn-thema/assets/css_compiled/theme.css themes/mijn-thema/assets/css_compiled/.mtime
|
||||||
|
```
|
||||||
|
|
||||||
|
## guide.twig
|
||||||
|
|
||||||
|
Speciale layout voor handleidingen. Injecteert de Navigation plugin in de sidebar voor zijbalk navigatie. Wordt automatisch gebruikt voor pagina's in de `guide/` map.
|
||||||
|
|
||||||
|
## Plugin CSS laden
|
||||||
|
|
||||||
|
Plugin CSS wordt automatisch geladen ná theme CSS in `base.twig`, zodat thema's plugin styling kunnen overschrijven:
|
||||||
|
|
||||||
|
```twig
|
||||||
|
{% for cssUrl in plugin_css_urls|default([]) %}
|
||||||
|
<link href="{{ cssUrl }}" rel="stylesheet">
|
||||||
|
{% endfor %}
|
||||||
```
|
```
|
||||||
@@ -2,20 +2,45 @@
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"title": "Mijn Thema",
|
"title": "Mijn Thema",
|
||||||
"default_layout": "full_content",
|
"config": {
|
||||||
"header_color": "#0a369d",
|
"default_template": "full_content"
|
||||||
"layouts": {
|
},
|
||||||
"full_content": "full_content.twig",
|
"template": {
|
||||||
"left_sidebar": "left_sidebar.twig",
|
"full_content": "full_content.twig",
|
||||||
"right_sidebar": "right_sidebar.twig"
|
"left_sidebar": "left_sidebar.twig",
|
||||||
}
|
"right_sidebar": "right_sidebar.twig",
|
||||||
|
"custom1": "custom1.twig",
|
||||||
|
"guide": "guide.twig"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Velden
|
## Velden
|
||||||
|
|
||||||
- `title` - Weergavenaam in admin
|
- `title` — Weergavenaam in admin
|
||||||
- `default_layout` - Standaard layout voor nieuwe pagina's
|
- `config.default_template` — Standaard layout voor pagina's zonder `layout:` frontmatter (fallback bij onbekende layouts)
|
||||||
- `header_color` - Kleur admin sidebar
|
- `template` — Mapping van layout naam naar `.twig` bestand
|
||||||
- `layouts` - Mapping van layout namen naar .twig bestanden
|
|
||||||
|
## Template mapping
|
||||||
|
|
||||||
|
De `template` mapping definieert welke layouts beschikbaar zijn. Elke key is een layout naam, elke value is het `.twig` bestand:
|
||||||
|
|
||||||
|
| Layout naam | Twig bestand | Beschrijving |
|
||||||
|
|-------------|--------------|--------------|
|
||||||
|
| `full_content` | `full_content.twig` | Volledige breedte, geen sidebar |
|
||||||
|
| `left_sidebar` | `left_sidebar.twig` | Sidebar links |
|
||||||
|
| `right_sidebar` | `right_sidebar.twig` | Sidebar rechts |
|
||||||
|
| `custom1` | `custom1.twig` | Custom layout |
|
||||||
|
| `guide` | `guide.twig` | Handleiding met sidebar (Navigation plugin) |
|
||||||
|
|
||||||
|
## Layout keuze
|
||||||
|
|
||||||
|
- Layouts worden gekozen via frontmatter `layout:` key in content bestanden
|
||||||
|
- Onbekende layouts vallen terug op `config.default_template`
|
||||||
|
- `ThemeManager::getTemplates()` geeft de template mapping terug
|
||||||
|
- `ThemeManager::getConfig()` geeft de config sectie terug (inclusief `default_template`)
|
||||||
|
|
||||||
|
## Guide layout
|
||||||
|
|
||||||
|
De `guide` layout is speciaal voor handleidingen. `getGuidePage()` in `CodePressCMS.php` injecteert automatisch de Navigation plugin in de metadata voor zijbalk navigatie.
|
||||||
Reference in New Issue
Block a user