20 KiB
CodePress CMS Guide
Table of Contents
Overview
CodePress CMS is a lightweight, file-based content management system built with PHP (>=8.0). Works without a database.
Installation
- Upload files to web server
- Set permissions for web server
- Run
composer installfor CommonMark dependency - Configure
config.jsonif needed - Access website via browser
- PHP development server:
php -S localhost:8080 -t public(usescms/router.php)
Project Structure
codepress/
├── cms/ # Core CMS engine
│ ├── core/
│ │ ├── class/
│ │ │ ├── CodePressCMS.php # Main CMS class (content, navigation, search)
│ │ │ ├── Logger.php # Structured logging system
│ │ │ ├── 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/
│ │ │ ├── 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
│ ├── templates/ # Mustache templates
│ │ ├── layout.mustache # Main layout (CSS, structure)
│ │ ├── assets/ # Header, navigation, footer partials
│ │ ├── markdown_content.mustache
│ │ ├── php_content.mustache
│ │ └── html_content.mustache
│ └── router.php # PHP dev server router
├── 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/ # Uploaded theme backgrounds
│ └── manifest.json / sw.js # PWA support
├── themes/ # Theme definitions
│ ├── default/ # Default theme
│ │ └── theme.json # Colors, heights, background
│ └── ... # Other themes
├── 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.mdanden.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
// 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
// Get menu structure
$menu = $api->getMenu();
// Nested array with 'title', 'path', 'url', 'children'
Configuration
// Get config value (dot notation)
$title = $api->getConfig('site_title');
$lang = $api->getConfig('language.default');
$seoDesc = $api->getConfig('seo.description', 'Default description');
Current page
// 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
// 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
// Get translation
$label = $api->t('home');
// Search results (if searching)
if ($api->isSearching()) {
$results = $api->getSearchResults();
}
Example PHP content file
---
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
{
"site_title": "CodePress",
"content_dir": "content",
"templates_dir": "cms\/templates",
"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. You can create, activate, adjust colors, upload background images, and delete themes.
Theme Configuration (themes/<name>/theme.json)
{
"name": "Default",
"header_color": "#0a369d",
"header_font_color": "#ffffff",
"header_height": "56",
"navigation_color": "#2754b4",
"navigation_font_color": "#ffffff",
"nav_height": "42",
"sidebar_background": "#f8f9fa",
"sidebar_border": "#dee2e6",
"background_image": "",
"background_image_opacity": "100"
}
How to create a new theme
- Go to
/admin/theme - Enter a name and click "Create"
- Adjust colors, heights and background
- Activate the theme
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 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.
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
CMSAPIclass - 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
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
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:
---
title: My Page
layout: sidebar-content
plugins: HTMLBlock
---
Available Layouts
sidebar-content- Sidebar left, content right (default)content- Content only (full width)sidebar- Sidebar onlycontent-sidebar- Content left, sidebar rightcontent-sidebar-reverse- Content right, sidebar left
Meta Data
---
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)
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:
<meta name="generator" content="CodePress CMS">
<meta name="author" content="E. Noorlander">
<meta name="description" content="...">
<meta name="keywords" content="...">
Security Headers
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?
- Go to Configuration in the admin panel (
/admin/config) - Select the desired page in the Default/homepage dropdown
- 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?
- Via the admin panel:
/admin/content-new - Or upload files to the
content/directory - Organize in logical directories
- Use correct filenames and extensions
How do I move a file or directory?
- Go to
/admin/content - Click "Move" next to the item
- Select the target directory
- Confirm the move
How do I exclude my own IP from statistics?
- Go to Configuration in the admin panel (
/admin/config) - Scroll to the "IP Exclusions" field
- Enter your IP address (one per line)
- Click Save configuration
Troubleshooting
Page not found (404)
- Check filename and path
- Check file extension (.md, .php, .html)
- Check file permissions
- Check if the file has the correct language prefix (
nl.oren.)
Navigation not updated
- Reload the page
- Check content directory structure
- Check filenames (no spaces)
- Files with language prefix only show in the correct language mode
Admin panel not accessible
- Check if the session is still valid
- On lockout: wait 15 minutes or clear lockout data in
admin/config/admin.json - 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.