feat: smart 404 redirige vers article le plus proche via moteur de recherche

This commit is contained in:
Cedric Abonnel
2026-05-12 22:47:37 +02:00
parent f273c3fa6a
commit 7de1cbaed8
2 changed files with 56 additions and 1 deletions
+3
View File
@@ -59,3 +59,6 @@ RewriteRule ^sitemap\.xml$ /sitemap.php [L]
# Ajoute .php si le fichier correspondant existe
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI}.php -f
RewriteRule ^(.+?)/?$ /$1.php [L,QSA]
# 404 intelligent : redirige vers l'article le plus proche
ErrorDocument 404 /index.php?action=not_found
+53 -1
View File
@@ -22,10 +22,38 @@ $action = $_GET['action'] ?? 'list';
$uuid = $_GET['uuid'] ?? '';
$slug = $_GET['slug'] ?? '';
$_noindexActions = ['create', 'edit', 'admin', 'categories', 'diff', 'add_files', 'import_image', 'import_image_step2', 'sources', 'profile', 'delete_file', 'delete_external_link', 'rename_category', 'delete_category', 'toggle_private_category', 'admin_save_site'];
$_noindexActions = ['create', 'edit', 'admin', 'categories', 'diff', 'add_files', 'import_image', 'import_image_step2', 'sources', 'profile', 'delete_file', 'delete_external_link', 'rename_category', 'delete_category', 'toggle_private_category', 'admin_save_site', 'not_found'];
$metaRobots = in_array($action, $_noindexActions, true) ? 'noindex, nofollow' : null;
unset($_noindexActions);
// ─── Recherche de l'article le plus proche et redirection 301 ────────────────
function searchAndRedirect(string $rawPath, ArticleManager $articles): void
{
require_once BASE_PATH . '/src/SearchEngine.php';
$query = (string)preg_replace('/\s{2,}/', ' ', trim(
(string)preg_replace('/[^a-zA-ZÀ-ÿ0-9\s]/u', ' ', str_replace(['-', '_', '/'], ' ', $rawPath))
));
if ($query === '') {
return;
}
$privateCats = $articles->getPrivateCategories();
$pool = array_values(array_filter(
$articles->getAll(true),
static function (array $a) use ($privateCats): bool {
if (strtotime((string)($a['published_at'] ?? '')) > time()) {
return false;
}
$cat = trim($a['category'] ?? '');
return $cat === '' || !in_array($cat, $privateCats, true);
}
));
$results = (new SearchEngine())->search($query, $pool);
if (!empty($results)) {
header('Location: /post/' . rawurlencode($results[0]['article']['slug'] ?? ''), true, 301);
exit;
}
}
// ─── Extraction de métadonnées depuis une URL ────────────────────────────────
function fetchUrlMeta(string $url): array
{
@@ -472,6 +500,7 @@ switch ($action) {
case 'view':
$article = $slug !== '' ? $articles->getBySlug($slug) : null;
if (!$article) {
searchAndRedirect($slug, $articles);
http_response_code(404);
echo 'Article introuvable.';
exit;
@@ -1826,6 +1855,29 @@ switch ($action) {
include BASE_PATH . '/templates/search.php';
break;
case 'not_found':
$notFoundPath = trim(
(string)(parse_url($_SERVER['REDIRECT_URL'] ?? $_SERVER['REQUEST_URI'] ?? '', PHP_URL_PATH) ?? ''),
'/'
);
if ($notFoundPath !== '') {
searchAndRedirect($notFoundPath, $articles);
}
http_response_code(404);
ob_start();
?>
<div class="container py-5 text-center">
<h1 class="h2 mb-3">Page introuvable</h1>
<p class="text-muted mb-4">Cette adresse ne correspond à aucun article.<br>Vous avez peut-être suivi un ancien lien.</p>
<a href="/" class="btn btn-primary">← Retour à l'accueil</a>
</div>
<?php
$content = ob_get_clean();
$title = '404 — ' . siteTitle();
$metaRobots = 'noindex, nofollow';
include BASE_PATH . '/templates/layout.php';
break;
case 'list':
default:
$privateCats = $articles->getPrivateCategories();