v1.9.2: Admin sidebar groepen, IP-uitsluitingen, guides herschreven

This commit is contained in:
2026-07-29 16:08:04 +02:00
parent fd393250fc
commit ebc3841a17
4 changed files with 817 additions and 892 deletions
+29 -16
View File
@@ -22,6 +22,7 @@ $layoutSidebarColor = $layoutThemeConfig['header_color'] ?? '#0a369d';
.admin-sidebar .nav-link:hover { color: #fff; background-color: rgba(255,255,255,0.1); } .admin-sidebar .nav-link:hover { color: #fff; background-color: rgba(255,255,255,0.1); }
.admin-sidebar .nav-link.active { color: #fff; background-color: rgba(255,255,255,0.2); border-left: 3px solid #fff; } .admin-sidebar .nav-link.active { color: #fff; background-color: rgba(255,255,255,0.2); border-left: 3px solid #fff; }
.admin-sidebar .nav-link i { width: 24px; text-align: center; margin-right: 0.5rem; } .admin-sidebar .nav-link i { width: 24px; text-align: center; margin-right: 0.5rem; }
.admin-sidebar .nav-section { color: rgba(255,255,255,0.4); font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.08em; padding: 1rem 1.25rem 0.3rem 1.25rem; }
.admin-main { margin-left: 240px; padding: 2rem; } .admin-main { margin-left: 240px; padding: 2rem; }
.admin-brand { color: #fff; padding: 1.25rem; font-size: 1.1rem; border-bottom: 1px solid rgba(255,255,255,0.15); } .admin-brand { color: #fff; padding: 1.25rem; font-size: 1.1rem; border-bottom: 1px solid rgba(255,255,255,0.15); }
.admin-brand i { margin-right: 0.5rem; } .admin-brand i { margin-right: 0.5rem; }
@@ -45,37 +46,50 @@ $layoutSidebarColor = $layoutThemeConfig['header_color'] ?? '#0a369d';
<i class="bi bi-gear-fill"></i> CodePress Admin <i class="bi bi-gear-fill"></i> CodePress Admin
</div> </div>
<ul class="nav flex-column mt-2"> <ul class="nav flex-column mt-2">
<li class="nav-section">Algemeen</li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link <?= ($route ?? '') === 'dashboard' || ($route ?? '') === '' ? 'active' : '' ?>" href="/admin/dashboard"> <a class="nav-link <?= ($route ?? '') === 'dashboard' || ($route ?? '') === '' ? 'active' : '' ?>" href="/admin/dashboard">
<i class="bi bi-speedometer2"></i> Dashboard <i class="bi bi-speedometer2"></i> Dashboard
</a> </a>
</li> </li>
<li class="nav-section">Content</li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link <?= ($route ?? '') === 'content' || str_starts_with($route ?? '', 'content') ? 'active' : '' ?>" href="/admin/content"> <a class="nav-link <?= ($route ?? '') === 'content' || str_starts_with($route ?? '', 'content') ? 'active' : '' ?>" href="/admin/content">
<i class="bi bi-file-earmark-text"></i> Content <i class="bi bi-file-earmark-text"></i> Content
</a> </a>
</li> </li>
<li class="nav-item"> <li class="nav-section">Instellingen</li>
<a class="nav-link <?= ($route ?? '') === 'theme' ? 'active' : '' ?>" href="/admin/theme">
<i class="bi bi-palette"></i> Thema
</a>
</li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link <?= ($route ?? '') === 'config' ? 'active' : '' ?>" href="/admin/config"> <a class="nav-link <?= ($route ?? '') === 'config' ? 'active' : '' ?>" href="/admin/config">
<i class="bi bi-sliders"></i> Configuratie <i class="bi bi-sliders"></i> Configuratie
</a> </a>
</li> </li>
<li class="nav-item">
<a class="nav-link <?= ($route ?? '') === 'theme' ? 'active' : '' ?>" href="/admin/theme">
<i class="bi bi-palette"></i> Thema
</a>
</li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link <?= ($route ?? '') === 'security' ? 'active' : '' ?>" href="/admin/security"> <a class="nav-link <?= ($route ?? '') === 'security' ? 'active' : '' ?>" href="/admin/security">
<i class="bi bi-shield-check"></i> Beveiliging <i class="bi bi-shield-check"></i> Beveiliging
</a> </a>
</li> </li>
<li class="nav-section">Gegevens</li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link <?= ($route ?? '') === 'statistics' ? 'active' : '' ?>" href="/admin/statistics"> <a class="nav-link <?= ($route ?? '') === 'statistics' ? 'active' : '' ?>" href="/admin/statistics">
<i class="bi bi-bar-chart"></i> Statistieken <i class="bi bi-bar-chart"></i> Statistieken
</a> </a>
</li> </li>
<li class="nav-item">
<a class="nav-link <?= ($route ?? '') === 'logs' ? 'active' : '' ?>" href="/admin/logs">
<i class="bi bi-journal-text"></i> Logs
</a>
</li>
<li class="nav-section">Systeem</li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link <?= ($route ?? '') === 'plugins' ? 'active' : '' ?>" href="/admin/plugins"> <a class="nav-link <?= ($route ?? '') === 'plugins' ? 'active' : '' ?>" href="/admin/plugins">
<i class="bi bi-plug"></i> Plugins <i class="bi bi-plug"></i> Plugins
@@ -86,22 +100,21 @@ $layoutSidebarColor = $layoutThemeConfig['header_color'] ?? '#0a369d';
<i class="bi bi-people"></i> Gebruikers <i class="bi bi-people"></i> Gebruikers
</a> </a>
</li> </li>
<li class="nav-item">
<a class="nav-link <?= ($route ?? '') === 'guide' ? 'active' : '' ?>" href="/admin/guide">
<i class="bi bi-book"></i> Handleiding
</a>
</li>
<li class="nav-item">
<a class="nav-link <?= ($route ?? '') === 'logs' ? 'active' : '' ?>" href="/admin/logs">
<i class="bi bi-journal-text"></i> Logs
</a>
</li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link <?= ($route ?? '') === 'update' ? 'active' : '' ?>" href="/admin/update"> <a class="nav-link <?= ($route ?? '') === 'update' ? 'active' : '' ?>" href="/admin/update">
<i class="bi bi-cloud-arrow-down"></i> Update <i class="bi bi-cloud-arrow-down"></i> Update
</a> </a>
</li> </li>
<li class="nav-item mt-3">
<li class="nav-section">Help</li>
<li class="nav-item">
<a class="nav-link <?= ($route ?? '') === 'guide' ? 'active' : '' ?>" href="/admin/guide">
<i class="bi bi-book"></i> Handleiding
</a>
</li>
<li class="nav-section mt-3">Links</li>
<li class="nav-item">
<a class="nav-link" href="/" target="_blank"> <a class="nav-link" href="/" target="_blank">
<i class="bi bi-box-arrow-up-right"></i> Website bekijken <i class="bi bi-box-arrow-up-right"></i> Website bekijken
</a> </a>
+382 -428
View File
@@ -3,22 +3,36 @@
## Table of Contents ## Table of Contents
- [Overview](#overview) - [Overview](#overview)
- [Features](#features)
- [Installation](#installation) - [Installation](#installation)
- [Project Structure](#project-structure) - [Project Structure](#project-structure)
- [Configuration](#configuration)
- [Content](#content)
- [Content Structure](#content-structure) - [Content Structure](#content-structure)
- [Admin Console](#admin-console) - [Content API (for PHP content files)](#content-api-for-php-content-files)
- [Logging & Request Log](#logging--request-log)
- [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) - [Templates](#templates)
- [URL Structure](#url-structure) - [URL Structure](#url-structure)
- [SEO Optimization](#seo-optimization) - [SEO Optimization](#seo-optimization)
- [Plugin System](#plugin-system)
- [Content API](#content-api-for-php-content-files)
- [Analytics & Tracking](#analytics--tracking)
- [Frequently Asked Questions](#frequently-asked-questions) - [Frequently Asked Questions](#frequently-asked-questions)
- [Troubleshooting](#troubleshooting) - [Troubleshooting](#troubleshooting)
- [Security](#security)
- [Version](#version) - [Version](#version)
- [Support](#support) - [Support](#support)
- [License](#license) - [License](#license)
@@ -27,72 +41,6 @@
CodePress CMS is a lightweight, file-based content management system built with PHP (>=8.0). Works without a database. CodePress CMS is a lightweight, file-based content management system built with PHP (>=8.0). Works without a database.
## Features
### Navigation
- Tab-style navigation with Bootstrap 5 styling
- Dropdown menus for folders and sub-folders
- Home button with icon
- Automatic menu generation based on directory structure
- Responsive design
- Breadcrumb navigation with sidebar toggle
- Active state marking
- **Sidebar toggle** - Button placed left of HOME in the breadcrumb to open/close the sidebar. The icon changes between open and closed state. The choice is preserved during the session
### Content Types
- **Markdown (.md)** - CommonMark support via `league/commonmark`
- **PHP (.php)** - Dynamic content with **Content API** (`$api` variable)
- **HTML (.html)** - Static HTML pages
- **Directory listings** - Automatic directory overviews
- **Language-specific content** - `en.` and `nl.` prefixes
### Search Functionality
- Full-text search through all content
- Results with snippets and highlighting
- Direct navigation to found pages
- SEO-friendly search results
- Search URL: `?search=query`
### Configuration
- **Settings form** in admin panel via `/admin/config`
- Dynamic homepage setting via dropdown (auto, newest modified page, or manual selection)
- SEO settings (description, keywords)
- Author information with links
- Theme configuration via `themes/` directory
- Language settings
- Feature toggles (auto_link_pages, search_enabled, breadcrumbs_enabled)
### Layout & Design
- Flexbox layout for responsive structure
- Fixed header with logo and search
- Breadcrumb navigation
- Fixed footer with file info and links
- Bootstrap 5 styling
- Mustache templates (`cms/templates/`)
- Semantic HTML5 structure
- **Dynamic layouts** with YAML frontmatter
- **Sidebar support** with plugin integration and toggle function via breadcrumb
- **Theme support** via `themes/` directory with theme.json per theme
### Admin Console
- Built-in admin panel at `/admin`
- **Dashboard** with statistics (pages, directories, plugins) and quick actions
- **Content management** - Browse files, upload, create, edit, rename, move and delete
- **CodeMirror editor** with toolbar (bold, italic, heading, link, image, list, media insert)
- **Media browser modal** in the editor for selecting images/files
- **Directory management** - Create, rename and delete directories (empty only)
- **Configuration editor** - Settings form for site configuration (title, homepage, language, SEO, author, features)
- **Theme management** - Create, activate, edit (colors, background) and delete themes
- **Plugin management** - Overview, create, edit, configure, enable/disable and delete
- **Media management** - Upload and delete media files in `content/-assets/`
- **User management** - Add, remove users, change passwords
- **Guide** - Built-in documentation with API reference
- **Logging** - Activity log and request log with IP, page, domain; view and download via `/admin/logs`
- **Bot & AI blocking** - Automatic 403 for known bots and AI crawlers
- Session-based authentication with bcrypt hashing
- CSRF protection, brute-force lockout (5 attempts, 15 min)
- Default login: `admin` / `admin` (change immediately after installation)
## Installation ## Installation
1. Upload files to web server 1. Upload files to web server
@@ -111,7 +59,12 @@ codepress/
│ │ ├── class/ │ │ ├── class/
│ │ │ ├── CodePressCMS.php # Main CMS class (content, navigation, search) │ │ │ ├── CodePressCMS.php # Main CMS class (content, navigation, search)
│ │ │ ├── Logger.php # Structured logging system │ │ │ ├── Logger.php # Structured logging system
│ │ │ ── SimpleTemplate.php # Mustache-style template engine │ │ │ ── SimpleTemplate.php # Mustache-style template engine
│ │ │ ├── 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/ │ │ ├── plugin/
│ │ │ ├── PluginManager.php # Plugin loader and manager │ │ │ ├── PluginManager.php # Plugin loader and manager
│ │ │ └── CMSAPI.php # API for plugin developers │ │ │ └── CMSAPI.php # API for plugin developers
@@ -120,7 +73,6 @@ codepress/
│ ├── lang/ # Language files │ ├── lang/ # Language files
│ │ ├── nl.php # Dutch translations │ │ ├── nl.php # Dutch translations
│ │ └── en.php # English translations │ │ └── en.php # English translations
│ ├── logs/ # CMS logs
│ ├── templates/ # Mustache templates │ ├── templates/ # Mustache templates
│ │ ├── layout.mustache # Main layout (CSS, structure) │ │ ├── layout.mustache # Main layout (CSS, structure)
│ │ ├── assets/ # Header, navigation, footer partials │ │ ├── assets/ # Header, navigation, footer partials
@@ -144,14 +96,18 @@ codepress/
│ │ ├── content-new.php # Create new content │ │ ├── content-new.php # Create new content
│ │ ├── content-dir-form.php # Create/edit directory │ │ ├── content-dir-form.php # Create/edit directory
│ │ ├── content-move-form.php # Move content │ │ ├── content-move-form.php # Move content
│ │ ├── config.php # Configuration editor (JSON) │ │ ├── config.php # Configuration editor
│ │ ├── security.php # Security settings
│ │ ├── statistics.php # Statistics dashboard
│ │ ├── plugins.php # Plugin overview │ │ ├── plugins.php # Plugin overview
│ │ ├── plugins-edit.php # Plugin PHP source code editor │ │ ├── plugins-edit.php # Plugin PHP source code editor
│ │ ├── plugins-new.php # Create new plugin │ │ ├── plugins-new.php # Create new plugin
│ │ ├── plugin-config.php # Plugin configuration editor │ │ ├── plugin-config.php # Plugin configuration editor
│ │ ├── theme.php # Theme management (create, activate, edit) │ │ ├── theme.php # Theme management
│ │ ├── media.php # Media management (upload, delete) │ │ ├── users.php # User management
│ │ ── users.php # User management │ │ ── logs.php # Log viewer
│ │ ├── update.php # System update
│ │ └── guide.php # Guide
│ └── storage/logs/ # Admin logs │ └── storage/logs/ # Admin logs
├── cli/ # CLI scripts & tests ├── cli/ # CLI scripts & tests
├── content/ # Content files ├── content/ # Content files
@@ -160,8 +116,7 @@ codepress/
│ └── ... # Other content │ └── ... # Other content
├── plugins/ # CMS plugins ├── plugins/ # CMS plugins
│ ├── HTMLBlock/ # Custom HTML blocks in sidebar │ ├── HTMLBlock/ # Custom HTML blocks in sidebar
── MQTTTracker/ # Real-time analytics and tracking ── MQTTTracker/ # Real-time analytics and tracking
│ └── test/ # Test plugin
├── public/ # Web root ├── public/ # Web root
│ ├── index.php # Website entry point (media serving + CMS) │ ├── index.php # Website entry point (media serving + CMS)
│ ├── admin.php # Admin entry point + routing │ ├── admin.php # Admin entry point + routing
@@ -174,28 +129,173 @@ codepress/
├── themes/ # Theme definitions ├── themes/ # Theme definitions
│ ├── default/ # Default theme │ ├── default/ # Default theme
│ │ └── theme.json # Colors, heights, background │ │ └── theme.json # Colors, heights, background
│ └── test/ # Test theme │ └── ... # Other themes
│ └── theme.json
├── config.json # Site configuration ├── config.json # Site configuration
├── version.php # Version information (1.6.0) ├── version.php # Version information
└── vendor/ # Composer dependencies └── vendor/ # Composer dependencies
``` ```
## Configuration ---
### Basic Configuration ## Content
The site configuration is managed via the **admin panel** at `/admin/config`. Here you'll find a settings form with the following sections: ### 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) - **General settings** - Site title and homepage (dropdown with available pages)
- **Language** - Default language and available languages - **Language** - Default language and available languages
- **SEO** - Meta description and keywords - **SEO** - Meta description and keywords
- **Author** - Name and website - **Author** - Name and website
- **Features** - Auto-link pages, search, breadcrumbs, show version - **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 like `active_theme`, `content_dir` and `templates_dir`. The configuration is stored in `config.json`. You can also edit this file manually for advanced options.
### Example `config.json` #### 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 ```json
{ {
@@ -220,11 +320,25 @@ The configuration is stored in `config.json`. You can also edit this file manual
"auto_link_pages": true, "auto_link_pages": true,
"search_enabled": true, "search_enabled": true,
"breadcrumbs_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
} }
} }
``` ```
### Theme Configuration (`themes/<name>/theme.json`) ### Themes
Themes are managed via the admin panel at `/admin/theme`. You can create, activate, adjust colors, upload background images, and delete themes.
#### Theme Configuration (`themes/<name>/theme.json`)
```json ```json
{ {
@@ -242,232 +356,82 @@ The configuration is stored in `config.json`. You can also edit this file manual
} }
``` ```
Themes can be managed via the admin panel: create, activate, adjust colors, upload background image and delete. #### How to create a new theme
## Content Structure 1. Go to `/admin/theme`
2. Enter a name and click "Create"
3. Adjust colors, heights and background
4. Activate the theme
### File Structure ### Security
``` Security settings are managed via `/admin/security`. Includes:
content/
├── folder1/
│ ├── subfolder1/
│ │ ├── nl.page1.md
│ │ └── en.page1.md
│ └── page3.html
├── folder2/
│ └── page4.md
├── index.md
└── -assets/
├── image.jpg
└── document.pdf
```
### File Naming #### Bot, AI & Scraper Blocking
- 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/`
## Admin Console
### Access
- **URL**: `/admin`
- **Default login**: `admin` / `admin`
### Routes
| Route | Description |
|---|---|
| `login` | Login page |
| `logout` | Logout |
| `dashboard` | Dashboard with statistics |
| `content` | Content overview (browse, upload) |
| `content-edit` | Edit content (CodeMirror editor) |
| `content-new` | Create new content |
| `content-delete` | Delete content |
| `content-move` | Move content to another directory |
| `content-dir-form` | Create or edit directory |
| `content-dir-rename` | Rename directory |
| `content-dir-create` | Create directory (POST) |
| `content-dir-delete` | Delete directory (empty only) |
| `config` | Configuration form (title, homepage, language, SEO, author, features) |
| `security` | Security settings (bot/AI blocking, rate limiting, IP block/allowlist) |
| `statistics` | Visitor statistics with world map, countries, pages and GeoIP settings |
| `update` | One-click system update via Git pull |
| `theme` | Theme management |
| `plugins` | Plugin overview |
| `plugins-new` | Create new plugin |
| `plugins-edit` | Edit plugin PHP source code |
| `plugins-config` | Edit plugin configuration |
| `plugins-toggle` | Enable/disable plugin |
| `plugins-delete` | Delete plugin |
| `media` | Media management (upload, delete) |
| `media-list` | JSON list of all media (for editor modal) |
| `users` | User management |
| `guide` | Guide / documentation |
| `logs` | Log viewer (activity + requests) |
### Editor Features
The content editor (`content-edit`, `content-new`) includes:
- **CodeMirror** syntax highlighting for Markdown/PHP/HTML
- **Toolbar** with buttons for: bold, italic, heading, link, image, list, media insert
- **Media browser modal** - Open via the "Media" button to select images/files
- **Inline filename rename** - Inline filename input with extension badge
- **Layout selector** - Choose from available layouts
- **Plugin per-page visibility** - Select which plugins to show on this page
- **Upload and "Create" buttons** are disabled until input is provided
- **"Cancel" button** (instead of "Back") for unsaved changes
### Logging & Request Log
The admin console maintains two 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.
Both logs can be viewed and downloaded via **`/admin/logs`** or the sidebar "Logs" link. The dashboard shows the last 20 entries of each log. Click "View all →" for the full list, where you can also download or clear.
### Bot & AI Blocking
Incoming requests are checked against known bot and AI crawler patterns via the User-Agent header. Detected bots receive a **403 Forbidden** response. Incoming requests are checked against known bot and AI crawler patterns via the User-Agent header. Detected bots receive a **403 Forbidden** response.
Blocked categories:
| Category | Examples | | Category | Examples |
|---|---| |---|---|
| AI Crawlers | GPTBot, ChatGPT-User, Claude-Web, ClaudeBot, Google-Extended, CCBot, PerplexityBot | | AI Crawlers | GPTBot, ChatGPT-User, Claude-Web, ClaudeBot, Google-Extended, CCBot, PerplexityBot |
| Search Engines | Googlebot, Bingbot, BingPreview, DuckDuckBot, YandexBot, Baiduspider | | Search Engines | Googlebot, Bingbot, BingPreview, DuckDuckBot, YandexBot, Baiduspider |
| Scrapers | HTTrack, Scrapy, PhantomJS | | Scrapers | HTTrack, Scrapy, PhantomJS |
## Templates #### Rate Limiting
### Template Variables Prevents IPs from overloading the site. Returns HTTP 429 on exceedance.
#### Site Info #### IP Lists
- `site_title` - Website title
- `author_name` - Author name
- `author_website` - Author website
- `author_git` - Git repository link
#### Page Info - **IP Whitelist** - IPs on the whitelist are never blocked
- `page_title` - Page title - **IP Blocklist** - IPs on the blocklist always receive a 403 Forbidden
- `content` - Content (HTML)
- `file_info` - File information
- `is_homepage` - Boolean: is this the homepage?
#### Navigation #### Dynamic robots.txt
- `menu` - Navigation menu
- `breadcrumb` - Breadcrumb navigation
- `homepage` - Homepage link
#### Theme (from theme.json) The system automatically generates a `robots.txt` based on your security settings, available at `/robots.txt`.
- `header_color` - Header background color
- `header_font_color` - Header text color
- `header_height` - Header height in pixels
- `navigation_color` - Navigation background color
- `navigation_font_color` - Navigation text color
- `nav_height` - Navigation height in pixels
- `sidebar_background` - Sidebar background color
- `sidebar_border` - Sidebar border color
- `background_image_css` - CSS for background image
- `background_image_opacity` - Overlay opacity
#### Language
- `current_lang` - Current language (en/nl)
- `current_lang_upper` - Current language (EN/NL)
- `t_*` - Translated strings
### Layout Options
Use YAML frontmatter to select layout:
```yaml
--- ---
title: My Page
layout: sidebar-content ## Data
plugins: HTMLBlock
### 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 two 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.
The dashboard shows the last 20 entries of each log. Click "View all →" for the full list, where you can also download or clear.
--- ---
```
### Available Layouts ## System
- `sidebar-content` - Sidebar left, content right (default) ### Plugin System
- `content` - Content only (full width)
- `sidebar` - Sidebar only
- `content-sidebar` - Content left, sidebar right
- `content-sidebar-reverse` - Content right, sidebar left
### Meta Data #### Plugin Structure
```yaml
---
title: Page Title
layout: content-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)
- **Guide**: `/en/guide`
- **Language switch**: `/nl` or `/en`
### 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`
- **Edit content**: `/admin/content-edit?file=page.md`
- **New content**: `/admin/content-new?dir=folder`
- **Edit theme**: `/admin/theme?edit=themename`
## 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'; ...
```
## Plugin System
### Plugin Structure
``` ```
plugins/ plugins/
@@ -479,13 +443,9 @@ plugins/
│ ├── MQTTTracker.php │ ├── MQTTTracker.php
│ ├── config.json │ ├── config.json
│ └── README.md │ └── README.md
└── test/
├── test.php
├── config.json
└── README.md
``` ```
### Plugin Development #### Plugin Development
- **API access** via `CMSAPI` class - gives access to CMS configuration, templates, menu - **API access** via `CMSAPI` class - gives access to CMS configuration, templates, menu
- **Sidebar content** with `getSidebarContent()` - returns HTML for sidebar - **Sidebar content** with `getSidebarContent()` - returns HTML for sidebar
@@ -494,7 +454,7 @@ plugins/
- **viewable** field in config.json determines if plugin is visible in sidebar - **viewable** field in config.json determines if plugin is visible in sidebar
- **Per-page visibility** - via the editor plugin selector per page - **Per-page visibility** - via the editor plugin selector per page
### Plugin Boilerplate #### Plugin Boilerplate
```php ```php
<?php <?php
@@ -533,196 +493,190 @@ class MyPlugin
} }
``` ```
### Available Plugins #### Known Issue: MQTTTracker Credentials
- **HTMLBlock** - Custom HTML blocks in sidebar
- **MQTTTracker** - Real-time analytics and tracking via MQTT
- **test** - Example/test plugin
### 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. 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.
## Content API (for PHP content files) ### User Management
PHP content files (`.php` in the `content/` directory) have access to an `$api` variable with the following methods: 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)
### Getting pages Passwords are stored as bcrypt hashes in `admin/config/admin.json`.
```php ### Update
// Get all pages with titles
$pages = $api->getAllPages();
// Result: ['index' => 'Home', 'about' => 'About Us', ...]
// Get a specific page's content 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.
$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 ## Guide (in Admin)
This guide is also built into the admin panel via `/admin/guide`, with support for Dutch and English.
---
## Other
### Templates
#### 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 (from theme.json)** - `header_color`, `header_font_color`, `header_height`, `navigation_color`, `navigation_font_color`, `nav_height`, `sidebar_background`, `sidebar_border`, `background_image_css`, `background_image_opacity`
**Language** - `current_lang`, `current_lang_upper`, `t_*` (translated strings)
#### Layout Options
Use YAML frontmatter to select layout:
```yaml
---
title: My Page
layout: sidebar-content
plugins: HTMLBlock
--- ---
<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>
``` ```
## Analytics & Tracking #### Available Layouts
### MQTT Tracker - `sidebar-content` - Sidebar left, content right (default)
- `content` - Content only (full width)
- `sidebar` - Sidebar only
- `content-sidebar` - Content left, sidebar right
- `content-sidebar-reverse` - Content right, sidebar left
- Real-time page tracking via MQTT broker #### Meta Data
- Session management
- Business Intelligence data
- Privacy aware (GDPR compliant)
- MQTT integration for dashboards
- Optional: visitor tracking, page views, performance metrics, user flows
## Frequently Asked Questions ```yaml
---
title: Page Title
layout: content-sidebar
description: Page description
author: Author Name
date: 2025-11-26
plugins: HTMLBlock, MQTTTracker
---
```
### How do I set the homepage? ### 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`) 1. Go to **Configuration** in the admin panel (`/admin/config`)
2. Select the desired page in the **Default/homepage** dropdown 2. Select the desired page in the **Default/homepage** dropdown
3. Click **Save configuration** 3. Click **Save configuration**
### How does navigation work? #### How does navigation work?
- **Directories** become dropdown menus - **Directories** become dropdown menus
- **Files** become direct links - **Files** become direct links
- **Sub-directories** become nested dropdowns - **Sub-directories** become nested dropdowns
- Only files without a language prefix show in the menu - Only files without a language prefix show in the menu
### How do I add new content? #### How do I add new content?
1. Via the admin panel: `/admin/content-new` 1. Via the admin panel: `/admin/content-new`
2. Or upload files to the `content/` directory 2. Or upload files to the `content/` directory
3. Organize in logical directories 3. Organize in logical directories
4. Use correct filenames and extensions 4. Use correct filenames and extensions
### How do I move a file or directory? #### How do I move a file or directory?
1. Go to `/admin/content` 1. Go to `/admin/content`
2. Click "Move" next to the item 2. Click "Move" next to the item
3. Select the target directory 3. Select the target directory
4. Confirm the move 4. Confirm the move
### How do I create a new theme? #### How do I exclude my own IP from statistics?
1. Go to `/admin/theme` 1. Go to **Configuration** in the admin panel (`/admin/config`)
2. Enter a name and click "Create" 2. Scroll to the "IP Exclusions" field
3. Adjust colors, heights and background 3. Enter your IP address (one per line)
4. Activate the theme 4. Click **Save configuration**
## Troubleshooting ### Troubleshooting
### Page not found (404) #### Page not found (404)
1. Check filename and path 1. Check filename and path
2. Check file extension (.md, .php, .html) 2. Check file extension (.md, .php, .html)
3. Check file permissions 3. Check file permissions
4. Check if the file has the correct language prefix (`nl.` or `en.`) 4. Check if the file has the correct language prefix (`nl.` or `en.`)
### Navigation not updated #### Navigation not updated
1. Reload the page 1. Reload the page
2. Check content directory structure 2. Check content directory structure
3. Check filenames (no spaces) 3. Check filenames (no spaces)
4. Files with language prefix only show in the correct language mode 4. Files with language prefix only show in the correct language mode
### Admin panel not accessible #### Admin panel not accessible
1. Check if the session is still valid 1. Check if the session is still valid
2. On lockout: wait 15 minutes or clear lockout data in `admin/config/admin.json` 2. On lockout: wait 15 minutes or clear lockout data in `admin/config/admin.json`
3. Check CSRF token (reload the page) 3. Check CSRF token (reload the page)
## Security
- **CSRF protection** via tokens on all admin forms
- **Brute-force lockout** after 5 failed attempts (15 minute block)
- **Bcrypt password hashing** for user passwords
- **Path traversal prevention** via `realpath()` and prefix check
- **Direct content access** blocked (403 Forbidden)
- **Security headers** for all pages
- **PHP execution** in content directory blocked
- **File upload restrictions** on allowed extensions
## Version ## Version
Current version: **1.6.0** (codename: "Enhanced") Current version: **1.9.1**
Release date: 2026-07-14 Release date: 2026-07-29
## Support ## Support
+385 -435
View File
File diff suppressed because it is too large Load Diff
+9 -1
View File
@@ -6,12 +6,20 @@
*/ */
return [ return [
'version' => '1.9.1', 'version' => '1.9.2',
'release_date' => '2026-07-29', 'release_date' => '2026-07-29',
'codename' => 'Atlas', 'codename' => 'Atlas',
'status' => 'stable', 'status' => 'stable',
'changelog' => [ 'changelog' => [
'1.9.2' => [
'date' => '2026-07-29',
'changes' => [
'Admin sidebar restructured into logical groups: Algemeen, Content, Instellingen, Gegevens, Systeem, Help, Links',
'IP uitsluitingen toegevoegd aan configuratie: IP's niet meetellen in statistieken en overslaan bij beveiligingscontroles',
'Guide (NL/EN) volledig herschreven metzelfde logische indeling als sidebar',
]
],
'1.9.1' => [ '1.9.1' => [
'date' => '2026-07-29', 'date' => '2026-07-29',
'changes' => [ 'changes' => [