partial}}) $template = preg_replace_callback('/{{>([^}]+)}}/', function($matches) use ($data) { $partialName = $matches[1]; return $data[$partialName] ?? $matches[0]; }, $template); // Handle conditional blocks foreach ($data as $key => $value) { if (is_array($value) || (is_string($value) && !empty($value))) { // Handle {{#key}}...{{/key}} blocks $pattern = '/{{#' . preg_quote($key, '/') . '}}(.*?){{\/' . preg_quote($key, '/') . '}}/s'; if (preg_match($pattern, $template, $matches)) { $replacement = $matches[1]; $template = preg_replace($pattern, $replacement, $template); } // Handle {{^key}}...{{/key}} blocks (negative condition) $pattern = '/{{\^' . preg_quote($key, '/') . '}}(.*?){{\/' . preg_quote($key, '/') . '}}/s'; $template = preg_replace($pattern, '', $template); } else { // Handle empty blocks $pattern = '/{{#' . preg_quote($key, '/') . '}}.*?{{\/' . preg_quote($key, '/') . '}}/s'; $template = preg_replace($pattern, '', $template); // Handle {{^key}}...{{/key}} blocks (show when empty) $pattern = '/{{\^' . preg_quote($key, '/') . '}}(.*?){{\/' . preg_quote($key, '/') . '}}/s'; if (preg_match_all($pattern, $template, $matches)) { foreach ($matches[1] as $match) { $template = preg_replace('/{{\^' . preg_quote($key, '/') . '}}.*?{{\/' . preg_quote($key, '/') . '}}/s', $match, $template, 1); } } } } // Handle variable replacements foreach ($data as $key => $value) { // Handle triple braces for unescaped HTML content if (strpos($template, '{{{' . $key . '}}}') !== false) { $template = str_replace('{{{' . $key . '}}}', $value, $template); } // Handle double braces for escaped content elseif (strpos($template, '{{' . $key . '}}') !== false) { $template = str_replace('{{' . $key . '}}', htmlspecialchars($value, ENT_QUOTES, 'UTF-8'), $template); } } return $template; } } $config = include 'config.php'; /** * CodePressCMS - Lightweight file-based content management system * * Features: * - Markdown, PHP, and HTML content support * - Dynamic navigation with dropdown menus * - Search functionality * - Breadcrumb navigation * - Auto-linking between pages * - Configurable via JSON * - Responsive design with Bootstrap */ /** * CodePressCMS - Lightweight file-based content management system * * Features: * - Markdown, PHP, and HTML content support * - Dynamic navigation with dropdown menus * - Search functionality * - Breadcrumb navigation * - Auto-linking between pages * - Configurable via JSON * - Responsive design with Bootstrap */ class CodePressCMS { private $config; private $menu = []; private $searchResults = []; public function __construct($config) { $this->config = $config; $this->buildMenu(); if (isset($_GET['search'])) { $this->performSearch($_GET['search']); } } private function buildMenu() { $this->menu = $this->scanDirectory($this->config['content_dir'], ''); } private function scanDirectory($dir, $prefix) { if (!is_dir($dir)) return []; $items = scandir($dir); sort($items); $result = []; foreach ($items as $item) { if ($item[0] === '.') continue; $path = $dir . '/' . $item; $relativePath = $prefix ? $prefix . '/' . $item : $item; if (is_dir($path)) { $result[] = [ 'type' => 'folder', 'title' => ucfirst($item), 'path' => $relativePath, 'children' => $this->scanDirectory($path, $relativePath) ]; } elseif (preg_match('/\.(md|php|html)$/', $item)) { $title = ucfirst(pathinfo($item, PATHINFO_FILENAME)); $result[] = [ 'type' => 'file', 'title' => $title, 'path' => $relativePath, 'url' => '?page=' . $relativePath ]; } } return $result; } private function performSearch($query) { $this->searchResults = []; $this->searchInDirectory($this->config['content_dir'], '', $query); } private function searchInDirectory($dir, $prefix, $query) { if (!is_dir($dir)) return; $items = scandir($dir); foreach ($items as $item) { if ($item[0] === '.') continue; $path = $dir . '/' . $item; $relativePath = $prefix ? $prefix . '/' . $item : $item; if (is_dir($path)) { $this->searchInDirectory($path, $relativePath, $query); } elseif (preg_match('/\.(md|php|html)$/', $item)) { $content = file_get_contents($path); if (stripos($content, $query) !== false || stripos($item, $query) !== false) { $title = ucfirst(pathinfo($item, PATHINFO_FILENAME)); $this->searchResults[] = [ 'title' => $title, 'path' => $relativePath, 'url' => '?page=' . $relativePath, 'snippet' => $this->createSnippet($content, $query) ]; } } } } private function createSnippet($content, $query) { $content = strip_tags($content); $pos = stripos($content, $query); if ($pos === false) return substr($content, 0, 100) . '...'; $start = max(0, $pos - 50); $snippet = substr($content, $start, 150); return '...' . $snippet . '...'; } public function getPage() { if (isset($_GET['search'])) { return $this->getSearchResults(); } // Check if guide is requested if (isset($_GET['guide'])) { return $this->getGuidePage(); } // Check if content directory is empty if ($this->isContentDirEmpty()) { return $this->getGuidePage(); } $page = $_GET['page'] ?? $this->config['default_page']; $page = preg_replace('/\.[^.]+$/', '', $page); $filePath = $this->config['content_dir'] . '/' . $page; $actualFilePath = null; if (file_exists($filePath . '.md')) { $actualFilePath = $filePath . '.md'; $result = $this->parseMarkdown(file_get_contents($actualFilePath)); } elseif (file_exists($filePath . '.php')) { $actualFilePath = $filePath . '.php'; $result = $this->parsePHP($actualFilePath); } elseif (file_exists($filePath . '.html')) { $actualFilePath = $filePath . '.html'; $result = $this->parseHTML(file_get_contents($actualFilePath)); } elseif (file_exists($filePath)) { $actualFilePath = $filePath; $extension = pathinfo($filePath, PATHINFO_EXTENSION); if ($extension === 'md') { $result = $this->parseMarkdown(file_get_contents($actualFilePath)); } elseif ($extension === 'php') { $result = $this->parsePHP($actualFilePath); } elseif ($extension === 'html') { $result = $this->parseHTML(file_get_contents($actualFilePath)); } } if (isset($result) && $actualFilePath) { $result['file_info'] = $this->getFileInfo($actualFilePath); return $result; } return $this->getError404(); } private function getFileInfo($filePath) { if (!file_exists($filePath)) { return null; } $stats = stat($filePath); $created = date('d-m-Y H:i', $stats['ctime']); $modified = date('d-m-Y H:i', $stats['mtime']); return [ 'created' => $created, 'modified' => $modified, 'size' => $this->formatFileSize($stats['size']) ]; } private function formatFileSize($bytes) { $units = ['B', 'KB', 'MB', 'GB']; $bytes = max($bytes, 0); $pow = floor(($bytes ? log($bytes) : 0) / log(1024)); $pow = min($pow, count($units) - 1); $bytes /= pow(1024, $pow); return round($bytes, 2) . ' ' . $units[$pow]; } private function getSearchResults() { $query = $_GET['search']; $content = '
No results found.
'; } else { $content .= 'Found ' . count($this->searchResults) . ' results:
'; foreach ($this->searchResults as $result) { $content .= '' . htmlspecialchars($result['path']) . '
'; $content .= '' . htmlspecialchars($result['snippet']) . '
'; $content .= '', $body); $body = '
' . $body . '
'; $body = preg_replace('/<\/p>/', '', $body); $body = preg_replace('/
( The page you are looking for does not exist.]*>(.*?)<\/h1>/i', $content, $matches)) {
return trim(strip_tags($matches[1]));
}
}
return null;
}
private function parsePHP($filePath) {
ob_start();
$title = 'Untitled';
include $filePath;
$content = ob_get_clean();
return [
'title' => $title,
'content' => $content
];
}
private function parseHTML($content) {
$title = 'Untitled';
if (preg_match('/
]*>(.*?)<\/h1>/i', $content, $matches)) {
$title = strip_tags($matches[1]);
}
return [
'title' => $title,
'content' => $content
];
}
private function isContentDirEmpty() {
$contentDir = $this->config['content_dir'];
if (!is_dir($contentDir)) {
return true;
}
$files = scandir($contentDir);
$files = array_diff($files, ['.', '..']);
return empty($files);
}
private function getGuidePage() {
$lang = $this->detectLanguage();
$guideFile = __DIR__ . '/../../guide/' . $lang . '.md';
if (!file_exists($guideFile)) {
$guideFile = __DIR__ . '/../../guide/en.md'; // Fallback to English
}
$content = file_get_contents($guideFile);
$result = $this->parseMarkdown($content);
// Set special title for guide
$result['title'] = 'Handleiding - CodePress CMS';
return $result;
}
private function detectLanguage() {
// Simple language detection based on browser Accept-Language header
$acceptLanguage = $_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? '';
if (strpos($acceptLanguage, 'nl') !== false) {
return 'nl';
}
return 'en'; // Default to English
}
private function getError404() {
return [
'title' => 'Page Not Found',
'content' => '
404 - Page Not Found
]*>(.*?)<\/h1>\s*<\/a>/', '
$1
', $headerContent);
}
$footerContent = file_get_contents($this->config['templates_dir'] . '/assets/footer.mustache');
if (!$hasContent) {
// Remove guide link from footer when no content
$footerContent = preg_replace('/\s*\|\s*]*>Handleiding<\/a><\/span>/', '', $footerContent);
}
// Determine content type and load appropriate template
$contentType = $this->getContentType($page);
$contentTemplateFile = $this->config['templates_dir'] . '/' . $contentType . '_content.mustache';
$contentTemplate = file_exists($contentTemplateFile) ? file_get_contents($contentTemplateFile) : '