diff --git a/index.php b/index.php index 4965702..f9cd2a7 100644 --- a/index.php +++ b/index.php @@ -219,6 +219,9 @@ class CodePressCMS { $body = preg_replace('/href="\/blog\/([^"]+)"/', 'href="?page=blog/$1"', $body); $body = preg_replace('/href="\/([^"]+)"/', 'href="?page=$1"', $body); + // Auto-link page titles to existing content pages + $body = $this->autoLinkPageTitles($body); + $body = preg_replace('/\n\n/', '

', $body); $body = '

' . $body . '

'; $body = preg_replace('/

<\/p>/', '', $body); @@ -231,6 +234,88 @@ class CodePressCMS { ]; } + private function autoLinkPageTitles($content) { + // Get all available pages with their titles + $pages = $this->getAllPageTitles(); + + foreach ($pages as $pagePath => $pageTitle) { + // Create a pattern that matches the exact page title (case-insensitive) + $pattern = '/\b' . preg_quote($pageTitle, '/') . '\b/i'; + + // Replace with link, but avoid linking inside existing links or headings + $replacement = function($matches) use ($pageTitle, $pagePath) { + // Check if we're inside an HTML tag or link + $before = substr($matches[0], 0, 50); + if (preg_match('/<[^>]*$/', $before) || preg_match('/href=/', $before)) { + return $matches[0]; // Don't link inside HTML tags + } + + return '' . $matches[0] . ''; + }; + + $content = preg_replace_callback($pattern, $replacement, $content); + } + + return $content; + } + + private function getAllPageTitles() { + $pages = []; + $this->scanForPageTitles($this->config['content_dir'], '', $pages); + return $pages; + } + + private function scanForPageTitles($dir, $prefix, &$pages) { + if (!is_dir($dir)) return; + + $items = scandir($dir); + sort($items); + + foreach ($items as $item) { + if ($item[0] === '.') continue; + + $path = $dir . '/' . $item; + $relativePath = $prefix ? $prefix . '/' . $item : $item; + + if (is_dir($path)) { + $this->scanForPageTitles($path, $relativePath, $pages); + } elseif (preg_match('/\.(md|php|html)$/', $item)) { + $title = $this->extractPageTitle($path); + if ($title && !empty(trim($title))) { + $pagePath = preg_replace('/\.[^.]+$/', '', $relativePath); + $pages[$pagePath] = $title; + } + } + } + } + + private function extractPageTitle($filePath) { + $content = file_get_contents($filePath); + $extension = pathinfo($filePath, PATHINFO_EXTENSION); + + if ($extension === 'md') { + // Extract first H1 from Markdown + if (preg_match('/^#\s+(.+)$/m', $content, $matches)) { + return trim($matches[1]); + } + } elseif ($extension === 'php') { + // Extract title from PHP file + if (preg_match('/\$title\s*=\s*["\']([^"\']+)["\']/', $content, $matches)) { + return trim($matches[1]); + } + } elseif ($extension === 'html') { + // Extract title from HTML file + if (preg_match('/(.*?)<\/title>/i', $content, $matches)) { + return trim(strip_tags($matches[1])); + } + if (preg_match('/<h1[^>]*>(.*?)<\/h1>/i', $content, $matches)) { + return trim(strip_tags($matches[1])); + } + } + + return null; + } + private function parsePHP($filePath) { ob_start(); $title = 'Untitled'; diff --git a/templates/layout.html b/templates/layout.html index cc23028..5e99457 100644 --- a/templates/layout.html +++ b/templates/layout.html @@ -162,6 +162,17 @@ .site-info a:hover { text-decoration: underline; } + .auto-link { + color: #0d6efd; + text-decoration: none; + border-bottom: 1px dotted #0d6efd; + font-weight: 500; + } + .auto-link:hover { + color: #0a58ca; + text-decoration: none; + border-bottom-style: solid; + } .search-form { max-width: 300px; }