v2.5.1: Admin theme refactor, Navigation plugin, user roles, guide restructure

- Reorganize admin into admin/theme/default/ (views + assets)
- Rename GuideNav to Navigation plugin (essential, protected)
- Plugin assets support (SCSS/CSS) loaded after theme CSS
- User roles: Admin, Content Manager, BI Manager, Site Admin
- Role-based access control (RBAC) for admin routes and sidebar
- Guide restructure: sub-topics in separate folders with sidebar nav
- Dynamic breadcrumb for homepage and subdirectories
- Fix theme path traversal (../../ -> ../) in admin.php
- Fix CodeMirror mode load order (xml -> css -> js -> htmlmixed -> php)
- Fix editor-toolbar.js null checks for plugin edit pages
- Layout select from theme.json with live frontmatter update
- Footer sticky at bottom of viewport (min-height: 100vh)
- Breadcrumb color fix (var(--nav-font) -> var(--header-bg))
- Remove language switcher from guide pages
- Update README.md and README.en.md
- Bump version to 2.5.1
This commit is contained in:
2026-08-10 15:36:29 +02:00
parent 0961b23b8d
commit cd498c8c3a
209 changed files with 11033 additions and 9125 deletions
-754
View File
@@ -1,754 +0,0 @@
# CodePress CMS Guide
## Table of Contents
- [Overview](#overview)
- [Installation](#installation)
- [Project Structure](#project-structure)
- [Content](#content)
- [Content Structure](#content-structure)
- [Content API (for PHP content files)](#content-api-for-php-content-files)
- [Settings](#settings)
- [Configuration](#configuration)
- [Themes](#themes)
- [Security](#security)
- [Data](#data)
- [Statistics & Analytics](#statistics--analytics)
- [Logging](#logging)
- [System](#system)
- [Plugin System](#plugin-system)
- [User Management](#user-management)
- [Update](#update)
- [Guide (in Admin)](#guide-in-admin)
- [Other](#other)
- [Templates](#templates)
- [URL Structure](#url-structure)
- [SEO Optimization](#seo-optimization)
- [Frequently Asked Questions](#frequently-asked-questions)
- [Troubleshooting](#troubleshooting)
- [Version](#version)
- [Support](#support)
- [License](#license)
## Overview
CodePress CMS is a lightweight, file-based content management system built with PHP (>=8.0). Works without a database.
## Installation
1. Upload files to web server
2. Set permissions for web server
3. Run `composer install` for CommonMark dependency
4. Configure `config.json` if needed
5. Access website via browser
6. **PHP development server**: `php -S localhost:8080 -t public` (uses `cms/router.php`)
## Project Structure
```
codepress/
├── cms/ # Core CMS engine
│ ├── core/
│ │ ├── class/
│ │ │ ├── CodePressCMS.php # Main CMS class (content, navigation, search)
│ │ │ ├── ThemeManager.php # Theme resolver + Twig render + SCSS compile
│ │ │ ├── Logger.php # Structured logging system
│ │ │ ├── Analytics.php # Visitor statistics
│ │ │ ├── BotGuard.php # Bot/AI/scraper detection
│ │ │ ├── GeoIP.php # Country lookup by IP
│ │ │ ├── Cache.php # File-based caching
│ │ │ └── RateLimiter.php # Per-IP rate limiting
│ │ ├── plugin/
│ │ │ ├── PluginManager.php # Plugin loader and manager
│ │ │ └── CMSAPI.php # API for plugin developers
│ │ ├── config.php # Configuration loader (merge with config.json)
│ │ └── index.php # Bootstrap (autoloader, requires)
│ ├── lang/ # Language files
│ │ ├── nl.php # Dutch translations
│ │ └── en.php # English translations
│ └── router.php # PHP dev server router (also serves /themes/)
├── themes/ # Dynamic themes (fully self-contained)
│ ├── default/ # Default theme
│ │ ├── theme.json # { title, config.default_template, template→.twig mapping }
│ │ ├── base.twig # Main layout (head, header, nav, footer)
│ │ ├── full_content.twig # Layout: full width
│ │ ├── left_sidebar.twig # Layout: sidebar left
│ │ ├── right_sidebar.twig # Layout: sidebar right
│ │ ├── custom1.twig # Layout: custom
│ │ ├── partials/ # header.twig, navigation.twig, footer.twig
│ │ ├── css/theme.scss # Colors, heights, background (compiled at runtime)
│ │ ├── js/theme.js # Theme JavaScript
│ │ └── theme.png # Preview image
│ ├── demo/ # Demo theme (same structure, different look)
│ └── test/ # Test theme
├── admin/ # Admin panel
│ ├── config/
│ │ ├── app.php # Admin app configuration (paths, timezone)
│ │ └── admin.json # Users & security (bcrypt hashes)
│ ├── src/
│ │ └── AdminAuth.php # Authentication (sessions, bcrypt, CSRF, lockout)
│ ├── templates/
│ │ ├── login.php # Login page
│ │ ├── layout.php # Admin layout with sidebar navigation
│ │ └── pages/
│ │ ├── dashboard.php # Dashboard with statistics
│ │ ├── content.php # Content overview with file upload
│ │ ├── content-edit.php # CodeMirror editor with toolbar and rename
│ │ ├── content-new.php # Create new content
│ │ ├── content-dir-form.php # Create/edit directory
│ │ ├── content-move-form.php # Move content
│ │ ├── config.php # Configuration editor
│ │ ├── security.php # Security settings
│ │ ├── statistics.php # Statistics dashboard
│ │ ├── plugins.php # Plugin overview
│ │ ├── plugins-edit.php # Plugin PHP source code editor
│ │ ├── plugins-new.php # Create new plugin
│ │ ├── plugin-config.php # Plugin configuration editor
│ │ ├── theme.php # Theme management
│ │ ├── users.php # User management
│ │ ├── logs.php # Log viewer
│ │ ├── update.php # System update
│ │ └── guide.php # Guide
│ └── storage/logs/ # Admin logs
├── cli/ # CLI scripts & tests
├── content/ # Content files
│ ├── -assets/ # Uploaded media files
│ ├── index.md # Default homepage
│ └── ... # Other content
├── plugins/ # CMS plugins
│ ├── HTMLBlock/ # Custom HTML blocks in sidebar
│ └── MQTTTracker/ # Real-time analytics and tracking
├── public/ # Web root
│ ├── index.php # Website entry point (media serving + CMS)
│ ├── admin.php # Admin entry point + routing
│ ├── .htaccess # Apache rewrite/security rules
│ ├── assets/ # CSS, JS, favicons
│ │ ├── codemirror/ # CodeMirror editor (minified JS/CSS)
│ │ └── css/js/ # Bootstrap, icons, app CSS/JS
│ ├── themes/ # Runtime compiled theme CSS (public/themes)
│ └── manifest.json / sw.js # PWA support
├── themes/ # Dynamic themes (fully self-contained)
│ ├── default/ # Default theme
│ │ ├── theme.json # Title, default template, template mapping
│ │ ├── base.twig # Main layout
│ │ ├── *.twig # Layout templates (full_content, left_sidebar, ...)
│ │ ├── partials/ # header, navigation, footer
│ │ ├── css/theme.scss # Colors, heights, background
│ │ ├── js/theme.js # Theme JavaScript
│ │ └── theme.png # Preview image
│ ├── demo/ # Demo theme
│ └── test/ # Test theme
├── config.json # Site configuration
├── version.php # Version information
└── vendor/ # Composer dependencies
```
---
## Content
### Content Structure
#### File Structure
```
content/
├── folder1/
│ ├── subfolder1/
│ │ ├── nl.page1.md
│ │ └── en.page1.md
│ └── page3.html
├── folder2/
│ └── page4.md
├── index.md
└── -assets/
├── image.jpg
└── document.pdf
```
#### File Naming
- Use lowercase filenames
- No spaces - use `-` or `_`
- Logical extensions - `.md`, `.php`, `.html`
- Unique names - no duplicates
- Language prefixes - `nl.file.md` and `en.file.md`
#### Media Files
Media files (images, PDFs, video, audio) can be placed in any `content/` subdirectory and are served via:
- **`/-media/path/file.jpg`** - Media from any content subdirectory
- **`/-assets/file.jpg`** - Backward compatibility (old URLs)
- Uploads via the admin panel go to `content/-assets/`
### Content API (for PHP content files)
PHP content files (`.php` in the `content/` directory) have access to an `$api` variable with the following methods:
#### Getting pages
```php
// Get all pages with titles
$pages = $api->getAllPages();
// Result: ['index' => 'Home', 'about' => 'About Us', ...]
// Get a specific page's content
$page = $api->getPage('about');
// $page['title'], $page['content'], $page['path'], $page['layout'], $page['metadata']
// Check if a page exists
if ($api->pageExists('contact')) {
// ...
}
```
#### Navigation
```php
// Get menu structure
$menu = $api->getMenu();
// Nested array with 'title', 'path', 'url', 'children'
```
#### Configuration
```php
// Get config value (dot notation)
$title = $api->getConfig('site_title');
$lang = $api->getConfig('language.default');
$seoDesc = $api->getConfig('seo.description', 'Default description');
```
#### Current page
```php
// Current page title
$pageTitle = $api->getCurrentPageTitle();
// Current page path
$pagePath = $api->getCurrentPagePath();
// Check if this is the homepage
if ($api->isHomepage()) {
echo 'Welcome!';
}
```
#### URLs and language
```php
// Build URL for a page
$url = $api->buildUrl('about', 'en');
// Current language
$lang = $api->getCurrentLanguage();
// Available languages
$languages = $api->getAvailableLanguages();
// Site title
$title = $api->getSiteTitle();
```
#### Translations and search
```php
// Get translation
$label = $api->t('home');
// Search results (if searching)
if ($api->isSearching()) {
$results = $api->getSearchResults();
}
```
#### Example PHP content file
```php
---
title: Page Overview
layout: content
---
<h1>All Pages</h1>
<ul>
<?php foreach ($api->getAllPages() as $path => $title): ?>
<li><a href="<?= $api->buildUrl($path) ?>"><?= htmlspecialchars($title) ?></a></li>
<?php endforeach; ?>
</ul>
```
---
## Settings
### Configuration
The site configuration is managed via the **admin panel** at `/admin/config`. The form includes:
- **General settings** - Site title and homepage (dropdown with available pages)
- **Language** - Default language and available languages
- **SEO** - Meta description and keywords
- **Author** - Name and website
- **Features** - Auto-link pages, search, breadcrumbs, show version
- **IP Exclusions** - Exclude IP addresses from statistics and security checks
The configuration is stored in `config.json`. You can also edit this file manually for advanced options.
#### IP Exclusions
Under **Configuration** in the admin panel, the "IP Exclusions" field lets you specify IP addresses that will be:
- Excluded from visitor statistics
- Skipped during all security checks (bot detection, rate limiting, IP blocklist)
This is useful for your own IP address or internal monitoring tools.
#### Example `config.json`
```json
{
"site_title": "CodePress",
"content_dir": "content",
"default_page": "index",
"active_theme": "default",
"language": {
"default": "en",
"available": ["nl", "en"]
},
"seo": {
"description": "CodePress CMS - Lightweight file-based content management system",
"keywords": "cms, php, content management, file-based"
},
"author": {
"name": "E. Noorlander",
"website": "https:\/\/noorlander.info"
},
"features": {
"auto_link_pages": true,
"search_enabled": true,
"breadcrumbs_enabled": true
},
"analytics": {
"enabled": true,
"excluded_ips": ["127.0.0.1", "::1"]
},
"security": {
"block_ai_bots": true,
"block_scrapers": true,
"block_empty_user_agent": true,
"rate_limit_enabled": true
}
}
```
### Themes
Themes are managed via the admin panel at `/admin/theme`. This is a selection page: pick the active theme and click "Activate theme". Each theme is a fully self-contained folder in `themes/` with its own Twig templates, SCSS and JavaScript.
#### Theme structure (`themes/<name>/`)
```
themes/<name>/
├── theme.json # Title, default template, template mapping
├── base.twig # Main layout (head, header, nav, footer)
├── full_content.twig # Layout: full width
├── left_sidebar.twig # Layout: sidebar left
├── right_sidebar.twig # Layout: sidebar right
├── custom1.twig # Layout: custom
├── partials/ # header.twig, navigation.twig, footer.twig
├── css/theme.scss # Colors, heights, background (compiled at runtime)
├── js/theme.js # Theme JavaScript
└── theme.png # Preview image (shown in admin)
```
#### Theme Configuration (`themes/<name>/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"
}
}
```
- **`config.default_template`**: the default template used when a page requests an unknown layout.
- **`template`**: the layout-key → `.twig` file mapping. A theme can have multiple template pages.
Colors, heights and background are **not** set in `theme.json` but in `css/theme.scss`:
```scss
$header-bg: #0a369d;
$header-font: #ffffff;
$header-height: 56px;
$nav-bg: #2754b4;
$nav-font: #ffffff;
$nav-height: 42px;
$sidebar-bg: #f8f9fa;
$sidebar-border: #dee2e6;
$header-bg-image: none; // optional header background
$header-bg-opacity: 1;
```
The SCSS is compiled at runtime into `public/themes/<name>/theme.css`.
#### How to create a new theme
Themes are created manually: copy the `themes/default/` folder to `themes/<name>/`, adjust the SCSS colors and templates, and add a `theme.png` preview. The theme is then available on `/admin/theme` to activate.
### Security
Security settings are managed via `/admin/security`. Includes:
#### Bot, AI & Scraper Blocking
Incoming requests are checked against known bot and AI crawler patterns via the User-Agent header. Detected bots receive a **403 Forbidden** response.
| Category | Examples |
|---|---|
| AI Crawlers | GPTBot, ChatGPT-User, Claude-Web, ClaudeBot, Google-Extended, CCBot, PerplexityBot |
| Search Engines | Googlebot, Bingbot, BingPreview, DuckDuckBot, YandexBot, Baiduspider |
| Scrapers | HTTrack, Scrapy, PhantomJS |
#### Rate Limiting
Prevents IPs from overloading the site. Returns HTTP 429 on exceedance.
#### IP Lists
- **IP Whitelist** - IPs on the whitelist are never blocked
- **IP Blocklist** - IPs on the blocklist always receive a 403 Forbidden
#### Dynamic robots.txt
The system automatically generates a `robots.txt` based on your security settings, available at `/robots.txt`.
---
## Data
### Statistics & Analytics
The statistics dashboard is available at `/admin/statistics` and provides:
- **KPI cards** - Page views, unique visitors, human/bot ratio, blocked requests
- **World map** - Visual representation of visitors per country with color intensity
- **Countries list** - Top 25 countries with percentage
- **Most viewed pages** - Top 25 pages
- **Daily chart** - Bar chart of visitors per day
- **Referring sites** - Top 15 referrers
#### Periods and export
Filter by 7, 30, 90 days or all time. Export data as CSV or JSON.
#### GeoIP
Country detection via three sources:
- **Local (DB-IP Lite)** - Offline, privacy-friendly, auto-updated
- **MaxMind database (.mmdb)** - Custom MMDB file
- **External API** - Custom API URL and key
### Logging
The admin console maintains logs, viewable at `/admin/logs`:
- **Activity log** (`admin/storage/logs/admin.log`) — admin actions like creating, editing, deleting pages, enabling/disabling plugins, changing configuration.
- **Request log** (`admin/storage/logs/requests.log`) — every page view on the website, including IP, page, domain, language, user agent, and referrer.
- **Dynamic log** — structured log entries via `LogManager`, with event type, level, IP, and message.
#### Configuring dynamic logging
Via `/admin/config`**Logging** you can configure how and what is recorded:
- **Storage**: `SQLite` (default) or `Syslog`.
- **Syslog server**: if a host is provided, log entries are sent to that server over UDP. Leave empty to use SQLite.
- **Facility**: the category of the log source in syslog. `local0``local7` are for your own applications; `daemon`, `user`, and `auth` are standard system categories.
- **Syslog ident**: the name that appears in the log message (e.g. `codepress`).
- **Events**: choose which types are recorded — `admin`, `requests`, `errors`, `security`, `content`, `system`.
If no syslog server is configured, SQLite is always used (with a file fallback if SQLite is unavailable).
The dashboard shows the last 20 entries of each log. Click "View all →" for the full list, where you can also download or clear.
---
## System
### Plugin System
#### Plugin Structure
```
plugins/
├── HTMLBlock/
│ ├── HTMLBlock.php # Plugin class (required)
│ ├── config.json # Configuration (optional)
│ └── README.md # Documentation (optional)
├── MQTTTracker/
│ ├── MQTTTracker.php
│ ├── config.json
│ └── README.md
```
#### Plugin Development
- **API access** via `CMSAPI` class - gives access to CMS configuration, templates, menu
- **Sidebar content** with `getSidebarContent()` - returns HTML for sidebar
- **Metadata access** from YAML frontmatter via `CMSAPI`
- **Configuration** via `config.json` - editable through admin panel
- **viewable** field in config.json determines if plugin is visible in sidebar
- **Per-page visibility** - via the editor plugin selector per page
#### Plugin Boilerplate
```php
<?php
class MyPlugin
{
private ?CMSAPI $api = null;
private array $config;
public function __construct()
{
$this->config = [
'viewable' => true,
];
}
public function setAPI(CMSAPI $api): void
{
$this->api = $api;
}
public function getSidebarContent(): string
{
return '';
}
public function getConfig(): array
{
return $this->config;
}
public function setConfig(array $config): void
{
$this->config = array_merge($this->config, $config);
}
}
```
#### Known Issue: MQTTTracker Credentials
The MQTTTracker plugin stores `broker_host`, `broker_port`, `client_id`, `username` and `password` in plain text in `plugins/MQTTTracker/config.json`. This is a known open security issue - in a production environment it is recommended to externalize these credentials to environment variables or a separate credential manager.
### User Management
Users are managed via `/admin/users`. Features:
- Add user with username, password and role
- Delete user
- Change password for other users (admin)
- Change own password (requires current password)
Passwords are stored as bcrypt hashes in `admin/config/admin.json`.
### Update
Via `/admin/update` the system can be updated in one click via Git pull. The page shows the current version and git branch, and executes `git pull origin <branch>` on confirmation.
---
## Guide (in Admin)
This guide is also built into the admin panel via `/admin/guide`, with support for Dutch and English.
---
## Other
### Templates
Templates are Twig files per theme in `themes/<name>/`. `ThemeManager` renders them and compiles `css/theme.scss` at runtime into `public/themes/<name>/theme.css`.
#### Template Variables
**Site Info** - `site_title`, `author_name`, `author_website`, `author_git`
**Page Info** - `page_title`, `content`, `file_info`, `is_homepage`
**Navigation** - `menu`, `breadcrumb`, `homepage`
**Theme** - `theme_title`, `theme_css_url`, `theme_js_url`, `theme_config` (config from theme.json)
**Language** - `current_lang`, `current_lang_upper`, `t_*` (translated strings)
#### Layout Options
Use YAML frontmatter to select the template. The layout key references a template in the active theme:
```yaml
---
title: My Page
layout: left_sidebar
plugins: HTMLBlock
---
```
#### Available Layouts
The available layouts are defined by the `template` section of the active theme (`themes/<name>/theme.json`). The default theme includes:
- `full_content` - Content only (full width)
- `left_sidebar` - Sidebar left, content right
- `right_sidebar` - Content left, sidebar right
- `custom1` - Custom layout
If a page requests an unknown layout, the `default_template` from the theme's `config` is used.
#### Meta Data
```yaml
---
title: Page Title
layout: left_sidebar
description: Page description
author: Author Name
date: 2025-11-26
plugins: HTMLBlock, MQTTTracker
---
```
### URL Structure
#### Frontend Page URLs
- **Home**: `/` or `/en/`
- **Page**: `/en/folder/page`
- **Search**: `?search=query` (via search form)
#### Media URLs
- **Media**: `/-media/path/to/file.jpg` (from any content subdirectory)
- **Assets**: `/-assets/file.jpg` (from content/-assets/, backward compatible)
#### Admin URLs
- **Admin**: `/admin`
- **Dashboard**: `/admin/dashboard`
- **Content**: `/admin/content`
- **Configuration**: `/admin/config`
- **Security**: `/admin/security`
- **Statistics**: `/admin/statistics`
- **Theme**: `/admin/theme`
- **Plugins**: `/admin/plugins`
- **Users**: `/admin/users`
- **Logs**: `/admin/logs`
- **Update**: `/admin/update`
- **Guide**: `/admin/guide`
### SEO Optimization
#### Meta Tags
The CMS automatically adds meta tags:
```html
<meta name="generator" content="CodePress CMS">
<meta name="author" content="E. Noorlander">
<meta name="description" content="...">
<meta name="keywords" content="...">
```
#### Security Headers
```http
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
Referrer-Policy: strict-origin-when-cross-origin
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'; ...
```
### Frequently Asked Questions
#### How do I set the homepage?
1. Go to **Configuration** in the admin panel (`/admin/config`)
2. Select the desired page in the **Default/homepage** dropdown
3. Click **Save configuration**
#### How does navigation work?
- **Directories** become dropdown menus
- **Files** become direct links
- **Sub-directories** become nested dropdowns
- Only files without a language prefix show in the menu
#### How do I add new content?
1. Via the admin panel: `/admin/content-new`
2. Or upload files to the `content/` directory
3. Organize in logical directories
4. Use correct filenames and extensions
#### How do I move a file or directory?
1. Go to `/admin/content`
2. Click "Move" next to the item
3. Select the target directory
4. Confirm the move
#### How do I exclude my own IP from statistics?
1. Go to **Configuration** in the admin panel (`/admin/config`)
2. Scroll to the "IP Exclusions" field
3. Enter your IP address (one per line)
4. Click **Save configuration**
### Troubleshooting
#### Page not found (404)
1. Check filename and path
2. Check file extension (.md, .php, .html)
3. Check file permissions
4. Check if the file has the correct language prefix (`nl.` or `en.`)
#### Navigation not updated
1. Reload the page
2. Check content directory structure
3. Check filenames (no spaces)
4. Files with language prefix only show in the correct language mode
#### Admin panel not accessible
1. Check if the session is still valid
2. On lockout: wait 15 minutes or clear lockout data in `admin/config/admin.json`
3. Check CSRF token (reload the page)
## Version
Current version: **1.9.1**
Release date: 2026-07-29
## Support
For technical support:
- **Git**: https://git.noorlander.info/E.Noorlander/CodePress
- **Website**: https://noorlander.info
- **Issues**: Report problems via Git issues
## License
CodePress CMS is open-source software under dual-license: AGPL v3 for open-source use, commercial license for proprietary use.
+15
View File
@@ -0,0 +1,15 @@
# Admin Manager
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
- **Logs** - Viewing and filtering log files
Select a topic from the navigation on the left.
+12
View File
@@ -0,0 +1,12 @@
# Security
## Bot protection
- **BotGuard** - Bot/AI detection
- **Rate limiting** - Limit requests per IP
- **Block/allowlist** - Block or allow IPs
## Session settings
- **Session timeout** - Default 3600 seconds
- **Max login attempts** - Default 5 attempts
+9
View File
@@ -0,0 +1,9 @@
# Configuration
## General settings
- **Site title** - Website name
- **Default language** - nl/en/de/fr
- **Author** - Name and email
- **Analytics** - Visitor tracking on/off
- **Logging** - Log files on/off
@@ -0,0 +1,17 @@
# Content management
## 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
## Editor
- CodeMirror with syntax highlighting
- Toolbar for Markdown formatting
- Shortcuts: Ctrl+S (save), Ctrl+N (new)
+10
View File
@@ -0,0 +1,10 @@
# Dashboard
The dashboard shows an overview of:
- Views (30 days)
- Unique visitors
- Number of pages and folders
- Active plugins
- Recent activity
- Quick actions
+13
View File
@@ -0,0 +1,13 @@
# Users
## Add user
1. Go to **Users**
2. Enter username
3. Choose password
4. Click **Add**
## Delete user
- Cannot delete own account
- Confirm with password
+12
View File
@@ -0,0 +1,12 @@
# Logs
## Log types
- **Admin** - Admin actions
- **Requests** - Website visits
## Filter
- Search by IP, message
- Filter by level (info, warning, error)
- Download as file
+15
View File
@@ -0,0 +1,15 @@
# Plugins
## Managing plugins
- **Enable/Disable** - Turn plugins on/off
- **Edit** - Modify plugin code
- **Configuration** - Plugin settings
- **Delete** - Remove plugin
## New plugin
1. Go to **Plugins****New plugin**
2. Enter a name (e.g. `MyPlugin`)
3. Edit `plugin.php`
4. Enable the plugin
+14
View File
@@ -0,0 +1,14 @@
# Statistics
## Overview
- Total views
- Unique visitors
- Countries with flags
- Top pages
- Referrers
## Filters
- Period: 7/30/90 days or all
- Export: CSV or JSON
+21
View File
@@ -0,0 +1,21 @@
# Theme management
## 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
## 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
```
+14
View File
@@ -0,0 +1,14 @@
# CodePress Developer
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
Select a topic from the navigation on the left.
@@ -0,0 +1,11 @@
# CMS Architecture
```
codepress/
├── cms/core/ # Core engine
├── admin/ # Admin console
├── themes/ # Themes
├── plugins/ # Plugins
├── content/ # Content
└── public/ # Web root
```
@@ -0,0 +1,34 @@
# Security
## XSS prevention
```php
// Always escape
echo htmlspecialchars($userInput, ENT_QUOTES, 'UTF-8');
// In Twig (automatic)
{{ userVariable }}
```
## CSRF tokens
```php
// Generate
$csrf = $auth->getCsrfToken();
// Verify
if (!$auth->verifyCsrf($_POST['csrf_token'])) {
die('Invalid CSRF token');
}
```
## Path traversal prevention
```php
// Use realpath() and check prefix
$realPath = realpath($filePath);
$realContentDir = realpath($contentDir);
if (strpos($realPath, $realContentDir) !== 0) {
die('Invalid path');
}
```
@@ -0,0 +1,32 @@
# Core Classes
## CodePressCMS.php
Main CMS class in `cms/core/class/CodePressCMS.php`:
```php
$cms = new CodePressCMS();
$cms->init();
$cms->renderPage($pagePath);
```
## ThemeManager.php
Theme management in `cms/core/class/ThemeManager.php`:
```php
$themeManager = new ThemeManager($config);
$themeManager->getActiveTheme();
$themeManager->renderTwig($template, $data);
$themeManager->compileCss($force);
```
## PluginManager.php
Plugin system in `cms/core/class/PluginManager.php`:
```php
$pluginManager = new PluginManager();
$pluginManager->loadPlugins($enabledPlugins);
$pluginManager->executeHook($name, $params);
```
+23
View File
@@ -0,0 +1,23 @@
# Debugging
## Logging
```php
// Admin logging
adminLog($config, 'info', 'Message text');
// LogManager
LogManager::log(LogManager::EVENT_ADMIN, 'info', 'Message');
```
## Disabling cache
In `config.json`:
```json
{
"cache": {
"enabled": false
}
}
```
@@ -0,0 +1,19 @@
# Performance
## Enabling OPcache
In `php.ini`:
```ini
opcache.enable=1
opcache.memory_consumption=128
opcache.max_accelerated_files=10000
```
## SCSS caching
SCSS is compiled with caching:
```php
$themeManager->compileCss(false); // Use cache when possible
```
@@ -0,0 +1,43 @@
# Plugin Development
## Plugin structure
```
plugins/MyPlugin/
├── plugin.json # Plugin metadata
├── plugin.php # Plugin code
└── config.json # Optional configuration
```
## plugin.json
```json
{
"name": "My Plugin",
"version": "1.0.0",
"author": "Your Name",
"description": "Description"
}
```
## plugin.php example
```php
<?php
/**
* Plugin: MyPlugin
*/
echo '<div class="my-plugin">Hello World</div>';
```
## Using CMSAPI
```php
<?php
require_once '../../cms/core/class/PluginManager.php';
$api = PluginManager::getAPI();
$config = $api->getConfig();
$content = $api->getContent();
```
+19
View File
@@ -0,0 +1,19 @@
# Routing
## Frontend routing
Via `cms/router.php` for PHP dev server:
```php
// Clean URLs: /nl/page
// Query: ?page=page&lang=nl
```
## Admin routing
Via `public/admin.php`:
```php
// Routes: /admin/dashboard, /admin/content, etc.
// Query parameter: ?route=dashboard
```
+22
View File
@@ -0,0 +1,22 @@
# Testing
## Penetration tests
```bash
cd cli/test/pentest
./security-test.sh
```
## Accessibility tests
```bash
cd cli/test
./accessibility.sh
```
## Functional tests
```bash
cd cli/test/functional
./content-tests.sh
```
+10
View File
@@ -0,0 +1,10 @@
# Content Manager
The content manager guide contains the following topics:
- **Content structure** - How content is stored
- **Managing pages** - Creating and editing pages
- **Managing media** - Uploading and using media
- **Content API** - Using the Content API in PHP pages
Select a topic from the navigation on the left.
+119
View File
@@ -0,0 +1,119 @@
# Content API
The Content API is available in PHP content files (`.php`) and provides a safe, read-only interface to CMS data.
## Usage in PHP content files
```php
<?php
/** @var ContentAPI $api */
// Get all pages
$allPages = $api->getAllPages();
// Result: ['index' => 'Home', 'about-us' => 'About Us', ...]
// Get a specific page
$page = $api->getPage('about-us');
// Result: ['title' => 'About Us', 'content' => '...', 'path' => 'about-us', 'layout' => 'full_content', 'metadata' => [...]]
// Get menu structure
$menu = $api->getMenu();
// Result: [['title' => 'Home', 'path' => 'index', 'type' => 'file', 'active' => true], ...]
// Get config value (dot notation)
$siteTitle = $api->getConfig('site_title');
$searchEnabled = $api->getConfig('features.search_enabled', false);
```
## Available methods
### Pages
- `getAllPages(): array` - All pages as `['path' => 'title']` pairs
- `getPage(string $path): ?array` - Specific page with `title`, `content`, `path`, `layout`, `metadata`
- `pageExists(string $path): bool` - Check if a page exists
- `getCurrentPageTitle(): string` - Title of current page
- `getCurrentPagePath(): string` - Path of current page
- `isHomepage(): bool` - Whether current page is the homepage
### Menu & Navigation
- `getMenu(): array` - Hierarchical menu structure with `title`, `path`, `children`, `active`
- `buildUrl(string $page = 'index', ?string $lang = null, array $params = []): string` - Build a URL for a page
### Configuration
- `getConfig(string $key, mixed $default = null): mixed` - Config value via dot notation (e.g. `'features.search_enabled'`)
- `getSiteTitle(): string` - Site title from config
### Language
- `getCurrentLanguage(): string` - Current language code (e.g. `'nl'`)
- `getAvailableLanguages(): array` - Available languages (e.g. `['nl', 'en']`)
- `t(string $key): string` - Translate a language key
### Search
- `getSearchResults(): array` - Search results (empty if not searching)
- `isSearching(): bool` - Whether a search is currently active
## Example: Show recent pages
```php
<?php
/** @var ContentAPI $api */
$pages = $api->getAllPages();
$currentLang = $api->getCurrentLanguage();
?>
<ul>
<?php foreach (array_slice($pages, 0, 5, true) as $path => $title): ?>
<li>
<a href="/<?= $currentLang ?>/<?= htmlspecialchars($path) ?>">
<?= htmlspecialchars($title) ?>
</a>
</li>
<?php endforeach; ?>
</ul>
```
## Example: Using config values
```php
<?php
/** @var ContentAPI $api */
if ($api->getConfig('features.search_enabled', false)): ?>
<form method="GET" action="">
<input type="search" name="search" placeholder="<?= $api->t('search_placeholder') ?>">
<button type="submit"><?= $api->t('search_button') ?></button>
</form>
<?php endif; ?>
```
## CMSAPI (for plugins)
Plugins use the `CMSAPI` class via `$this->api`. It offers similar methods:
```php
$this->api->getCurrentPageTitle();
$this->api->getCurrentPageContent();
$this->api->getMenu();
$this->api->getConfig('site_title');
$this->api->getCurrentLanguage();
$this->api->isHomepage();
$this->api->hasContent();
$this->api->getSearchResults();
$this->api->isSearching();
$this->api->getAvailableLanguages();
$this->api->createUrl('about-us');
$this->api->translate('home');
```
Additionally, CMSAPI provides:
- `getCurrentPage(): array` - Full page data
- `getCurrentPageUrl(): string` - URL of current page
- `getCurrentPageFileInfo(): ?array` - File info (created, modified)
- `getBreadcrumb(): string` - Breadcrumb HTML
- `executePhpFile(string $filePath): string` - Execute PHP file and capture output
- `getFileContent(string $filePath): string` - Get content from PHP/HTML/Markdown file
- `contentFileExists(string $filename): bool` - Check if file exists in content directory
@@ -0,0 +1,31 @@
# Content structure
Content is stored in the `content/` folder without a database.
## Supported file formats
- `.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
```
## Frontmatter
Markdown files can contain frontmatter metadata:
```markdown
---
layout: full_content
plugins: HTMLBlock
---
# Page title
Content...
```
@@ -0,0 +1,16 @@
# Managing media
## Uploading
1. Go to Content folder
2. Click **Upload**
3. Select files (JPG, PNG, GIF, WebP, SVG, PDF, etc.)
4. Upload
## Using in content
```markdown
![Alt text](/content/image.jpg)
<video src="/content/video.mp4" controls></video>
```
@@ -0,0 +1,16 @@
# Managing pages
## Via Admin Console
1. Login at `/admin`
2. Go to **Content**
3. Choose a folder or create a new page
4. Edit content in the editor
5. Save with Ctrl+S
## Editor features
- **CodeMirror** editor with syntax highlighting
- **Toolbar** for quick Markdown insertion
- **Live preview** via button
- **Auto-save** backups in `.bak/` folder
+3
View File
@@ -0,0 +1,3 @@
# Manual
Select a topic from the navigation on the left.
+14
View File
@@ -0,0 +1,14 @@
# Theme Developer
The theme developer guide contains the following topics:
- **Theme structure** - Folder structure of a theme
- **theme.json** - Theme configuration
- **Twig templates** - Twig syntax, variables and blocks
- **SCSS styling** - Compiling and writing SCSS
- **Layouts** - Defining and using layouts
- **New theme** - Creating a theme via admin or manually
See also the **Content API** guide under Content Manager for all available Twig variables and CMSAPI methods.
Select a topic from the navigation on the left.
+27
View File
@@ -0,0 +1,27 @@
# Layouts
## Choosing a layout in content
```markdown
---
layout: left_sidebar
---
# Page title
Content...
```
## Layouts in theme.json
```json
{
"default_layout": "full_content",
"layouts": {
"full_content": "full_content.twig",
"left_sidebar": "left_sidebar.twig",
"right_sidebar": "right_sidebar.twig",
"custom1": "custom1.twig"
}
}
```
+25
View File
@@ -0,0 +1,25 @@
# Creating a new theme
## Via Admin
1. Go to **Theme****New theme**
2. Enter a name (e.g. `my-theme`)
3. Theme is created with basic structure
4. Edit `theme.json` and templates
## Manually
```bash
mkdir themes/my-theme
mkdir themes/my-theme/partials
mkdir themes/my-theme/assets/{scss,css,js,fonts,img}
```
Create basic files:
- `theme.json`
- `base.twig`
- `full_content.twig`
- `partials/header.twig`
- `partials/footer.twig`
- `scss/theme.scss`
+24
View File
@@ -0,0 +1,24 @@
# SCSS styling
## Compiling theme.scss
1. Go to **Admin****Theme**
2. Click **Compile SCSS** for your theme
3. CSS is generated in `assets/css/theme.css`
## SCSS example
```scss
$primary-color: #0a369d;
$font-stack: Helvetica, Arial, sans-serif;
body {
font-family: $font-stack;
color: #333;
}
.header {
background: $primary-color;
color: #fff;
}
```
@@ -0,0 +1,21 @@
# Theme structure
```
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
├── partials/
│ ├── header.twig
│ ├── navigation.twig
│ └── footer.twig
└── assets/
├── scss/theme.scss # SCSS source
├── css/ # CSS files
├── js/theme.js # JavaScript
├── fonts/ # Fonts
└── img/ # Images
```
+21
View File
@@ -0,0 +1,21 @@
# theme.json
```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"
}
}
```
## 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
+206
View File
@@ -0,0 +1,206 @@
# Twig templates
## Basic syntax
```twig
{# Comment #}
{{ variable }}
{{ variable|default('default') }}
{% if condition %}...{% endif %}
{% for item in items %}...{% endfor %}
{% extends 'base.twig' %}
{% block content %}{% endblock %}
{% include 'partials/header.twig' %}
```
## base.twig example
```twig
<!DOCTYPE html>
<html lang="{{ current_lang }}">
<head>
<meta charset="UTF-8">
<title>{{ page_title }} - {{ site_title }}</title>
<meta name="description" content="{{ seo_description }}">
<link rel="stylesheet" href="{{ theme_css_url }}">
</head>
<body>
{% include 'partials/header.twig' %}
{% block content %}{% endblock %}
{% include 'partials/footer.twig' %}
</body>
</html>
```
## Variables available in templates
### Page data
| Variable | Type | Description |
|----------|------|-------------|
| `page_title` | string | Current page title (HTML-escaped) |
| `content` | string | Rendered page content (HTML) |
| `page_metadata` | array | Frontmatter metadata of the page |
| `layout` | string | Layout name (e.g. `full_content`) |
| `sidebar_content` | string | Sidebar content from plugins (HTML) |
| `breadcrumb` | string | Breadcrumb HTML (generated by CMS) |
### Site data
| Variable | Type | Description |
|----------|------|-------------|
| `site_title` | string | Site title from config.json |
| `default_page` | string | Default page path |
| `homepage` | string | Homepage path |
| `homepage_title` | string | Homepage title |
| `is_homepage` | bool | Whether current page is the homepage |
| `is_guide_page` | bool | Whether current page is a guide page |
| `has_content` | bool | Whether content directory is not empty |
| `cms_version` | string | CMS version number |
### Menu & Navigation
| Variable | Type | Description |
|----------|------|-------------|
| `menu` | string | Rendered menu HTML |
| `current_page` | string | Current page path |
| `breadcrumb` | string | Breadcrumb HTML |
### Language
| Variable | Type | Description |
|----------|------|-------------|
| `current_lang` | string | Current language code (e.g. `nl`) |
| `current_lang_upper` | string | Current language in uppercase |
| `available_langs` | array | Available languages with `code`, `name`, `url`, `is_current` |
### SEO
| Variable | Type | Description |
|----------|------|-------------|
| `seo_description` | string | SEO description |
| `seo_keywords` | string | SEO keywords |
| `block_ai_bots` | bool | Block AI bots |
| `block_search_engines` | bool | Block search engines |
### Author
| Variable | Type | Description |
|----------|------|-------------|
| `author_name` | string | Author name |
| `author_website` | string | Author website URL |
| `author_git` | string | Author Git URL |
### Theme
| Variable | Type | Description |
|----------|------|-------------|
| `theme_title` | string | Theme title |
| `theme_css_url` | string | Compiled CSS URL |
| `theme_js_url` | string | JavaScript URL |
| `theme_config` | array | Theme configuration from theme.json |
| `theme_base_url` | string | Theme base URL (e.g. `/themes/default`) |
| `theme_css_files` | array | List of CSS files |
| `theme_js_files` | array | List of JS files |
| `theme_favicon` | string | Favicon URL |
| `plugin_css_urls` | array | CSS URLs from plugins (loaded after theme CSS) |
### Theme colors
| Variable | Type | Description |
|----------|------|-------------|
| `header_color` | string | Header background color |
| `header_font_color` | string | Header text color |
| `header_height` | string | Header height in px |
| `navigation_color` | string | Navigation background color |
| `navigation_font_color` | string | Navigation text color |
| `nav_height` | string | Navigation height in px |
| `sidebar_background` | string | Sidebar background color |
| `sidebar_border` | string | Sidebar border color |
### File info
| Variable | Type | Description |
|----------|------|-------------|
| `created` | string | File creation date |
| `modified` | string | File modification date |
| `show_created` | bool | Whether to show creation date |
| `file_info_block` | bool | Whether to show file info block |
### Translations
| Variable | Type | Description |
|----------|------|-------------|
| `t_home` | string | "Home" translation |
| `t_search` | string | "Search" translation |
| `t_search_placeholder` | string | Search placeholder translation |
| `t_search_button` | string | Search button translation |
| `t_welcome` | string | "Welcome" translation |
| `t_created` | string | "Created" translation |
| `t_modified` | string | "Modified" translation |
| `t_author` | string | "Author" translation |
| `t_manual` | string | "Manual" translation |
| `t_guide` | string | "Guide" translation |
| `t_no_content` | string | "No content" translation |
| `t_no_results` | string | "No results" translation |
| `t_results_found` | string | "Results found" translation |
| `t_powered_by` | string | "Powered by" translation |
| `t_page_not_found` | string | "Page not found" translation |
| `t_page_not_found_text` | string | "Page not found" text translation |
| `t_mappen` | string | "Folders" translation |
| `t_paginas` | string | "Pages" translation |
## Layouts and blocks
A layout template extends `base.twig` and fills the `content` block:
```twig
{% extends 'base.twig' %}
{% block content %}
<div class="container">
{{ content|raw }}
</div>
{% endblock %}
```
## Conditional sidebar
```twig
{% if sidebar_content %}
<div class="row">
<aside class="col-md-4">
{{ sidebar_content|raw }}
</aside>
<main class="col-md-8">
{{ content|raw }}
</main>
</div>
{% else %}
<div class="container">
{{ content|raw }}
</div>
{% endif %}
```
## Language switcher
```twig
{% for lang in available_langs %}
<a href="{{ lang.url }}" class="{{ lang.is_current ? 'active' : '' }}">
{{ lang.name }}
</a>
{% endfor %}
```
## Plugin CSS loading
Plugin CSS is automatically loaded after theme CSS, so themes can override plugin styling:
```twig
{% for cssUrl in plugin_css_urls|default([]) %}
<link href="{{ cssUrl }}" rel="stylesheet">
{% endfor %}
```
-755
View File
@@ -1,755 +0,0 @@
# CodePress CMS Handleiding
## Inhoudsopgave
- [Overzicht](#overzicht)
- [Installatie](#installatie)
- [Projectstructuur](#projectstructuur)
- [Content](#content)
- [Content Structuur](#content-structuur)
- [Content API (voor PHP content)](#content-api-voor-php-content-bestanden)
- [Instellingen](#instellingen)
- [Configuratie](#configuratie)
- [Thema's](#themas)
- [Beveiliging](#beveiliging)
- [Gegevens](#gegevens)
- [Statistieken & Analytics](#statistieken--analytics)
- [Logging](#logging)
- [Systeem](#systeem)
- [Plugin Systeem](#plugin-systeem)
- [Gebruikersbeheer](#gebruikersbeheer)
- [Update](#update)
- [Handleiding](#handleiding-in-admin)
- [Overig](#overig)
- [Templates](#templates)
- [URL Structuur](#url-structuur)
- [SEO Optimalisatie](#seo-optimalisatie)
- [Veelgestelde Vragen](#veelgestelde-vragen)
- [Troubleshooting](#troubleshooting)
- [Versie](#versie)
- [Ondersteuning](#ondersteuning)
- [Licentie](#licentie)
## Overzicht
CodePress CMS is een lichtgewicht, file-based content management systeem gebouwd met PHP (>=8.0). Werkt zonder database.
## Installatie
1. Upload bestanden naar webserver
2. Stel permissies in voor webserver
3. Voer `composer install` uit voor CommonMark dependency
4. Configureer `config.json` indien nodig
5. Toegang tot website via browser
6. **PHP ontwikkelserver**: `php -S localhost:8080 -t public` (gebruikt `cms/router.php`)
## Projectstructuur
```
codepress/
├── cms/ # Core CMS engine
│ ├── core/
│ │ ├── class/
│ │ │ ├── CodePressCMS.php # Hoofd CMS class (content, navigatie, search)
│ │ │ ├── ThemeManager.php # Thema-resolver + Twig render + SCSS compile
│ │ │ ├── Logger.php # Gestructureerd logging systeem
│ │ │ ├── Analytics.php # Bezoekersstatistieken
│ │ │ ├── BotGuard.php # Bot/AI/scraper detectie
│ │ │ ├── GeoIP.php # Landbepaling op basis van IP
│ │ │ ├── Cache.php # File-based caching
│ │ │ └── RateLimiter.php # Snelheidsbeperking per IP
│ │ ├── plugin/
│ │ │ ├── PluginManager.php # Plugin lader en beheer
│ │ │ └── CMSAPI.php # API voor plugin developers
│ │ ├── config.php # Configuratie lader (merge met config.json)
│ │ └── index.php # Bootstrap (autoloader, requires)
│ ├── lang/ # Taalbestanden
│ │ ├── nl.php # Nederlandse vertalingen
│ │ └── en.php # Engelse vertalingen
│ └── router.php # PHP dev server router (serveert ook /themes/)
├── themes/ # Dynamische thema's (volledig zelfstandig)
│ ├── default/ # Standaard thema
│ │ ├── theme.json # { title, config.default_template, template→.twig mapping }
│ │ ├── base.twig # Hoofd layout (head, header, nav, footer)
│ │ ├── full_content.twig # Layout: volledige breedte
│ │ ├── left_sidebar.twig # Layout: sidebar links
│ │ ├── right_sidebar.twig # Layout: sidebar rechts
│ │ ├── custom1.twig # Layout: custom
│ │ ├── partials/ # header.twig, navigation.twig, footer.twig
│ │ ├── css/theme.scss # Kleuren, hoogtes, achtergrond (runtime gecompileerd)
│ │ ├── js/theme.js # Thema JavaScript
│ │ └── theme.png # Voorbeeldafbeelding
│ ├── demo/ # Demo thema (zelfde structuur, andere look)
│ └── test/ # Test thema
├── admin/ # Admin paneel
│ ├── config/
│ │ ├── app.php # Admin app configuratie (paden, timezone)
│ │ └── admin.json # Gebruikers & security (bcrypt hashes)
│ ├── src/
│ │ └── AdminAuth.php # Authenticatie (sessies, bcrypt, CSRF, lockout)
│ ├── templates/
│ │ ├── login.php # Login pagina
│ │ ├── layout.php # Admin layout met sidebar navigatie
│ │ └── pages/
│ │ ├── dashboard.php # Dashboard met statistieken
│ │ ├── content.php # Content overzicht met bestanden uploaden
│ │ ├── content-edit.php # CodeMirror editor met toolbar en rename
│ │ ├── content-new.php # Nieuwe content aanmaken
│ │ ├── content-dir-form.php # Map aanmaken/bewerken
│ │ ├── content-move-form.php # Content verplaatsen
│ │ ├── config.php # Configuratie editor
│ │ ├── security.php # Beveiligingsinstellingen
│ │ ├── statistics.php # Statistieken dashboard
│ │ ├── plugins.php # Plugin overzicht
│ │ ├── plugins-edit.php # Plugin PHP broncode editor
│ │ ├── plugins-new.php # Nieuwe plugin aanmaken
│ │ ├── plugin-config.php # Plugin configuratie editor
│ │ ├── theme.php # Thema beheer
│ │ ├── users.php # Gebruikersbeheer
│ │ ├── logs.php # Log viewer
│ │ ├── update.php # Systeem update
│ │ └── guide.php # Handleiding
│ └── storage/logs/ # Admin logs
├── cli/ # CLI scripts & tests
├── content/ # Content bestanden
│ ├── -assets/ # Geuploade mediabestanden
│ ├── index.md # Standaard homepage
│ └── ... # Overige content
├── plugins/ # CMS plugins
│ ├── HTMLBlock/ # Custom HTML blokken in sidebar
│ └── MQTTTracker/ # Real-time analytics en tracking
├── public/ # Web root
│ ├── index.php # Website entry point (media serving + CMS)
│ ├── admin.php # Admin entry point + routing
│ ├── .htaccess # Apache rewrite/security rules
│ ├── assets/ # CSS, JS, favicons
│ │ ├── codemirror/ # CodeMirror editor (minified JS/CSS)
│ │ └── css/js/ # Bootstrap, icons, app CSS/JS
│ ├── themes/ # Runtime gecompileerde thema CSS (public/themes)
│ └── manifest.json / sw.js # PWA ondersteuning
├── themes/ # Dynamische thema's (volledig zelfstandig)
│ ├── default/ # Standaard thema
│ │ ├── theme.json # Titel, default template, template mapping
│ │ ├── base.twig # Hoofd layout
│ │ ├── *.twig # Layout-sjablonen (full_content, left_sidebar, ...)
│ │ ├── partials/ # header, navigation, footer
│ │ ├── css/theme.scss # Kleuren, hoogtes, achtergrond
│ │ ├── js/theme.js # Thema JavaScript
│ │ └── theme.png # Voorbeeldafbeelding
│ ├── demo/ # Demo thema
│ └── test/ # Test thema
├── config.json # Site configuratie
├── version.php # Versie informatie
└── vendor/ # Composer dependencies
```
---
## Content
### Content Structuur
#### Bestandsstructuur
```
content/
├── map1/
│ ├── submap1/
│ │ ├── nl.pagina1.md
│ │ └── en.pagina1.md
│ └── pagina3.html
├── map2/
│ └── pagina4.md
├── index.md
└── -assets/
├── afbeelding.jpg
└── document.pdf
```
#### Bestandsnamen
- Gebruik lowercase bestandsnamen
- Geen spaties - gebruik `-` of `_`
- Logische extensies - `.md`, `.php`, `.html`
- Unieke namen - geen duplicaten
- Language prefixes - `nl.bestand.md` en `en.bestand.md`
#### Media Bestanden
Media bestanden (afbeeldingen, PDFs, video, audio) kunnen in elke `content/` subdirectory worden geplaatst en worden geserveerd via:
- **`/-media/pad/bestand.jpg`** - Media uit elke content subdirectory
- **`/-assets/bestand.jpg`** - Backward compatibility (oude URLs)
- Uploads via het admin paneel gaan naar `content/-assets/`
### Content API (voor PHP content bestanden)
PHP content bestanden (`.php` in de `content/` map) hebben toegang tot een `$api` variabele met de volgende methodes:
#### Pagina's opvragen
```php
// Alle pagina's met titels ophalen
$pages = $api->getAllPages();
// Resultaat: ['index' => 'Home', 'over-ons' => 'Over ons', ...]
// specifieke pagina inhoud ophalen
$page = $api->getPage('over-ons');
// $page['title'], $page['content'], $page['path'], $page['layout'], $page['metadata']
// Controleren of een pagina bestaat
if ($api->pageExists('contact')) {
// ...
}
```
#### Navigatie
```php
// Menu structuur ophalen
$menu = $api->getMenu();
// Bevat geneste array met 'title', 'path', 'url', 'children'
```
#### Configuratie
```php
// Configuratie waarde opvragen (punt-notatie)
$title = $api->getConfig('site_title');
$lang = $api->getConfig('language.default');
$seoDesc = $api->getConfig('seo.description', 'Standaard beschrijving');
```
#### Huidige pagina
```php
// Huidige pagina titel
$pageTitle = $api->getCurrentPageTitle();
// Huidige pagina pad
$pagePath = $api->getCurrentPagePath();
// Check of dit de homepage is
if ($api->isHomepage()) {
echo 'Welkom!';
}
```
#### URLs en taal
```php
// URL bouwen voor een pagina
$url = $api->buildUrl('over-ons', 'nl');
// Huidige taal
$lang = $api->getCurrentLanguage();
// Beschikbare talen
$languages = $api->getAvailableLanguages();
// Site titel
$title = $api->getSiteTitle();
```
#### Vertalingen en zoeken
```php
// Vertaling ophalen
$label = $api->t('home');
// Zoekresultaten (als er gezocht wordt)
if ($api->isSearching()) {
$results = $api->getSearchResults();
}
```
#### Voorbeeld PHP content bestand
```php
---
title: Pagina Overzicht
layout: content
---
<h1>Alle Pagina's</h1>
<ul>
<?php foreach ($api->getAllPages() as $path => $title): ?>
<li><a href="<?= $api->buildUrl($path) ?>"><?= htmlspecialchars($title) ?></a></li>
<?php endforeach; ?>
</ul>
```
---
## Instellingen
### Configuratie
De site configuratie wordt beheerd via het **admin paneel** op `/admin/config`. Het formulier bevat de volgende secties:
- **Algemene instellingen** - Site titel en startpagina (dropdown met beschikbare pagina's)
- **Taal** - Standaard taal en beschikbare talen
- **SEO** - Meta beschrijving en keywords
- **Auteur** - Naam en website
- **Features** - Auto-link pagina's, zoekfunctie, breadcrumbs, versie tonen
- **IP Uitsluitingen** - IP-adressen uitsluiten van statistieken en beveiligingscontroles
De configuratie wordt opgeslagen in `config.json`. Je kunt dit bestand ook handmatig bewerken voor geavanceerde opties.
#### IP Uitsluitingen
Onder **Configuratie** in het admin paneel vind je het veld "IP-adressen uitsluiten". IP's die hier worden ingevuld worden:
- Niet opgenomen in de bezoekersstatistieken
- Overgeslagen bij alle beveiligingscontroles (bot-detectie, rate limiting, IP blocklist)
Dit is handig voor je eigen IP-adres of dat van interne monitoring tools.
#### Voorbeeld `config.json`
```json
{
"site_title": "CodePress",
"content_dir": "content",
"default_page": "index",
"active_theme": "default",
"language": {
"default": "nl",
"available": ["nl", "en"]
},
"seo": {
"description": "CodePress CMS - Lightweight file-based content management system",
"keywords": "cms, php, content management, file-based"
},
"author": {
"name": "E. Noorlander",
"website": "https:\/\/noorlander.info"
},
"features": {
"auto_link_pages": true,
"search_enabled": true,
"breadcrumbs_enabled": true
},
"analytics": {
"enabled": true,
"excluded_ips": ["127.0.0.1", "::1"]
},
"security": {
"block_ai_bots": true,
"block_scrapers": true,
"block_empty_user_agent": true,
"rate_limit_enabled": true
}
}
```
### Thema's
Thema's worden beheerd via het admin paneel op `/admin/theme`. Dit is een selectiepagina: kies het actieve thema en klik "Thema activeren". Elk thema is een volledig zelfstandige map in `themes/` met eigen Twig-sjablonen, SCSS en JavaScript.
#### Thema-structuur (`themes/<naam>/`)
```
themes/<naam>/
├── theme.json # Titel, default template, template mapping
├── base.twig # Hoofd layout (head, header, nav, footer)
├── full_content.twig # Layout: volledige breedte
├── left_sidebar.twig # Layout: sidebar links
├── right_sidebar.twig # Layout: sidebar rechts
├── custom1.twig # Layout: custom
├── partials/ # header.twig, navigation.twig, footer.twig
├── css/theme.scss # Kleuren, hoogtes, achtergrond (runtime gecompileerd)
├── js/theme.js # Thema JavaScript
└── theme.png # Voorbeeldafbeelding (tonen in admin)
```
#### Thema Configuratie (`themes/<naam>/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"
}
}
```
- **`config.default_template`**: de standaard sjabloon die gebruikt wordt wanneer een pagina een onbekende layout vraagt.
- **`template`**: de layout-sleutel → `.twig`-bestand koppeling. Zo kan een thema meerdere template-pagina's hebben.
Kleuren, hoogtes en achtergrond worden **niet** in `theme.json` gezet, maar in `css/theme.scss`:
```scss
$header-bg: #0a369d;
$header-font: #ffffff;
$header-height: 56px;
$nav-bg: #2754b4;
$nav-font: #ffffff;
$nav-height: 42px;
$sidebar-bg: #f8f9fa;
$sidebar-border: #dee2e6;
$header-bg-image: none; // optionele header-achtergrond
$header-bg-opacity: 1;
```
De SCSS wordt runtime gecompileerd naar `public/themes/<naam>/theme.css`.
#### Een nieuw thema maken
Thema's zijn handmatig aan te maken: kopieer de `themes/default/` map naar `themes/<naam>/`, pas de SCSS-kleuren en sjablonen aan, en voeg een `theme.png` preview toe. Daarna is het thema beschikbaar op `/admin/theme` om te activeren.
### Beveiliging
Beveiligingsinstellingen worden beheerd via `/admin/security`. Hier vind je:
#### Bot, AI & Scraper Blokkering
Bij binnenkomende requests detecteert het systeem bekende bots en AI-crawlers op basis van de User-Agent header. Gedetecteerde bots krijgen een **403 Forbidden**.
| Categorie | Voorbeelden |
|---|---|
| AI Crawlers | GPTBot, ChatGPT-User, Claude-Web, ClaudeBot, Google-Extended, CCBot, PerplexityBot |
| Search Engines | Googlebot, Bingbot, BingPreview, DuckDuckBot, YandexBot, Baiduspider |
| Scrapers | HTTrack, Scrapy, PhantomJS |
#### Snelheidsbeperking (Rate Limiting)
Voorkomt dat IP's de site overbelasten. Bij overschrijding wordt HTTP 429 geretourneerd.
#### IP Lijsten
- **IP Whitelist** - IP's op de whitelist worden nooit geblokkeerd
- **IP Blocklist** - IP's op de blocklist krijgen altijd een 403 Forbidden
#### Dynamische robots.txt
Het systeem genereert automatisch een `robots.txt` op basis van je beveiligingsinstellingen, beschikbaar op `/robots.txt`.
---
## Gegevens
### Statistieken & Analytics
Het statistieken dashboard is beschikbaar op `/admin/statistics` en biedt:
- **KPI-kaarten** - Paginaweergaven, unieke bezoekers, mens/bot verhouding, geblokkeerde verzoeken
- **Wereldkaart** - Visuele weergave van bezoekers per land met kleurintensiteit
- **Landenlijst** - Top 25 landen met percentage
- **Meest gelezen pagina's** - Top 25 pagina's
- **Dagelijkse grafiek** - Staafdiagram van bezoekers per dag
- **Verwijzende sites** - Top 15 referrers
#### Periodes en export
Filter op 7, 30, 90 dagen of alles. Exporteer data als CSV of JSON.
#### GeoIP
Landbepaling kan via drie bronnen:
- **Lokaal (DB-IP Lite)** - Offline, privacy-vriendelijk, automatisch bijgewerkt
- **MaxMind database (.mmdb)** - Eigen MMDB bestand
- **Externe API** - Eigen API URL en sleutel
### Logging
De admin console houdt logs bij, te bekijken via `/admin/logs`:
- **Activiteiten log** (`admin/storage/logs/admin.log`) — admin acties zoals pagina's aanmaken, bewerken, verwijderen, plugin in/uitschakelen, configuratie wijzigen.
- **Requests log** (`admin/storage/logs/requests.log`) — elke pageview op de website, met IP, pagina, domein, taal, user-agent en referrer.
- **Dynamisch log** — gestructureerde logregels via `LogManager`, met gebeurtenistype, niveau, IP en bericht.
#### Dynamische logging configureren
Via `/admin/config`**Logging** kun je instellen hoe en wat er geregistreerd wordt:
- **Opslag**: `SQLite` (standaard) of `Syslog`.
- **Syslog server**: als er een host is opgegeven, worden logregels via UDP naar die server gestuurd. Laat leeg om SQLite te gebruiken.
- **Facility**: de categorie van de logbron in syslog. `local0``local7` zijn bedoeld voor eigen applicaties; `daemon`, `user` en `auth` zijn standaard systeemcategorieën.
- **Syslog ident**: de naam die in het logbericht verschijnt (bijv. `codepress`).
- **Gebeurtenissen**: kies welke types geregistreerd worden — `admin`, `requests`, `errors`, `security`, `content`, `system`.
Als er geen syslog-server is opgegeven, wordt altijd SQLite gebruikt (met een bestands-fallback als SQLite niet beschikbaar is).
Het dashboard toont de laatste 20 entries van elk log. Klik "Bekijk alle →" voor de volledige lijst, waar je ook kunt downloaden of wissen.
---
## Systeem
### Plugin Systeem
#### Plugin Structuur
```
plugins/
├── HTMLBlock/
│ ├── HTMLBlock.php # Plugin class (verplicht)
│ ├── config.json # Configuratie (optioneel)
│ └── README.md # Documentatie (optioneel)
├── MQTTTracker/
│ ├── MQTTTracker.php
│ ├── config.json
│ └── README.md
```
#### Plugin Ontwikkeling
- **API toegang** via `CMSAPI` class - geeft toegang tot CMS configuratie, templates, menu
- **Sidebar content** met `getSidebarContent()` - retourneert HTML voor sidebar
- **Metadata toegang** uit YAML frontmatter via `CMSAPI`
- **Configuratie** via `config.json` - bewerkbaar via admin paneel
- **viewable** veld in config.json bepaalt of plugin zichtbaar is in sidebar
- **Per-page zichtbaarheid** - via de editor plugin selector per pagina
#### Plugin Boilerplate
```php
<?php
class MijnPlugin
{
private ?CMSAPI $api = null;
private array $config;
public function __construct()
{
$this->config = [
'viewable' => true,
];
}
public function setAPI(CMSAPI $api): void
{
$this->api = $api;
}
public function getSidebarContent(): string
{
return '';
}
public function getConfig(): array
{
return $this->config;
}
public function setConfig(array $config): void
{
$this->config = array_merge($this->config, $config);
}
}
```
#### Bekende Issue: MQTTTracker Credentials
De MQTTTracker plugin slaat `broker_host`, `broker_port`, `client_id`, `username` en `password` op in plain text in `plugins/MQTTTracker/config.json`. Dit is een bekend openstaand security punt - bij een productieomgeving wordt aangeraden deze gegevens te externaliseren naar omgevingsvariabelen of een aparte credentials manager.
### Gebruikersbeheer
Gebruikers worden beheerd via `/admin/users`. Functionaliteiten:
- Gebruiker toevoegen met gebruikersnaam, wachtwoord en rol
- Gebruiker verwijderen
- Wachtwoord wijzigen voor andere gebruikers (admin)
- Eigen wachtwoord wijzigen (vereist huidig wachtwoord)
Wachtwoorden worden opgeslagen als bcrypt-hashes in `admin/config/admin.json`.
### Update
Via `/admin/update` kan het systeem in één klik worden bijgewerkt via Git pull. De pagina toont de huidige versie en git branch, en voert na bevestiging `git pull origin <branch>` uit.
---
## Handleiding (in Admin)
Deze handleiding is ook ingebouwd in het admin paneel via `/admin/guide`, met ondersteuning voor Nederlands en Engels.
---
## Overig
### Templates
Sjablonen zijn Twig-bestanden die per thema in `themes/<naam>/` staan. `ThemeManager` rendert ze en compileert `css/theme.scss` runtime naar `public/themes/<naam>/theme.css`.
#### Template Variabelen
**Site Info** - `site_title`, `author_name`, `author_website`, `author_git`
**Page Info** - `page_title`, `content`, `file_info`, `is_homepage`
**Navigation** - `menu`, `breadcrumb`, `homepage`
**Theme** - `theme_title`, `theme_css_url`, `theme_js_url`, `theme_config` (config uit theme.json)
**Language** - `current_lang`, `current_lang_upper`, `t_*` (vertaalde strings)
#### Layout Opties
Gebruik YAML frontmatter om de sjabloon te selecteren. De layout-sleutel verwijst naar een template in het actieve thema:
```yaml
---
title: Mijn Pagina
layout: left_sidebar
plugins: HTMLBlock
---
```
#### Beschikbare Layouts
De beschikbare layouts worden bepaald door de `template`-sectie van het actieve thema (`themes/<naam>/theme.json`). Het standaard thema bevat:
- `full_content` - Alleen content (volle breedte)
- `left_sidebar` - Sidebar links, content rechts
- `right_sidebar` - Content links, sidebar rechts
- `custom1` - Custom layout
Vraag een pagina een onbekende layout aan, dan wordt de `default_template` uit `config` van het thema gebruikt.
#### Meta Data
```yaml
---
title: Pagina Titel
layout: left_sidebar
description: Pagina beschrijving
author: Auteur Naam
date: 2025-11-26
plugins: HTMLBlock, MQTTTracker
---
```
### URL Structuur
#### Frontend Pagina URLs
- **Home**: `/` of `/nl/`
- **Pagina**: `/nl/map/pagina`
- **Zoeken**: `?search=zoekterm` (via zoekformulier)
#### Media URLs
- **Media**: `/-media/pad/naar/bestand.jpg` (uit elke content subdirectory)
- **Assets**: `/-assets/bestand.jpg` (uit content/-assets/, backward compatible)
#### Admin URLs
- **Admin**: `/admin`
- **Dashboard**: `/admin/dashboard`
- **Content**: `/admin/content`
- **Configuratie**: `/admin/config`
- **Beveiliging**: `/admin/security`
- **Statistieken**: `/admin/statistics`
- **Thema**: `/admin/theme`
- **Plugins**: `/admin/plugins`
- **Gebruikers**: `/admin/users`
- **Logs**: `/admin/logs`
- **Update**: `/admin/update`
- **Handleiding**: `/admin/guide`
### SEO Optimalisatie
#### Meta Tags
De CMS voegt automatisch meta tags toe:
```html
<meta name="generator" content="CodePress CMS">
<meta name="author" content="E. Noorlander">
<meta name="description" content="...">
<meta name="keywords" content="...">
```
#### Security Headers
```http
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
Referrer-Policy: strict-origin-when-cross-origin
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'; ...
```
### Veelgestelde Vragen
#### Hoe stel ik de homepage in?
1. Ga naar **Configuratie** in het admin paneel (`/admin/config`)
2. Selecteer de gewenste pagina in het **Standaard/startpagina** dropdown
3. Klik op **Configuratie opslaan**
#### Hoe werkt de navigatie?
- **Mappen** worden dropdown menus
- **Bestanden** worden directe links
- **Sub-mappen** worden geneste dropdowns
- Alleen bestanden zonder taalprefix tonen in het menu
#### Hoe voeg ik nieuwe content toe?
1. Via het admin paneel: `/admin/content-new`
2. Of upload bestanden naar de `content/` map
3. Organiseer in logische mappen
4. Gebruik juiste bestandsnamen en extensies
#### Hoe verplaats ik een bestand of map?
1. Ga naar `/admin/content`
2. Klik op "Verplaatsen" naast het item
3. Selecteer de doelmap
4. Bevestig de verplaatsing
#### Hoe sluit ik mijn eigen IP uit van statistieken?
1. Ga naar **Configuratie** in het admin paneel (`/admin/config`)
2. Scroll naar het veld "IP-adressen uitsluiten"
3. Voer je IP-adres in (één per regel)
4. Klik op **Configuratie opslaan**
### Troubleshooting
#### Pagina niet gevonden (404)
1. Controleer bestandsnaam en pad
2. Controleer bestandsextensie (.md, .php, .html)
3. Controleer permissies van bestanden
4. Controleer of het bestand de juiste taalprefix heeft (`nl.` of `en.`)
#### Navigatie niet bijgewerkt
1. Herlaad de pagina
2. Controleer content map structuur
3. Controleer bestandsnamen (geen spaties)
4. Bestanden met taalprefix worden alleen getoond in de juiste taalmodus
#### Admin paneel niet toegankelijk
1. Controleer of de sessie nog geldig is
2. Bij lockout: wacht 15 minuten of wis `admin/config/admin.json` lockout data
3. Controleer CSRF token (herlaad de pagina)
## Versie
Huidige versie: **1.9.1**
Release datum: 2026-07-29
## Ondersteuning
Voor technische ondersteuning:
- **Git**: https://git.noorlander.info/E.Noorlander/CodePress
- **Website**: https://noorlander.info
- **Issues**: Rapporteer problemen via Git issues
## Licentie
CodePress CMS is open-source software onder dual-license: AGPL v3 voor open-source gebruik, commerciële licentie voor proprietary gebruik.
+15
View File
@@ -0,0 +1,15 @@
# Admin Beheerder
De admin beheerder handleiding bevat de volgende onderwerpen:
- **Dashboard** - Overzicht van de website
- **Content beheer** - Bestanden en pagina's beheren
- **Configuratie** - Site instellingen
- **Thema beheer** - Thema's beheren en aanmaken
- **Beveiliging** - Bot bescherming en sessies
- **Plugins** - Plugins beheren en aanmaken
- **Gebruikers** - Gebruikers toevoegen en verwijderen
- **Statistieken** - Bezoekersstatistieken bekijken
- **Logs** - Logbestanden bekijken en filteren
Selecteer een onderwerp uit de navigatie aan de linkerkant.
+12
View File
@@ -0,0 +1,12 @@
# Beveiliging
## Bot bescherming
- **BotGuard** - Bot/AI detectie
- **Rate limiting** - Requests per IP beperken
- **Block/allowlist** - IPs blokkeren of toestaan
## Sessie instellingen
- **Sessie timeout** - Standaard 3600 seconden
- **Max login pogingen** - Standaard 5 pogingen
+9
View File
@@ -0,0 +1,9 @@
# Configuratie
## Algemene instellingen
- **Site titel** - Naam van de website
- **Standaard taal** - nl/en/de/fr
- **Auteur** - Naam en e-mail
- **Analytics** - Bezoekers tracking aan/uit
- **Logging** - Logbestanden aan/uit
@@ -0,0 +1,17 @@
# Content beheer
## Bestanden beheren
- **Uploaden** - Media bestanden uploaden
- **Nieuwe map** - Mappen structuur aanmaken
- **Nieuw bestand** - Pagina aanmaken
- **Bewerken** - Bestaande content wijzigen
- **Hernoemen** - Bestandsnamen aanpassen
- **Verplaatsen** - Content verplaatsen
- **Verwijderen** - Content verwijderen
## Editor
- CodeMirror met syntax highlighting
- Toolbar voor Markdown formatting
- Sneltoetsen: Ctrl+S (opslaan), Ctrl+N (nieuw)
+10
View File
@@ -0,0 +1,10 @@
# Dashboard
Het dashboard toont een overzicht van:
- Weergaven (30 dagen)
- Unieke bezoekers
- Aantal pagina's en mappen
- Actieve plugins
- Recente activiteit
- Snelle acties
+13
View File
@@ -0,0 +1,13 @@
# Gebruikers
## Gebruiker toevoegen
1. Ga naar **Gebruikers**
2. Vul gebruikersnaam in
3. Kies wachtwoord
4. Klik **Toevoegen**
## Gebruiker verwijderen
- Kan niet voor eigen account
- Bevestig met wachtwoord
+12
View File
@@ -0,0 +1,12 @@
# Logs
## Log types
- **Admin** - Admin acties
- **Requests** - Website bezoeken
## Filteren
- Zoeken op IP, bericht
- Filteren op level (info, warning, error)
- Downloaden als bestand
+15
View File
@@ -0,0 +1,15 @@
# Plugins
## Plugins beheren
- **Activeren/Deactiveren** - Plugins aan/uit
- **Bewerken** - Plugin code aanpassen
- **Configuratie** - Plugin instellingen
- **Verwijderen** - Plugin verwijderen
## Nieuwe plugin
1. Ga naar **Plugins****Nieuwe plugin**
2. Geef naam op (bijv. `MijnPlugin`)
3. Bewerk `plugin.php`
4. Activeer de plugin
+14
View File
@@ -0,0 +1,14 @@
# Statistieken
## Overzicht
- Totaal aantal views
- Unieke bezoekers
- Landen met vlaggen
- Top pagina's
- Referrers
## Filters
- Periode: 7/30/90 dagen of alles
- Export: CSV of JSON
+19
View File
@@ -0,0 +1,19 @@
# Thema beheer
## Thema's beheren
1. Ga naar **Thema** in admin menu
2. **Activeren** - Kies actief thema
3. **SCSS compileren** - Verwerk SCSS naar CSS
4. **Nieuw thema** - Eigen thema aanmaken
## Thema structuur
```
themes/default/
├── theme.json # Thema configuratie
├── base.twig # Hoofd layout
├── full_content.twig # Layouts
├── partials/ # Header, nav, footer
└── assets/ # CSS, JS, afbeeldingen
```
+14
View File
@@ -0,0 +1,14 @@
# CodePress Developer
De CodePress developer handleiding bevat de volgende onderwerpen:
- **Architectuur** - CMS architectuur en mappenstructuur
- **Core classes** - CodePressCMS, ThemeManager, PluginManager
- **Plugin development** - Plugins ontwikkelen
- **Routing** - Frontend en admin routing
- **Beveiliging** - XSS, CSRF, path traversal
- **Testing** - Penetratie, accessibility en functionele tests
- **Debugging** - Logging en cache
- **Performance** - OPcache en SCSS caching
Selecteer een onderwerp uit de navigatie aan de linkerkant.
@@ -0,0 +1,11 @@
# CMS Architectuur
```
codepress/
├── cms/core/ # Core engine
├── admin/ # Admin console
├── themes/ # Thema's
├── plugins/ # Plugins
├── content/ # Content
└── public/ # Web root
```
@@ -0,0 +1,34 @@
# Beveiliging
## XSS preventie
```php
// Altijd escapen
echo htmlspecialchars($userInput, ENT_QUOTES, 'UTF-8');
// In Twig (automatisch)
{{ userVariable }}
```
## CSRF tokens
```php
// Genereren
$csrf = $auth->getCsrfToken();
// Verifiëren
if (!$auth->verifyCsrf($_POST['csrf_token'])) {
die('Ongeldige CSRF token');
}
```
## Path traversal preventie
```php
// Gebruik realpath() en check prefix
$realPath = realpath($filePath);
$realContentDir = realpath($contentDir);
if (strpos($realPath, $realContentDir) !== 0) {
die('Ongeldig pad');
}
```
@@ -0,0 +1,32 @@
# Core Classes
## CodePressCMS.php
Hoofd CMS class in `cms/core/class/CodePressCMS.php`:
```php
$cms = new CodePressCMS();
$cms->init();
$cms->renderPage($pagePath);
```
## ThemeManager.php
Themabeheer in `cms/core/class/ThemeManager.php`:
```php
$themeManager = new ThemeManager($config);
$themeManager->getActiveTheme();
$themeManager->renderTwig($template, $data);
$themeManager->compileCss($force);
```
## PluginManager.php
Plugin systeem in `cms/core/class/PluginManager.php`:
```php
$pluginManager = new PluginManager();
$pluginManager->loadPlugins($enabledPlugins);
$pluginManager->executeHook($name, $params);
```
+23
View File
@@ -0,0 +1,23 @@
# Debugging
## Logging
```php
// Admin logging
adminLog($config, 'info', 'Bericht tekst');
// LogManager
LogManager::log(LogManager::EVENT_ADMIN, 'info', 'Bericht');
```
## Cache uitschakelen
In `config.json`:
```json
{
"cache": {
"enabled": false
}
}
```
@@ -0,0 +1,19 @@
# Performance
## OPcache inschakelen
In `php.ini`:
```ini
opcache.enable=1
opcache.memory_consumption=128
opcache.max_accelerated_files=10000
```
## SCSS caching
SCSS wordt gecompileerd met caching:
```php
$themeManager->compileCss(false); // Gebruik cache indien mogelijk
```
@@ -0,0 +1,43 @@
# Plugin Development
## Plugin structuur
```
plugins/MijnPlugin/
├── plugin.json # Plugin metadata
├── plugin.php # Plugin code
└── config.json # Optionele configuratie
```
## plugin.json
```json
{
"name": "Mijn Plugin",
"version": "1.0.0",
"author": "Jouw Naam",
"description": "Beschrijving"
}
```
## plugin.php voorbeeld
```php
<?php
/**
* Plugin: MijnPlugin
*/
echo '<div class="mijn-plugin">Hello World</div>';
```
## CMSAPI gebruiken
```php
<?php
require_once '../../cms/core/class/PluginManager.php';
$api = PluginManager::getAPI();
$config = $api->getConfig();
$content = $api->getContent();
```
+19
View File
@@ -0,0 +1,19 @@
# Routing
## Frontend routing
Via `cms/router.php` voor PHP dev server:
```php
// Schone URLs: /nl/pagina
// Query: ?page=pagina&lang=nl
```
## Admin routing
Via `public/admin.php`:
```php
// Routes: /admin/dashboard, /admin/content, etc.
// Query parameter: ?route=dashboard
```
+22
View File
@@ -0,0 +1,22 @@
# Testing
## Penetration tests
```bash
cd cli/test/pentest
./security-test.sh
```
## Accessibility tests
```bash
cd cli/test
./accessibility.sh
```
## Functionele tests
```bash
cd cli/test/functional
./content-tests.sh
```
+10
View File
@@ -0,0 +1,10 @@
# Content Beheerder
De content beheerder handleiding bevat de volgende onderwerpen:
- **Content structuur** - Hoe content wordt opgeslagen
- **Pagina's beheren** - Pagina's aanmaken en bewerken
- **Media beheren** - Media uploaden en gebruiken
- **Content API** - De Content API gebruiken in PHP pagina's
Selecteer een onderwerp uit de navigatie aan de linkerkant.
+119
View File
@@ -0,0 +1,119 @@
# Content API
De Content API is beschikbaar in PHP content bestanden (`.php`) en biedt een veilige, read-only interface tot CMS data.
## Gebruik in PHP content bestanden
```php
<?php
/** @var ContentAPI $api */
// Alle pagina's ophalen
$allPages = $api->getAllPages();
// Resultaat: ['index' => 'Home', 'over-ons' => 'Over ons', ...]
// Specifieke pagina ophalen
$page = $api->getPage('over-ons');
// Resultaat: ['title' => 'Over ons', 'content' => '...', 'path' => 'over-ons', 'layout' => 'full_content', 'metadata' => [...]]
// Menu structuur ophalen
$menu = $api->getMenu();
// Resultaat: [['title' => 'Home', 'path' => 'index', 'type' => 'file', 'active' => true], ...]
// Config waarde ophalen (dot notatie)
$siteTitle = $api->getConfig('site_title');
$searchEnabled = $api->getConfig('features.search_enabled', false);
```
## Beschikbare methods
### Pagina's
- `getAllPages(): array` - Alle pagina's als `['pad' => 'titel']` pairs
- `getPage(string $path): ?array` - Specifieke pagina met `title`, `content`, `path`, `layout`, `metadata`
- `pageExists(string $path): bool` - Controleer of een pagina bestaat
- `getCurrentPageTitle(): string` - Titel van huidige pagina
- `getCurrentPagePath(): string` - Pad van huidige pagina
- `isHomepage(): bool` - Of huidige pagina de homepage is
### Menu & Navigatie
- `getMenu(): array` - Hiërarchische menu structuur met `title`, `path`, `children`, `active`
- `buildUrl(string $page = 'index', ?string $lang = null, array $params = []): string` - Bouw een URL voor een pagina
### Configuratie
- `getConfig(string $key, mixed $default = null): mixed` - Config waarde via dot notatie (bijv. `'features.search_enabled'`)
- `getSiteTitle(): string` - Site titel uit config
### Taal
- `getCurrentLanguage(): string` - Huidige taal code (bijv. `'nl'`)
- `getAvailableLanguages(): array` - Beschikbare talen (bijv. `['nl', 'en']`)
- `t(string $key): string` - Vertaal een language key
### Zoeken
- `getSearchResults(): array` - Zoekresultaten (leeg als niet aan het zoeken)
- `isSearching(): bool` - Of er momenteel gezocht wordt
## Voorbeeld: Recentste pagina's tonen
```php
<?php
/** @var ContentAPI $api */
$pages = $api->getAllPages();
$currentLang = $api->getCurrentLanguage();
?>
<ul>
<?php foreach (array_slice($pages, 0, 5, true) as $path => $title): ?>
<li>
<a href="/<?= $currentLang ?>/<?= htmlspecialchars($path) ?>">
<?= htmlspecialchars($title) ?>
</a>
</li>
<?php endforeach; ?>
</ul>
```
## Voorbeeld: Config waarde gebruiken
```php
<?php
/** @var ContentAPI $api */
if ($api->getConfig('features.search_enabled', false)): ?>
<form method="GET" action="">
<input type="search" name="search" placeholder="<?= $api->t('search_placeholder') ?>">
<button type="submit"><?= $api->t('search_button') ?></button>
</form>
<?php endif; ?>
```
## CMSAPI (voor plugins)
Plugins gebruiken de `CMSAPI` class via `$this->api`. Deze biedt vergelijkbare methods:
```php
$this->api->getCurrentPageTitle();
$this->api->getCurrentPageContent();
$this->api->getMenu();
$this->api->getConfig('site_title');
$this->api->getCurrentLanguage();
$this->api->isHomepage();
$this->api->hasContent();
$this->api->getSearchResults();
$this->api->isSearching();
$this->api->getAvailableLanguages();
$this->api->createUrl('over-ons');
$this->api->translate('home');
```
Daarnaast heeft de CMSAPI:
- `getCurrentPage(): array` - Volledige pagina data
- `getCurrentPageUrl(): string` - URL van huidige pagina
- `getCurrentPageFileInfo(): ?array` - Bestandsinfo (created, modified)
- `getBreadcrumb(): string` - Breadcrumb HTML
- `executePhpFile(string $filePath): string` - Voer PHP bestand uit en vang output op
- `getFileContent(string $filePath): string` - Haal content uit PHP/HTML/Markdown bestand
- `contentFileExists(string $filename): bool` - Controleer of bestand bestaat in content map
@@ -0,0 +1,31 @@
# Content structuur
Content wordt opgeslagen in de `content/` map zonder database.
## Ondersteunde bestandsformaten
- `.md` - Markdown (aanbevolen)
- `.php` - Dynamische PHP pagina's
- `.html` - Statische HTML pagina's
## Bestandsnaam conventies
```
nl.pagina-naam.md # Nederlandse pagina
en.page-name.md # Engelse pagina
```
## Frontmatter
Markdown bestanden kunnen frontmatter metadata bevatten:
```markdown
---
layout: full_content
plugins: HTMLBlock
---
# Pagina titel
Content...
```
@@ -0,0 +1,16 @@
# Media beheren
## Uploaden
1. Ga naar Content map
2. Klik **Upload**
3. Selecteer bestanden (JPG, PNG, GIF, WebP, SVG, PDF, etc.)
4. Uploaden
## Gebruiken in content
```markdown
![Alt tekst](/content/afbeelding.jpg)
<video src="/content/video.mp4" controls></video>
```
@@ -0,0 +1,16 @@
# Pagina's beheren
## Via Admin Console
1. Login op `/admin`
2. Ga naar **Content**
3. Kies een map of maak een nieuwe pagina
4. Bewerk content in de editor
5. Sla op met Ctrl+S
## Editor functies
- **CodeMirror** editor met syntax highlighting
- **Toolbar** voor snel Markdown invoegen
- **Live preview** via knop
- **Auto-save** backups in `.bak/` map
+3
View File
@@ -0,0 +1,3 @@
# Handleiding
Selecteer een onderwerp uit de navigatie aan de linkerkant.
+14
View File
@@ -0,0 +1,14 @@
# Theme Developer
De theme developer handleiding bevat de volgende onderwerpen:
- **Thema structuur** - Mappenstructuur van een thema
- **theme.json** - Configuratie van een thema
- **Twig templates** - Twig syntax, variabelen en blocks
- **SCSS styling** - SCSS compileren en schrijven
- **Layouts** - Layouts definiëren en gebruiken
- **Nieuw thema** - Thema maken via admin of handmatig
Zie ook de **Content API** handleiding bij Content Beheerder voor alle beschikbare Twig variabelen en CMSAPI methods.
Selecteer een onderwerp uit de navigatie aan de linkerkant.
+27
View File
@@ -0,0 +1,27 @@
# Layouts
## Layout kiezen in content
```markdown
---
layout: left_sidebar
---
# Pagina titel
Content...
```
## Layouts in theme.json
```json
{
"default_layout": "full_content",
"layouts": {
"full_content": "full_content.twig",
"left_sidebar": "left_sidebar.twig",
"right_sidebar": "right_sidebar.twig",
"custom1": "custom1.twig"
}
}
```
+25
View File
@@ -0,0 +1,25 @@
# Nieuw thema maken
## Via Admin
1. Ga naar **Thema****Nieuw thema**
2. Geef naam (bijv. `mijn-thema`)
3. Thema wordt aangemaakt met basis structuur
4. Bewerk `theme.json` en templates
## Handmatig
```bash
mkdir themes/mijn-thema
mkdir themes/mijn-thema/partials
mkdir themes/mijn-thema/assets/{scss,css,js,fonts,img}
```
Maak basis bestanden:
- `theme.json`
- `base.twig`
- `full_content.twig`
- `partials/header.twig`
- `partials/footer.twig`
- `scss/theme.scss`
+24
View File
@@ -0,0 +1,24 @@
# SCSS styling
## theme.scss compileren
1. Ga naar **Admin****Thema**
2. Klik **SCSS compileren** bij jouw thema
3. CSS wordt gegenereerd in `assets/css/theme.css`
## SCSS voorbeeld
```scss
$primary-color: #0a369d;
$font-stack: Helvetica, Arial, sans-serif;
body {
font-family: $font-stack;
color: #333;
}
.header {
background: $primary-color;
color: #fff;
}
```
@@ -0,0 +1,21 @@
# Thema structuur
```
themes/mijn-thema/
├── theme.json # Thema configuratie
├── base.twig # Hoofd layout
├── full_content.twig # Layout: full-width
├── left_sidebar.twig # Layout: sidebar links
├── right_sidebar.twig # Layout: sidebar rechts
├── custom.twig # Layout: custom
├── partials/
│ ├── header.twig
│ ├── navigation.twig
│ └── footer.twig
└── assets/
├── scss/theme.scss # SCSS bron
├── css/ # CSS bestanden
├── js/theme.js # JavaScript
├── fonts/ # Lettertypes
└── img/ # Afbeeldingen
```
+21
View File
@@ -0,0 +1,21 @@
# theme.json
```json
{
"title": "Mijn Thema",
"default_layout": "full_content",
"header_color": "#0a369d",
"layouts": {
"full_content": "full_content.twig",
"left_sidebar": "left_sidebar.twig",
"right_sidebar": "right_sidebar.twig"
}
}
```
## Velden
- `title` - Weergavenaam in admin
- `default_layout` - Standaard layout voor nieuwe pagina's
- `header_color` - Kleur admin sidebar
- `layouts` - Mapping van layout namen naar .twig bestanden
+206
View File
@@ -0,0 +1,206 @@
# Twig templates
## Basis syntax
```twig
{# Commentaar #}
{{ variabele }}
{{ variabele|default('standaard') }}
{% if voorwaarde %}...{% endif %}
{% for item in items %}...{% endfor %}
{% extends 'base.twig' %}
{% block content %}{% endblock %}
{% include 'partials/header.twig' %}
```
## base.twig voorbeeld
```twig
<!DOCTYPE html>
<html lang="{{ current_lang }}">
<head>
<meta charset="UTF-8">
<title>{{ page_title }} - {{ site_title }}</title>
<meta name="description" content="{{ seo_description }}">
<link rel="stylesheet" href="{{ theme_css_url }}">
</head>
<body>
{% include 'partials/header.twig' %}
{% block content %}{% endblock %}
{% include 'partials/footer.twig' %}
</body>
</html>
```
## Variabelen beschikbaar in templates
### Pagina data
| Variabele | Type | Beschrijving |
|-----------|------|--------------|
| `page_title` | string | Titel van huidige pagina (HTML-escaped) |
| `content` | string | Ge-renderde pagina content (HTML) |
| `page_metadata` | array | Frontmatter metadata van de pagina |
| `layout` | string | Layout naam (bijv. `full_content`) |
| `sidebar_content` | string | Sidebar content van plugins (HTML) |
| `breadcrumb` | string | Breadcrumb HTML (gegeneerd door CMS) |
### Site data
| Variabele | Type | Beschrijving |
|-----------|------|--------------|
| `site_title` | string | Site titel uit config.json |
| `default_page` | string | Standaard pagina pad |
| `homepage` | string | Homepage pad |
| `homepage_title` | string | Homepage titel |
| `is_homepage` | bool | Of huidige pagina de homepage is |
| `is_guide_page` | bool | Of huidige pagina een handleiding is |
| `has_content` | bool | Of content map niet leeg is |
| `cms_version` | string | CMS versie nummer |
### Menu & Navigatie
| Variabele | Type | Beschrijving |
|-----------|------|--------------|
| `menu` | string | Ge-renderd menu HTML |
| `current_page` | string | Huidige pagina pad |
| `breadcrumb` | string | Breadcrumb HTML |
### Taal
| Variabele | Type | Beschrijving |
|-----------|------|--------------|
| `current_lang` | string | Huidige taal code (bijv. `nl`) |
| `current_lang_upper` | string | Huidige taal in hoofdletters |
| `available_langs` | array | Beschikbare talen met `code`, `name`, `url`, `is_current` |
### SEO
| Variabele | Type | Beschrijving |
|-----------|------|--------------|
| `seo_description` | string | SEO beschrijving |
| `seo_keywords` | string | SEO keywords |
| `block_ai_bots` | bool | AI bots blokkeren |
| `block_search_engines` | bool | Zoekmachines blokkeren |
### Auteur
| Variabele | Type | Beschrijving |
|-----------|------|--------------|
| `author_name` | string | Auteur naam |
| `author_website` | string | Auteur website URL |
| `author_git` | string | Auteur Git URL |
### Theme
| Variabele | Type | Beschrijving |
|-----------|------|--------------|
| `theme_title` | string | Thema titel |
| `theme_css_url` | string | Gecompileerde CSS URL |
| `theme_js_url` | string | JavaScript URL |
| `theme_config` | array | Thema configuratie uit theme.json |
| `theme_base_url` | string | Basis URL van thema (bijv. `/themes/default`) |
| `theme_css_files` | array | Lijst van CSS bestanden |
| `theme_js_files` | array | Lijst van JS bestanden |
| `theme_favicon` | string | Favicon URL |
| `plugin_css_urls` | array | CSS URLs van plugins (geladen ná theme CSS) |
### Theme kleuren
| Variabele | Type | Beschrijving |
|-----------|------|--------------|
| `header_color` | string | Header achtergrondkleur |
| `header_font_color` | string | Header tekstkleur |
| `header_height` | string | Header hoogte in px |
| `navigation_color` | string | Navigatie achtergrondkleur |
| `navigation_font_color` | string | Navigatie tekstkleur |
| `nav_height` | string | Navigatie hoogte in px |
| `sidebar_background` | string | Sidebar achtergrondkleur |
| `sidebar_border` | string | Sidebar randkleur |
### Bestandsinfo
| Variabele | Type | Beschrijving |
|-----------|------|--------------|
| `created` | string | Aanmaakdatum van bestand |
| `modified` | string | Wijzigingsdatum van bestand |
| `show_created` | bool | Of aanmaakdatum getoond moet worden |
| `file_info_block` | bool | Of bestandsinfo blok getoond moet worden |
### Vertalingen
| Variabele | Type | Beschrijving |
|-----------|------|--------------|
| `t_home` | string | "Home" vertaling |
| `t_search` | string | "Zoeken" vertaling |
| `t_search_placeholder` | string | Zoekbalk placeholder vertaling |
| `t_search_button` | string | Zoekknop vertaling |
| `t_welcome` | string | "Welkom" vertaling |
| `t_created` | string | "Aangemaakt" vertaling |
| `t_modified` | string | "Gewijzigd" vertaling |
| `t_author` | string | "Auteur" vertaling |
| `t_manual` | string | "Handleiding" vertaling |
| `t_guide` | string | "Handleiding" vertaling |
| `t_no_content` | string | "Geen content" vertaling |
| `t_no_results` | string | "Geen resultaten" vertaling |
| `t_results_found` | string | "Resultaten gevonden" vertaling |
| `t_powered_by` | string | "Aangedreven door" vertaling |
| `t_page_not_found` | string | "Pagina niet gevonden" vertaling |
| `t_page_not_found_text` | string | "Pagina niet gevonden" tekst vertaling |
| `t_mappen` | string | "Mappen" vertaling |
| `t_paginas` | string | "Pagina's" vertaling |
## Layouts en blocks
Een layout template extends `base.twig` en vult het `content` block:
```twig
{% extends 'base.twig' %}
{% block content %}
<div class="container">
{{ content|raw }}
</div>
{% endblock %}
```
## Conditionele sidebar
```twig
{% if sidebar_content %}
<div class="row">
<aside class="col-md-4">
{{ sidebar_content|raw }}
</aside>
<main class="col-md-8">
{{ content|raw }}
</main>
</div>
{% else %}
<div class="container">
{{ content|raw }}
</div>
{% endif %}
```
## Taal switcher
```twig
{% for lang in available_langs %}
<a href="{{ lang.url }}" class="{{ lang.is_current ? 'active' : '' }}">
{{ lang.name }}
</a>
{% endfor %}
```
## Plugin CSS laden
Plugin CSS wordt automatisch geladen ná theme CSS, zodat themes plugin styling kunnen overschrijven:
```twig
{% for cssUrl in plugin_css_urls|default([]) %}
<link href="{{ cssUrl }}" rel="stylesheet">
{% endfor %}
```