'CodePress', 'content_dir' => 'content', 'active_theme' => 'default', 'default_page' => 'auto', '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' => 'noorlander.info' ], 'show_version' => true, 'enabled_plugins' => ['MQTTTracker', 'HTMLBlock'], 'features' => [ 'auto_link_pages' => true, 'search_enabled' => true, 'breadcrumbs_enabled' => true ], 'security' => [ 'block_ai_bots' => true, 'block_scrapers' => true, 'block_search_engines' => false, 'block_empty_user_agent' => true, 'rate_limit_enabled' => true, 'rate_limit_max' => 60, 'rate_limit_window' => 60, 'custom_blocked_agents' => [], 'blocked_ips' => [], 'allowed_ips' => [] ], 'analytics' => [ 'enabled' => true, 'anonymize_ip' => false, 'geoip_provider' => 'local', 'geoip_mmdb_path' => '', 'geoip_api_url' => '', 'geoip_api_key' => '', 'retention_days' => 400, '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)); } } if (file_exists($configJsonPath)) { $jsonContent = file_get_contents($configJsonPath); $config = json_decode($jsonContent, true); if (json_last_error() === JSON_ERROR_NONE && is_array($config)) { // Merge defaults for sections that may be missing in existing installs $sectionDefaults = [ 'security' => [ 'block_ai_bots' => true, 'block_scrapers' => true, 'block_search_engines' => false, 'block_empty_user_agent' => true, 'rate_limit_enabled' => true, 'rate_limit_max' => 60, 'rate_limit_window' => 60, 'custom_blocked_agents' => [], 'blocked_ips' => [], 'allowed_ips' => [], ], 'analytics' => [ 'enabled' => true, 'anonymize_ip' => false, 'geoip_provider' => 'local', 'geoip_mmdb_path' => '', 'geoip_api_url' => '', 'geoip_api_key' => '', 'retention_days' => 400, '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']; } // 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); $config['theme'] = $themeConfig; } else { $config['theme'] = []; } return $config; } } // Fallback to minimal config return [ 'site_title' => 'CodePress', 'content_dir' => __DIR__ . '/../../content', 'default_page' => 'auto' ];