# 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) │ │ │ ├── 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.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 ---

All Pages

``` --- ## 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", "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//theme.json`) ```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 1. Go to `/admin/theme` 2. Enter a name and click "Create" 3. Adjust colors, heights and background 4. 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 `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 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 ` 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: ```yaml --- title: My Page layout: sidebar-content plugins: HTMLBlock --- ``` #### Available Layouts - `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 #### Meta Data ```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) #### 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 ``` #### 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.