CMS 2.0 - Theme engine, logging, admin improvements

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
This commit is contained in:
2026-08-08 18:02:14 +02:00
parent d453b8073f
commit 6333bc410f
833 changed files with 108974 additions and 1386 deletions
+53 -8
View File
@@ -12,7 +12,6 @@ if (!file_exists($configJsonPath)) {
$defaultConfig = [
'site_title' => 'CodePress',
'content_dir' => 'content',
'templates_dir' => 'cms/templates',
'active_theme' => 'default',
'default_page' => 'auto',
'language' => [
@@ -25,7 +24,7 @@ if (!file_exists($configJsonPath)) {
],
'author' => [
'name' => 'E. Noorlander',
'website' => 'https://noorlander.info'
'website' => 'noorlander.info'
],
'show_version' => true,
'enabled_plugins' => ['MQTTTracker', 'HTMLBlock'],
@@ -54,7 +53,29 @@ if (!file_exists($configJsonPath)) {
'geoip_api_url' => '',
'geoip_api_key' => '',
'retention_days' => 400,
'excluded_ips' => []
'excluded_ips' => [
'192.168.0.0/16',
'10.0.0.0/8',
'172.16.0.0/12',
'127.0.0.1',
'::1'
]
],
'logging' => [
'enabled' => true,
'driver' => 'sqlite',
'syslog_host' => '',
'syslog_port' => 514,
'syslog_facility' => 'local0',
'syslog_ident' => 'codepress',
'events' => [
'admin' => true,
'requests' => true,
'errors' => true,
'security' => true,
'content' => true,
'system' => true
]
]
];
@file_put_contents($configJsonPath, json_encode($defaultConfig, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
@@ -88,25 +109,50 @@ if (file_exists($configJsonPath)) {
'geoip_api_url' => '',
'geoip_api_key' => '',
'retention_days' => 400,
'excluded_ips' => [],
'excluded_ips' => [
'192.168.0.0/16',
'10.0.0.0/8',
'172.16.0.0/12',
'127.0.0.1',
'::1'
],
],
'logging' => [
'enabled' => true,
'driver' => 'sqlite',
'syslog_host' => '',
'syslog_port' => 514,
'syslog_facility' => 'local0',
'syslog_ident' => 'codepress',
'events' => [
'admin' => true,
'requests' => true,
'errors' => true,
'security' => true,
'content' => true,
'system' => true
],
],
];
foreach ($sectionDefaults as $section => $defaults) {
$config[$section] = array_merge($defaults, is_array($config[$section] ?? null) ? $config[$section] : []);
}
// Ensure the private/loopback IP defaults are present when the list is empty
if (empty($config['analytics']['excluded_ips'])) {
$config['analytics']['excluded_ips'] = $sectionDefaults['analytics']['excluded_ips'];
}
// Convert relative paths to absolute
$projectRoot = __DIR__ . '/../../';
if (isset($config['content_dir']) && strpos($config['content_dir'], '/') !== 0) {
$config['content_dir'] = $projectRoot . $config['content_dir'];
}
if (isset($config['templates_dir']) && strpos($config['templates_dir'], '/') !== 0) {
$config['templates_dir'] = $projectRoot . $config['templates_dir'];
}
// Load active theme
$activeTheme = $config['active_theme'] ?? 'default';
$themeDir = __DIR__ . '/../../themes/' . $activeTheme;
$config['theme_dir'] = $themeDir;
$themeFile = $themeDir . '/theme.json';
if (file_exists($themeFile)) {
$themeConfig = json_decode(file_get_contents($themeFile), true);
@@ -123,6 +169,5 @@ if (file_exists($configJsonPath)) {
return [
'site_title' => 'CodePress',
'content_dir' => __DIR__ . '/../../content',
'templates_dir' => __DIR__ . '/../templates',
'default_page' => 'auto'
];