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:
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
```
|
||||
@@ -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);
|
||||
```
|
||||
@@ -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();
|
||||
```
|
||||
@@ -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
|
||||
```
|
||||
@@ -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
|
||||
```
|
||||
@@ -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.
|
||||
@@ -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
|
||||

|
||||
|
||||
<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
|
||||
@@ -0,0 +1,3 @@
|
||||
# Manual
|
||||
|
||||
Select a topic from the navigation on the left.
|
||||
@@ -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.
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -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`
|
||||
@@ -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
|
||||
```
|
||||
@@ -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
|
||||
@@ -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 %}
|
||||
```
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
```
|
||||
@@ -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);
|
||||
```
|
||||
@@ -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();
|
||||
```
|
||||
@@ -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
|
||||
```
|
||||
@@ -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
|
||||
```
|
||||
@@ -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.
|
||||
@@ -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
|
||||

|
||||
|
||||
<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
|
||||
@@ -0,0 +1,3 @@
|
||||
# Handleiding
|
||||
|
||||
Selecteer een onderwerp uit de navigatie aan de linkerkant.
|
||||
@@ -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.
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -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`
|
||||
@@ -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
|
||||
```
|
||||
@@ -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
|
||||
@@ -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 %}
|
||||
```
|
||||
Reference in New Issue
Block a user