Major changes: - New ThemeManager with Twig templating and SCSS compilation - Dynamic themes system (themes/default, themes/demo) - LogManager with SQLite storage and syslog forwarding - RequestLogger with static helper methods - Admin UI overhaul (Bootstrap 5, dark mode) - Admin config page with logging and theme settings - Admin logs page with filters and search - Removed legacy Mustache templates - Removed test plugin and theme - Composer dependencies: Twig, scssphp, CommonMark, MaxMind GeoIP
25 KiB
CodePress CMS Handleiding
Inhoudsopgave
Overzicht
CodePress CMS is een lichtgewicht, file-based content management systeem gebouwd met PHP (>=8.0). Werkt zonder database.
Installatie
- Upload bestanden naar webserver
- Stel permissies in voor webserver
- Voer
composer installuit voor CommonMark dependency - Configureer
config.jsonindien nodig - Toegang tot website via browser
- PHP ontwikkelserver:
php -S localhost:8080 -t public(gebruiktcms/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.mdenen.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
// 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
// Menu structuur ophalen
$menu = $api->getMenu();
// Bevat geneste array met 'title', 'path', 'url', 'children'
Configuratie
// Configuratie waarde opvragen (punt-notatie)
$title = $api->getConfig('site_title');
$lang = $api->getConfig('language.default');
$seoDesc = $api->getConfig('seo.description', 'Standaard beschrijving');
Huidige pagina
// 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
// 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
// Vertaling ophalen
$label = $api->t('home');
// Zoekresultaten (als er gezocht wordt)
if ($api->isSearching()) {
$results = $api->getSearchResults();
}
Voorbeeld PHP content bestand
---
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
{
"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)
{
"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:
$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) ofSyslog. - 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–local7zijn bedoeld voor eigen applicaties;daemon,userenauthzijn 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
CMSAPIclass - 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
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:
---
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 rechtsright_sidebar- Content links, sidebar rechtscustom1- Custom layout
Vraag een pagina een onbekende layout aan, dan wordt de default_template uit config van het thema gebruikt.
Meta Data
---
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:
<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'; ...
Veelgestelde Vragen
Hoe stel ik de homepage in?
- Ga naar Configuratie in het admin paneel (
/admin/config) - Selecteer de gewenste pagina in het Standaard/startpagina dropdown
- 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?
- Via het admin paneel:
/admin/content-new - Of upload bestanden naar de
content/map - Organiseer in logische mappen
- Gebruik juiste bestandsnamen en extensies
Hoe verplaats ik een bestand of map?
- Ga naar
/admin/content - Klik op "Verplaatsen" naast het item
- Selecteer de doelmap
- Bevestig de verplaatsing
Hoe sluit ik mijn eigen IP uit van statistieken?
- Ga naar Configuratie in het admin paneel (
/admin/config) - Scroll naar het veld "IP-adressen uitsluiten"
- Voer je IP-adres in (één per regel)
- Klik op Configuratie opslaan
Troubleshooting
Pagina niet gevonden (404)
- Controleer bestandsnaam en pad
- Controleer bestandsextensie (.md, .php, .html)
- Controleer permissies van bestanden
- Controleer of het bestand de juiste taalprefix heeft (
nl.ofen.)
Navigatie niet bijgewerkt
- Herlaad de pagina
- Controleer content map structuur
- Controleer bestandsnamen (geen spaties)
- Bestanden met taalprefix worden alleen getoond in de juiste taalmodus
Admin paneel niet toegankelijk
- Controleer of de sessie nog geldig is
- Bij lockout: wacht 15 minuten of wis
admin/config/admin.jsonlockout data - 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.