From 347e4be0b7f387b2b2afa8d9628fb90705918881 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9drix?= Date: Fri, 15 May 2026 23:50:58 +0200 Subject: [PATCH] perf : getAll() sans contenu, search_index + featured, excerpts via plain (v1.6.14) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - loadArticle($dir, false) dans loadAll() — meta.json seulement, pas d'index.md - loadAll() enrichit les articles avec plain depuis search_index (1 lecture JSON) - rebuildSearchIndex() lit index.md directement + ajoute featured au schéma - getSearchIndex() rebuilde automatiquement si featured absent - post_list, author_articles, author_profile : excerpts via plain, plus de Parsedown - Ferme #24 Co-Authored-By: Claude Sonnet 4.6 --- CHANGELOG.md | 9 +++++ public/version.txt | 2 +- src/ArticleManager.php | 70 ++++++++++++++++++++++++----------- templates/author_articles.php | 5 +-- templates/author_profile.php | 5 +-- templates/post_list.php | 8 +++- 6 files changed, 67 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ebd6242..f5e2cb1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,15 @@ Format : [Keep a Changelog](https://keepachangelog.com/fr/1.0.0/) — versionnag --- +## [1.6.14] - 2026-05-15 + +### Modifié +- Perf : `getAll()` ne charge plus le contenu Markdown — `loadArticle()` reçoit `$withContent = false` dans `loadAll()`, seul `getByUuid()` lit encore `index.md` (#24) +- Perf : `search_index.json` enrichi du champ `featured` ; `rebuildSearchIndex()` lit `index.md` directement (indépendant du cache article) +- Perf : excerpts dans `post_list`, `author_articles`, `author_profile` proviennent du champ `plain` pré-calculé — plus de passage par Parsedown (#24) + +--- + ## [1.6.13] - 2026-05-15 ### Ajouté diff --git a/public/version.txt b/public/version.txt index d4ca915..5577648 100644 --- a/public/version.txt +++ b/public/version.txt @@ -1 +1 @@ -1.6.13 +1.6.14 diff --git a/src/ArticleManager.php b/src/ArticleManager.php index 36a2f4b..82b8ae7 100644 --- a/src/ArticleManager.php +++ b/src/ArticleManager.php @@ -44,7 +44,7 @@ class ArticleManager continue; } - $article = $this->loadArticle($dir); + $article = $this->loadArticle($dir, false); if (!$article) { continue; } @@ -53,6 +53,19 @@ class ArticleManager usort($articles, static fn ($a, $b) => strcmp($b['published_at'] ?? '', $a['published_at'] ?? '')); + // Enrichir avec le plain text pré-calculé (pour les excerpts sans charger index.md) + $siPath = $this->dataDir . '/search_index.json'; + if (file_exists($siPath)) { + $si = json_decode((string)file_get_contents($siPath), true); + if (is_array($si)) { + $plainByUuid = array_column($si, 'plain', 'uuid'); + foreach ($articles as &$a) { + $a['plain'] = $plainByUuid[$a['uuid']] ?? ''; + } + unset($a); + } + } + return $articles; } @@ -944,19 +957,25 @@ class ArticleManager { $index = []; foreach ($this->getAll() as $article) { + $uuid = $article['uuid'] ?? ''; + $contentPath = $this->dataDir . '/' . $uuid . '/index.md'; + $content = $uuid !== '' && file_exists($contentPath) + ? (string)file_get_contents($contentPath) + : ''; $index[] = [ - 'uuid' => $article['uuid'], + 'uuid' => $uuid, 'slug' => $article['slug'] ?? '', 'title' => $article['title'] ?? '', 'category' => $article['category'] ?? '', 'author' => $article['author'] ?? '', 'cover' => $article['cover'] ?? '', + 'featured' => (bool)($article['featured'] ?? false), 'published' => $article['published'], 'published_at' => $article['published_at'] ?? '', 'created_at' => $article['created_at'] ?? '', 'updated_at' => $article['updated_at'] ?? '', 'tags' => $article['tags'] ?? [], - 'plain' => $this->stripForIndex($article['content'] ?? ''), + 'plain' => $this->stripForIndex($content), ]; } file_put_contents( @@ -1027,8 +1046,8 @@ class ArticleManager if (!is_array($data) || empty($data)) { return null; } - // Rebuild automatique si le format est obsolète (champs cover/created_at absents) - if (!array_key_exists('cover', $data[0])) { + // Rebuild automatique si le format est obsolète (champs manquants) + if (!array_key_exists('cover', $data[0]) || !array_key_exists('featured', $data[0])) { $this->rebuildSearchIndex(); return $this->searchIndexCache; } @@ -1200,21 +1219,22 @@ class ArticleManager }; } - private function loadArticle(string $dir): ?array + private function loadArticle(string $dir, bool $withContent = true): ?array { - $metaPath = $dir . '/meta.json'; + $metaPath = $dir . '/meta.json'; if (!file_exists($metaPath)) { return null; } - $uuid = basename($dir); - $cachePath = $this->articleCachePath($uuid); - // Utiliser le cache si plus récent que meta.json ET index.md - $contentMtime = file_exists($dir . '/index.md') ? filemtime($dir . '/index.md') : 0; - if (file_exists($cachePath) && filemtime($cachePath) >= filemtime($metaPath) && filemtime($cachePath) >= $contentMtime) { - $cached = json_decode((string) file_get_contents($cachePath), true); - if (is_array($cached) && !empty($cached['uuid'])) { - return $cached; + if ($withContent) { + $uuid = basename($dir); + $cachePath = $this->articleCachePath($uuid); + $contentMtime = file_exists($dir . '/index.md') ? filemtime($dir . '/index.md') : 0; + if (file_exists($cachePath) && filemtime($cachePath) >= filemtime($metaPath) && filemtime($cachePath) >= $contentMtime) { + $cached = json_decode((string) file_get_contents($cachePath), true); + if (is_array($cached) && !empty($cached['uuid'])) { + return $cached; + } } } @@ -1227,8 +1247,11 @@ class ArticleManager return null; } - $contentPath = $dir . '/index.md'; - $meta['content'] = file_exists($contentPath) ? (string)file_get_contents($contentPath) : ''; + if ($withContent) { + $contentPath = $dir . '/index.md'; + $meta['content'] = file_exists($contentPath) ? (string)file_get_contents($contentPath) : ''; + } + $meta['published'] = (bool)($meta['published'] ?? false); $meta['featured'] = (bool)($meta['featured'] ?? false); $meta['files_meta'] = $meta['files_meta'] ?? []; @@ -1242,12 +1265,15 @@ class ArticleManager } } - // Écrire le cache - $cacheDir = dirname($cachePath); - if (!is_dir($cacheDir)) { - mkdir($cacheDir, 0755, true); + if ($withContent) { + $uuid = $meta['uuid']; + $cachePath = $this->articleCachePath($uuid); + $cacheDir = dirname($cachePath); + if (!is_dir($cacheDir)) { + mkdir($cacheDir, 0755, true); + } + file_put_contents($cachePath, json_encode($meta, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)); } - file_put_contents($cachePath, json_encode($meta, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)); return $meta; } diff --git a/templates/author_articles.php b/templates/author_articles.php index 9f8d530..ead17ad 100644 --- a/templates/author_articles.php +++ b/templates/author_articles.php @@ -1,6 +1,4 @@
text($post['content']); - $preview = mb_strimwidth(strip_tags($html), 0, 120, '…'); + $preview = mb_strimwidth($post['plain'] ?? '', 0, 120, '…'); $category = trim((string)($post['category'] ?? '')); $gradient = coverGradient($category !== '' ? $category : $post['uuid'], $allCats ?? []); $postUrl = '/post/' . rawurlencode($post['slug']); diff --git a/templates/author_profile.php b/templates/author_profile.php index b83c931..21eafb0 100644 --- a/templates/author_profile.php +++ b/templates/author_profile.php @@ -1,6 +1,4 @@
text($post['content']); - $preview = mb_strimwidth(strip_tags($html), 0, 120, '…'); + $preview = mb_strimwidth($post['plain'] ?? '', 0, 120, '…'); $category = trim((string)($post['category'] ?? '')); $gradient = coverGradient($category !== '' ? $category : $post['uuid'], $allCats ?? []); $postUrl = '/post/' . rawurlencode($post['slug']); diff --git a/templates/post_list.php b/templates/post_list.php index ab71c44..b6a47c4 100644 --- a/templates/post_list.php +++ b/templates/post_list.php @@ -17,7 +17,13 @@ function _cardCoverStyle(array $post, array $allCats): string function _cardExcerpt(array $post, \Parsedown $pd, int $len = 120): string { - return mb_strimwidth(strip_tags($pd->text($post['content'])), 0, $len, '…'); + if (($post['plain'] ?? '') !== '') { + return mb_strimwidth($post['plain'], 0, $len, '…'); + } + if (($post['content'] ?? '') !== '') { + return mb_strimwidth(strip_tags($pd->text($post['content'])), 0, $len, '…'); + } + return ''; } function _renderCard(array $post, array $privateCats, array $allCats, \Parsedown $pd): void