perf : getAll() sans contenu, search_index + featured, excerpts via plain (v1.6.14)
- 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 <noreply@anthropic.com>
This commit is contained in:
@@ -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é
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
1.6.13
|
||||
1.6.14
|
||||
|
||||
+48
-22
@@ -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;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
<?php
|
||||
require_once BASE_PATH . '/src/Parsedown.php';
|
||||
$Parsedown = new Parsedown();
|
||||
|
||||
$_apName = $authorRow['display_name'] ?? '';
|
||||
$_apSlug = $authorRow['profile_slug'] ?? '';
|
||||
@@ -19,8 +17,7 @@ ob_start();
|
||||
<?php else: ?>
|
||||
<div class="post-grid">
|
||||
<?php foreach ($posts as $post):
|
||||
$html = $Parsedown->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']);
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
<?php
|
||||
require_once BASE_PATH . '/src/Parsedown.php';
|
||||
$Parsedown = new Parsedown();
|
||||
|
||||
ob_start();
|
||||
|
||||
@@ -36,8 +34,7 @@ $_initials = mb_strtoupper(mb_substr($_apName, 0, 1, 'UTF-8'), 'UTF-8');
|
||||
<?php else: ?>
|
||||
<div class="post-grid">
|
||||
<?php foreach (array_slice($authorArticles, 0, 6) as $post):
|
||||
$html = $Parsedown->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']);
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user