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:
2026-08-12 12:05:53 +02:00
parent c2bcd7be22
commit b38be8366c
35 changed files with 1493 additions and 255 deletions
+8 -8
View File
@@ -2,14 +2,14 @@
The admin manager guide contains the following topics:
- **Dashboard** - Website overview
- **Content management** - Managing files and pages
- **Configuration** - Site settings
- **Theme management** - Managing and creating themes
- **Security** - Bot protection and sessions
- **Plugins** - Managing and creating plugins
- **Users** - Adding and removing users
- **Statistics** - Viewing visitor statistics
- **Dashboard** - Role-based overview of the website (Admin, Content Manager, BI Manager, Site Admin)
- **Content management** - Managing files and pages with layout selection and plugins
- **Configuration** - Site settings (title, language, author, analytics, logging)
- **Theme management** - Managing, activating and creating themes (SCSS compilation)
- **Security** - Bot protection, rate limiting and session settings
- **Plugins** - Managing plugins: content (sidebar) and system (admin menu/API)
- **Users** - User management with roles (Admin, Content Manager, BI Manager, Site Admin)
- **Statistics** - Viewing and exporting visitor statistics
- **Logs** - Viewing and filtering log files
Select a topic from the navigation on the left.
+40 -11
View File
@@ -2,16 +2,45 @@
## Managing files
- **Upload** - Upload media files
- **New folder** - Create folder structure
- **New file** - Create a page
- **Edit** - Modify existing content
- **Rename** - Change file names
- **Move** - Move content
- **Delete** - Remove content
- **New folder** — Create folder structure
- **New file** Create a page (`.md`, `.php`, `.html`)
- **Edit** — Modify existing content in the CodeMirror editor
- **Rename** — Change file or folder names
- **Move** — Move content to another folder
- **Delete** — Remove content
- **Rename folder** — Change a folder name
## Editor
## Editor (content-edit)
- CodeMirror with syntax highlighting
- Toolbar for Markdown formatting
- Shortcuts: Ctrl+S (save), Ctrl+N (new)
- **CodeMirror** with syntax highlighting (Markdown, PHP, HTML)
- **Toolbar** for quickly inserting Markdown
- **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...
```
+26 -4
View File
@@ -1,10 +1,32 @@
# 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)
- Unique visitors
## Roles and widgets
### Admin
- Views (30 days) and unique visitors
- Number of pages and folders
- Active plugins
- 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.
+33 -6
View File
@@ -1,13 +1,40 @@
# 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**
2. Enter username
3. Choose password
4. Click **Add**
3. Choose password (stored as bcrypt hash)
4. Select a role
5. Click **Add**
## Delete user
## Editing a user
- Cannot delete own account
- Confirm with password
- 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
## 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`
+42 -8
View File
@@ -1,15 +1,49 @@
# 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
- **Enable/Disable** - Turn plugins on/off
- **Edit** - Modify plugin code
- **Configuration** - Plugin settings
- **Delete** - Remove plugin
- **Activate/Deactivate** Turn a plugin on/off (not for essential plugins)
- **Edit** Modify plugin code in CodeMirror (not for essential plugins)
- **Configuration** — Edit plugin settings
- **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**
2. Enter a name (e.g. `MyPlugin`)
3. Edit `plugin.php`
4. Enable the plugin
2. Enter a name (e.g. `MyPlugin`) — this becomes the folder name
3. Choose the type: **Content** or **System**
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/...`
+57 -12
View File
@@ -2,20 +2,65 @@
## Managing themes
1. Go to **Theme** in admin menu
2. **Activate** - Choose active theme
3. **Compile SCSS** - Process SCSS to CSS
4. **New theme** - Create custom theme
1. Go to **Theme** in the admin menu
2. **Activate** Choose the active theme (stored in `config.json`)
3. **Compile SCSS** Process SCSS to CSS (forced)
4. **New theme** Create a custom theme via admin or manually
## Theme structure
```
themes/default/
├── theme.json # Theme configuration
├── base.twig # Main layout
├── full_content.twig # Layouts
├── left_sidebar.twig
├── right_sidebar.twig
├── partials/ # Header, nav, footer
── assets/ # CSS, JS, images
```
├── theme.json # { title, config.default_template, template: layout→.twig }
├── base.twig # Main layout (head, header, nav, breadcrumb, footer)
├── full_content.twig # Layout: full width
├── left_sidebar.twig # Layout: sidebar on the left
├── right_sidebar.twig # Layout: sidebar on the right
├── custom1.twig # Layout: custom
── 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.
+15 -8
View File
@@ -2,13 +2,20 @@
The CodePress developer guide contains the following topics:
- **Architecture** - CMS architecture and folder structure
- **Core classes** - CodePressCMS, ThemeManager, PluginManager
- **Plugin development** - Developing plugins
- **Routing** - Frontend and admin routing
- **Security** - XSS, CSRF, path traversal
- **Testing** - Penetration, accessibility and functional tests
- **Debugging** - Logging and cache
- **Performance** - OPcache and SCSS caching
- **Architecture** CMS architecture and folder structure
- **Core classes** CodePressCMS, ThemeManager, PluginManager, AdminAuth
- **Plugin development** — Plugin types (content/system), structure, API
- **Routing** Frontend, admin and plugin admin routing
- **Security** XSS, CSRF, path traversal, RBAC
- **Testing** Penetration, accessibility and functional tests
- **Debugging** Logging and cache
- **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.
+80 -7
View File
@@ -1,11 +1,84 @@
# CMS Architecture
CodePress is a file-based CMS without a database. Content, configuration and users are stored in files.
## Folder structure
```
codepress/
├── cms/core/ # Core engine
├── admin/ # Admin console
├── themes/ # Themes
├── plugins/ # Plugins
├── content/ # Content
└── public/ # Web root
```
├── cms/ # Core CMS engine
│ ├── core/
│ │ ├── class/
│ │ │ ├── CodePressCMS.php # Main CMS class (routing, rendering, breadcrumb)
│ │ │ ├── ThemeManager.php # Theme resolver + Twig render + SCSS compile
│ │ │ ├── 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`)
+81 -4
View File
@@ -10,6 +10,13 @@ $cms->init();
$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
Theme management in `cms/core/class/ThemeManager.php`:
@@ -19,14 +26,84 @@ $themeManager = new ThemeManager($config);
$themeManager->getActiveTheme();
$themeManager->renderTwig($template, $data);
$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
Plugin system in `cms/core/class/PluginManager.php`:
Plugin system in `cms/core/plugin/PluginManager.php`:
```php
$pluginManager = new PluginManager();
$pluginManager->loadPlugins($enabledPlugins);
$pluginManager = new PluginManager($pluginsPath, $enabledPlugins);
$pluginManager->getSidebarContent($allowedPlugins);
$pluginManager->getPluginCssUrls();
$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 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
```
plugins/MyPlugin/
├── plugin.json # Plugin metadata
├── plugin.php # Plugin code
── config.json # Optional configuration
├── MyPlugin.php # Plugin code (NOT plugin.php)
├── plugin.json # Metadata with type field
── 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
```json
{
"name": "My Plugin",
"version": "1.0.0",
"author": "Your Name",
"description": "Description"
"name": "My Plugin",
"version": "1.0.0",
"author": "Your Name",
"description": "Description",
"type": "content"
}
```
## plugin.php example
- `name` — Display name
- `type``"content"` or `"system"` (default: `content`)
## Content plugin example
```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
```php
<?php
require_once '../../cms/core/class/PluginManager.php';
$api = PluginManager::getAPI();
$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.
+49 -7
View File
@@ -2,18 +2,60 @@
## 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
// Clean URLs: /nl/page
// Query: ?page=page&lang=nl
### PHP dev server
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
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
// Routes: /admin/dashboard, /admin/content, etc.
// Query parameter: ?route=dashboard
// PluginManager calls this for /admin/my-system
$plugin->handleAdminRoute('my-system');
```
@@ -4,28 +4,48 @@ Content is stored in the `content/` folder without a database.
## Supported file formats
- `.md` - Markdown (recommended)
- `.php` - Dynamic PHP pages
- `.html` - Static HTML pages
- `.md` Markdown (recommended)
- `.php` Dynamic PHP pages
- `.html` Static HTML pages
## 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
Markdown files can contain frontmatter metadata:
```markdown
---
layout: full_content
plugins: HTMLBlock
layout: left_sidebar
plugins:
- HTMLBlock
- Navigation
---
# Page title
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`).
+36 -4
View File
@@ -5,12 +5,44 @@
1. Login at `/admin`
2. Go to **Content**
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
## Editor features
- **CodeMirror** editor with syntax highlighting
- **CodeMirror** editor with syntax highlighting (Markdown, PHP, HTML)
- **Toolbar** for quick Markdown insertion
- **Live preview** via button
- **Auto-save** backups in `.bak/` folder
- **Shortcuts**: Ctrl+S (save), Ctrl+N (new)
- **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).
+9
View File
@@ -1,3 +1,12 @@
# 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.
+1 -1
View File
@@ -3,7 +3,7 @@
The theme developer guide contains the following topics:
- **Theme structure** - Folder structure of a theme
- **theme.json** - Theme configuration
- **theme.json** - Configuration of a theme
- **Twig templates** - Twig syntax, variables and blocks
- **SCSS styling** - Compiling and writing SCSS
- **Layouts** - Defining and using layouts
+54 -8
View File
@@ -1,5 +1,7 @@
# 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
```markdown
@@ -14,14 +16,58 @@ Content...
## 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
{
"default_layout": "full_content",
"layouts": {
"full_content": "full_content.twig",
"left_sidebar": "left_sidebar.twig",
"right_sidebar": "right_sidebar.twig",
"custom1": "custom1.twig"
}
"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"
}
}
```
```
## 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.
+40 -11
View File
@@ -2,20 +2,49 @@
```
themes/my-theme/
├── theme.json # Theme configuration
├── base.twig # Main layout
├── full_content.twig # Layout: full-width
├── left_sidebar.twig # Layout: left sidebar
├── right_sidebar.twig # Layout: right sidebar
├── custom.twig # Layout: custom
├── theme.json # { title, config.default_template, template: layout→.twig }
├── base.twig # Main layout (head, header, nav, breadcrumb, footer)
├── full_content.twig # Layout: full width
├── left_sidebar.twig # Layout: sidebar on the left
├── right_sidebar.twig # Layout: sidebar on the right
├── custom1.twig # Layout: custom
├── guide.twig # Layout: guide with sidebar (Navigation plugin)
├── partials/
│ ├── header.twig
│ ├── navigation.twig
│ └── footer.twig
└── assets/
├── scss/theme.scss # SCSS source
├── css/ # CSS files
├── js/theme.js # JavaScript
├── fonts/ # Fonts
── img/ # Images
├── scss/theme.scss # SCSS source (the only CSS source)
├── 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
```
## 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 %}
```
+37 -12
View File
@@ -2,20 +2,45 @@
```json
{
"title": "My Theme",
"default_layout": "full_content",
"header_color": "#0a369d",
"layouts": {
"full_content": "full_content.twig",
"left_sidebar": "left_sidebar.twig",
"right_sidebar": "right_sidebar.twig"
}
"title": "My Theme",
"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"
}
}
```
## Fields
- `title` - Display name in admin
- `default_layout` - Default layout for new pages
- `header_color` - Admin sidebar color
- `layouts` - Mapping of layout names to .twig files
- `title` Display name in admin
- `config.default_template` Default layout for pages without a `layout:` frontmatter (fallback for unknown layouts)
- `template` — Mapping from layout name to `.twig` file
## 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.