default $defaultConfig = __DIR__ . '/default/config.ini'; $customConfig = __DIR__ . '/../custom/config.ini'; // Start with default config $config = file_exists($defaultConfig) ? parse_ini_file($defaultConfig, true) : []; // Merge with custom config if it exists if (file_exists($customConfig)) { $config = array_replace_recursive($config, parse_ini_file($customConfig, true) ?: []); } // Load global plugins getPluginManager()->loadGlobalPlugins($config); // Use user content if exists and has content, otherwise fall back to demo content $userContentDir = $_SERVER['DOCUMENT_ROOT']; $demoContentDir = __DIR__ . '/default/content'; // Check if user content directory has actual content (more than just . and ..) $hasUserContent = is_dir($userContentDir) && count(scandir($userContentDir) ?: []) > 2; $contentDir = $hasUserContent ? realpath($userContentDir) : realpath($demoContentDir); // Extract request information $requestUri = parse_url($_SERVER['REQUEST_URI'] ?? '', PHP_URL_PATH) ?: '/'; $hasTrailingSlash = str_ends_with($requestUri, '/') && $requestUri !== '/'; $requestPath = trim($requestUri, '/'); // Resolve templates with custom fallback to defaults $templates = new Templates( base: resolveTemplate('base'), page: resolveTemplate('page'), list: resolveTemplate('list') ); // Create base context $ctx = new Context( contentDir: $contentDir, templates: $templates, requestPath: $requestPath, hasTrailingSlash: $hasTrailingSlash ); // Store globally for plugins $GLOBALS['ctx'] = $ctx; // Let plugins modify context (e.g., extract language from URL) $ctx = Hooks::apply(Hook::CONTEXT_READY, $ctx, $config); return $ctx; }