🔍 Optimisations Pagefind : Normalisation et Indexation

📋 Résumé des changements

1. Normalisation automatique des tags via GitHub Actions

Fichier : .github/workflows/jekyll.yml

Modification :

  • Ajout d’une étape “Normalize tags for better filtering” après l’harmonisation des tags
  • Exécution automatique du script scripts/normalize_tags.rb --apply à chaque build

Impact :

  • ✅ Consolidation automatique des tags (IA, AI, Intelligence Artificielle → IA)
  • ✅ Cohérence linguistique (automatisation vs automation)
  • ✅ Pas besoin d’intervention manuelle

2. Optimisation de l’indexation Pagefind

Objectif : S’assurer que seul le contenu pertinent est indexé (titre + contenu de l’article) et exclure les éléments de navigation/UI.

Fichiers modifiés :

_layouts/post.html - Ajout de data-pagefind-ignore sur :

  • .post-breadcrumb - Navigation fil d’Ariane
  • .reading-progress - Barre de progression de lecture
  • .toc-perplexity-block - Bloc publicitaire Perplexity
  • .table-of-contents-inline - Table des matières
  • ✅ Schemas SEO (faq-schema.html, howto-schema.html)

_includes/series-navigation.html :

  • ✅ Ajout de data-pagefind-ignore sur .series-navigation

_includes/smart-internal-links.html :

  • ✅ Ajout de data-pagefind-ignore sur .smart-internal-links

_includes/post-related-resources.html :

  • ✅ Ajout de data-pagefind-ignore sur .related-resources

🎯 Ce qui est indexé maintenant

✅ Contenu indexé (recherchable)

  • Titre de l’article (<h1 class="post-title">)
  • Contenu principal (`<div class="page-header">

    🔧 Guide d’intégration des améliorations de filtres

</div>

🔧 Guide d’intégration des améliorations de filtres

1. Ajouter les nouveaux fichiers à la page blog

Dans pages/blog.html

Ajouter après la section de recherche (vers la ligne 100) :

<!-- Mode de filtrage ET/OU -->
<!-- Toggle pour choisir le mode de filtrage (ET / OU) -->
<div class="filter-mode-selector" id="filter-mode-selector" style="display: none;">
    <label class="filter-mode-label">
        <input type="radio" name="filter-mode" value="AND" checked>
        <span class="mode-text">
            <i class="fas fa-check-double"></i> ET (tous les tags)
        </span>
    </label>
    <label class="filter-mode-label">
        <input type="radio" name="filter-mode" value="OR">
        <span class="mode-text">
            <i class="fas fa-list"></i> OU (au moins un tag)
        </span>
    </label>
</div>

<style>
.filter-mode-selector {
    display: flex;
    gap: 1rem;
    margin: 1rem 0;
    padding: 0.75rem;
    background: var(--bg-secondary, #f8f9fa);
    border-radius: 8px;
    align-items: center;
}

.filter-mode-label {
    display: flex;
    align-items: center;
    cursor: pointer;
    padding: 0.5rem 1rem;
    border-radius: 6px;
    transition: all 0.2s ease;
    background: white;
    border: 2px solid transparent;
}

.filter-mode-label:hover {
    background: var(--primary-light, #e3f2fd);
}

.filter-mode-label input[type="radio"] {
    margin-right: 0.5rem;
}

.filter-mode-label input[type="radio"]:checked + .mode-text {
    font-weight: 600;
    color: var(--primary-color, #1976d2);
}

.filter-mode-label:has(input:checked) {
    border-color: var(--primary-color, #1976d2);
    background: var(--primary-light, #e3f2fd);
}

.mode-text {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}
</style>


<!-- Container pour les suggestions de tags -->
<div id="tag-suggestions"></div>

Dans _layouts/default.html ou dans pages/blog.html

Ajouter les nouveaux scripts avant la fermeture du </body> :

<!-- Améliorations des filtres (uniquement sur la page blog) -->

2. Modifier blog-search-pagefind.js

Ajouter le support du mode ET/OU

Dans la fonction performPagefindSearch (ligne 58), modifier :

// AVANT
if (activeFilters.tags.length > 0) {
    pagefindFilters.tags = activeFilters.tags;
}

// APRÈS
if (activeFilters.tags.length > 0) {
    const filterMode = window.filterEnhancements?.getFilterMode() || 'OR';

    if (filterMode === 'AND') {
        // Mode ET : tous les tags doivent être présents
        pagefindFilters.tags = activeFilters.tags;
    } else {
        // Mode OU : au moins un tag doit être présent
        pagefindFilters.tags = activeFilters.tags;
    }
}

Ajouter les suggestions après le filtrage

Dans la fonction toggleTagFilter (ligne 372), après updateActiveFiltersUI() :

// Mettre à jour les suggestions
if (window.filterEnhancements?.updateTagSuggestions) {
    window.filterEnhancements.updateTagSuggestions(activeFilters.tags);
}

Ajouter le tri par pertinence

Dans la fonction displaySearchResults (ligne 132), avant updatePagination() :

// Trier les résultats par pertinence
if (window.filterEnhancements?.sortResultsByRelevance) {
    window.filterEnhancements.sortResultsByRelevance(
        postsContainer,
        activeFilters.tags,
        query
    );
}

3. Exposer les fonctions nécessaires

À la fin de blog-search-pagefind.js, exposer les fonctions globalement :

// Exposer les fonctions pour les améliorations
window.toggleTagFilter = toggleTagFilter;
window.activeFilters = activeFilters;

4. Test des améliorations

Test du script de normalisation

# 1. Prévisualiser les changements
ruby scripts/normalize_tags.rb

# Vous devriez voir quelque chose comme :
# 📄 _posts/2025/06/2025-06-15-vibe-coding.md
#    Avant: IA, AI, développement
#    Après: IA, développement

# 2. Si tout est correct, appliquer
ruby scripts/normalize_tags.rb --apply

Test des suggestions de tags

  1. Ouvrir /blog/ dans votre navigateur
  2. Cliquer sur un tag (ex: #IA)
  3. Vérifier que des suggestions apparaissent en haut
  4. Cliquer sur une suggestion → le tag doit s’ajouter aux filtres actifs

Test du mode ET/OU

  1. Cliquer sur plusieurs tags
  2. Observer les résultats en mode OU (par défaut)
  3. Basculer en mode ET
  4. Observer que seuls les articles avec TOUS les tags s’affichent

Test du tri par pertinence

  1. Faire une recherche avec plusieurs tags
  2. Les articles les plus pertinents doivent apparaître en premier
  3. Les articles featured doivent avoir un bonus de pertinence

5. Styles à personnaliser (optionnel)

Si vous voulez adapter les couleurs à votre charte graphique, modifier dans filter-enhancements.css :

/* Couleur principale du gradient */
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
/* → Remplacer par vos couleurs */

/* Couleur des tags actifs */
.tag-pill-large.active-filter {
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}

6. Déploiement

Commit des changements

git add scripts/ assets/ _includes/ FILTER_IMPROVEMENTS.md INTEGRATION_EXAMPLE.md
git commit -m "feat: Ajouter améliorations des filtres Pagefind

- Script de normalisation des tags
- Suggestions de tags liés basées sur la co-occurrence
- Mode de filtrage ET/OU
- Tri des résultats par pertinence
- Documentation complète

Impact attendu:
- Consolidation des tags (IA: 73→91 articles)
- Meilleure découvrabilité du contenu
- Expérience de filtrage plus intuitive"

git push

Intégration progressive

Si vous préférez tester progressivement :

Étape 1 : Normalisation seule

ruby scripts/normalize_tags.rb --apply
git add _posts scripts/normalize_tags.rb
git commit -m "chore: Normaliser les tags du blog"
git push

Étape 2 : Attendre le rebuild et tester

Étape 3 : Ajouter les améliorations JS/CSS

git add assets/ _includes/
git commit -m "feat: Ajouter suggestions et tri des filtres"
git push

7. Vérifications post-déploiement

Checklist :

  • Les tags sont normalisés dans les articles
  • L’index Pagefind a été régénéré (vérifier les logs CI/CD)
  • La recherche fonctionne toujours
  • Les suggestions de tags apparaissent
  • Le toggle ET/OU fonctionne
  • Le tri par pertinence est actif
  • Les styles sont corrects sur mobile et desktop
  • Pas d’erreurs dans la console du navigateur

8. Rollback si nécessaire

Si quelque chose ne fonctionne pas :

# Revenir au commit précédent
git reset --hard HEAD~1

# Ou revenir à un commit spécifique
git reset --hard <commit-hash>

# Push force (attention, à utiliser avec précaution)
git push --force

9. Support et debugging

Console du navigateur

Les scripts affichent des logs utiles :

console.log('🏷️  20 tags configurés comme filtres')
console.log('✨ Améliorations des filtres chargées')
console.log('🔍 Recherche Pagefind: "MCP"')

Vérifier que les filtres sont bien indexés

Après le build, inspecter un article HTML généré :

cat _site/articles/2025/06/15/vibe-coding-prompt-driven-development.html | grep data-pagefind-filter

Vous devriez voir :

data-pagefind-filter="tags:IA"
data-pagefind-filter="tags:développement"
data-pagefind-filter="tags:prompt engineering"

10. Optimisations futures

Script de validation pre-commit

Créer .git/hooks/pre-commit :

#!/bin/bash
ruby scripts/normalize_tags.rb --check
if [ $? -ne 0 ]; then
    echo "❌ Des tags non normalisés ont été détectés"
    echo "Exécutez: ruby scripts/normalize_tags.rb --apply"
    exit 1
fi

Analytics

Tracker l’usage des filtres avec Google Analytics :

// Dans blog-search-pagefind.js
function toggleTagFilter(tag) {
    // ... code existant ...

    // Track dans GA4
    if (window.gtag) {
        gtag('event', 'filter_tag', {
            'tag_name': tag,
            'filter_action': activeFilters.tags.includes(tag) ? 'add' : 'remove'
        });
    }
}

🎉 C’est terminé !

Votre système de filtres est maintenant optimisé pour offrir une meilleure expérience utilisateur.

` dans <article class="post-content">)

  • Métadonnées :
    • data-pagefind-meta="title" - pour affichage dans les résultats
    • data-pagefind-meta="date"
    • data-pagefind-meta="author"
    • data-pagefind-meta="excerpt"
  • Filtres :
    • data-pagefind-filter="tags" - chaque tag individuellement
    • data-pagefind-filter="category" - chaque catégorie individuellement
    • data-pagefind-filter="lang" - langue de l’article

❌ Contenu exclu (non-recherchable)

  • Breadcrumb / fil d’Ariane
  • Barre de progression de lecture
  • Bloc publicitaire Perplexity
  • Table des matières (TOC)
  • Métadonnées (date, auteur, temps de lecture)
  • Technologies badges
  • Navigation de série
  • Articles liés / maillage interne
  • Ressources et services associés
  • Boutons de partage social
  • Schemas JSON-LD (SEO)

📊 Structure d’indexation

<article data-pagefind-body>
  <!-- INDEXÉ -->
  <header>
    <div data-pagefind-ignore>Breadcrumb</div>
    <h1>Titre de l'article</h1> <!-- ✅ Indexé -->
    <div data-pagefind-ignore>Meta (date, auteur)</div>
  </header>

  <!-- INDEXÉ -->
  <div>
    <div data-pagefind-ignore>Navigation série</div>

    <article class="post-content">
      <div data-pagefind-ignore>Bloc Perplexity</div>
      <div data-pagefind-ignore>TOC</div>

      <div class="page-header">
    <div class="container">
        <h1>🔧 Guide d’intégration des améliorations de filtres</h1>
        
        <nav class="breadcrumb">
            <a href="/">Home</a>
            
            
                
                    <span>🔧 Guide d’intégration des améliorations de filtres</span>
                
            
        </nav>
    </div>
</div>

<div class="container page-content">
    <div class="main-content">
        <h1 id="-guide-dintégration-des-améliorations-de-filtres">🔧 Guide d’intégration des améliorations de filtres</h1>

<h2 id="1-ajouter-les-nouveaux-fichiers-à-la-page-blog">1. Ajouter les nouveaux fichiers à la page blog</h2>

<h3 id="dans-pagesbloghtml">Dans <code class="language-plaintext highlighter-rouge">pages/blog.html</code></h3>

<p>Ajouter après la section de recherche (vers la ligne 100) :</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">&lt;!-- Mode de filtrage ET/OU --&gt;</span>
<span class="c">&lt;!-- Toggle pour choisir le mode de filtrage (ET / OU) --&gt;</span>
<span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"filter-mode-selector"</span> <span class="na">id=</span><span class="s">"filter-mode-selector"</span> <span class="na">style=</span><span class="s">"display: none;"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;label</span> <span class="na">class=</span><span class="s">"filter-mode-label"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"radio"</span> <span class="na">name=</span><span class="s">"filter-mode"</span> <span class="na">value=</span><span class="s">"AND"</span> <span class="na">checked</span><span class="nt">&gt;</span>
        <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"mode-text"</span><span class="nt">&gt;</span>
            <span class="nt">&lt;i</span> <span class="na">class=</span><span class="s">"fas fa-check-double"</span><span class="nt">&gt;&lt;/i&gt;</span> ET (tous les tags)
        <span class="nt">&lt;/span&gt;</span>
    <span class="nt">&lt;/label&gt;</span>
    <span class="nt">&lt;label</span> <span class="na">class=</span><span class="s">"filter-mode-label"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"radio"</span> <span class="na">name=</span><span class="s">"filter-mode"</span> <span class="na">value=</span><span class="s">"OR"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">"mode-text"</span><span class="nt">&gt;</span>
            <span class="nt">&lt;i</span> <span class="na">class=</span><span class="s">"fas fa-list"</span><span class="nt">&gt;&lt;/i&gt;</span> OU (au moins un tag)
        <span class="nt">&lt;/span&gt;</span>
    <span class="nt">&lt;/label&gt;</span>
<span class="nt">&lt;/div&gt;</span>

<span class="nt">&lt;style&gt;</span>
<span class="nc">.filter-mode-selector</span> <span class="p">{</span>
    <span class="nl">display</span><span class="p">:</span> <span class="n">flex</span><span class="p">;</span>
    <span class="py">gap</span><span class="p">:</span> <span class="m">1rem</span><span class="p">;</span>
    <span class="nl">margin</span><span class="p">:</span> <span class="m">1rem</span> <span class="m">0</span><span class="p">;</span>
    <span class="nl">padding</span><span class="p">:</span> <span class="m">0.75rem</span><span class="p">;</span>
    <span class="nl">background</span><span class="p">:</span> <span class="n">var</span><span class="p">(</span><span class="n">--bg-secondary</span><span class="p">,</span> <span class="m">#f8f9fa</span><span class="p">);</span>
    <span class="nl">border-radius</span><span class="p">:</span> <span class="m">8px</span><span class="p">;</span>
    <span class="nl">align-items</span><span class="p">:</span> <span class="nb">center</span><span class="p">;</span>
<span class="p">}</span>

<span class="nc">.filter-mode-label</span> <span class="p">{</span>
    <span class="nl">display</span><span class="p">:</span> <span class="n">flex</span><span class="p">;</span>
    <span class="nl">align-items</span><span class="p">:</span> <span class="nb">center</span><span class="p">;</span>
    <span class="nl">cursor</span><span class="p">:</span> <span class="nb">pointer</span><span class="p">;</span>
    <span class="nl">padding</span><span class="p">:</span> <span class="m">0.5rem</span> <span class="m">1rem</span><span class="p">;</span>
    <span class="nl">border-radius</span><span class="p">:</span> <span class="m">6px</span><span class="p">;</span>
    <span class="nl">transition</span><span class="p">:</span> <span class="n">all</span> <span class="m">0.2s</span> <span class="n">ease</span><span class="p">;</span>
    <span class="nl">background</span><span class="p">:</span> <span class="no">white</span><span class="p">;</span>
    <span class="nl">border</span><span class="p">:</span> <span class="m">2px</span> <span class="nb">solid</span> <span class="nb">transparent</span><span class="p">;</span>
<span class="p">}</span>

<span class="nc">.filter-mode-label</span><span class="nd">:hover</span> <span class="p">{</span>
    <span class="nl">background</span><span class="p">:</span> <span class="n">var</span><span class="p">(</span><span class="n">--primary-light</span><span class="p">,</span> <span class="m">#e3f2fd</span><span class="p">);</span>
<span class="p">}</span>

<span class="nc">.filter-mode-label</span> <span class="nt">input</span><span class="o">[</span><span class="nt">type</span><span class="o">=</span><span class="s1">"radio"</span><span class="o">]</span> <span class="p">{</span>
    <span class="nl">margin-right</span><span class="p">:</span> <span class="m">0.5rem</span><span class="p">;</span>
<span class="p">}</span>

<span class="nc">.filter-mode-label</span> <span class="nt">input</span><span class="o">[</span><span class="nt">type</span><span class="o">=</span><span class="s1">"radio"</span><span class="o">]</span><span class="nd">:checked</span> <span class="o">+</span> <span class="nc">.mode-text</span> <span class="p">{</span>
    <span class="nl">font-weight</span><span class="p">:</span> <span class="m">600</span><span class="p">;</span>
    <span class="nl">color</span><span class="p">:</span> <span class="n">var</span><span class="p">(</span><span class="n">--primary-color</span><span class="p">,</span> <span class="m">#1976d2</span><span class="p">);</span>
<span class="p">}</span>

<span class="nc">.filter-mode-label</span><span class="nd">:has</span><span class="o">(</span><span class="nt">input</span><span class="nd">:checked</span><span class="o">)</span> <span class="p">{</span>
    <span class="nl">border-color</span><span class="p">:</span> <span class="n">var</span><span class="p">(</span><span class="n">--primary-color</span><span class="p">,</span> <span class="m">#1976d2</span><span class="p">);</span>
    <span class="nl">background</span><span class="p">:</span> <span class="n">var</span><span class="p">(</span><span class="n">--primary-light</span><span class="p">,</span> <span class="m">#e3f2fd</span><span class="p">);</span>
<span class="p">}</span>

<span class="nc">.mode-text</span> <span class="p">{</span>
    <span class="nl">display</span><span class="p">:</span> <span class="n">flex</span><span class="p">;</span>
    <span class="nl">align-items</span><span class="p">:</span> <span class="nb">center</span><span class="p">;</span>
    <span class="py">gap</span><span class="p">:</span> <span class="m">0.5rem</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">&lt;/style&gt;</span>


<span class="c">&lt;!-- Container pour les suggestions de tags --&gt;</span>
<span class="nt">&lt;div</span> <span class="na">id=</span><span class="s">"tag-suggestions"</span><span class="nt">&gt;&lt;/div&gt;</span>
</code></pre></div></div>

<h3 id="dans-_layoutsdefaulthtml-ou-dans-pagesbloghtml">Dans <code class="language-plaintext highlighter-rouge">_layouts/default.html</code> ou dans <code class="language-plaintext highlighter-rouge">pages/blog.html</code></h3>

<p>Ajouter les nouveaux scripts avant la fermeture du <code class="language-plaintext highlighter-rouge">&lt;/body&gt;</code> :</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">&lt;!-- Améliorations des filtres (uniquement sur la page blog) --&gt;</span>

</code></pre></div></div>

<h2 id="2-modifier-blog-search-pagefindjs">2. Modifier <code class="language-plaintext highlighter-rouge">blog-search-pagefind.js</code></h2>

<h3 id="ajouter-le-support-du-mode-etou">Ajouter le support du mode ET/OU</h3>

<p>Dans la fonction <code class="language-plaintext highlighter-rouge">performPagefindSearch</code> (ligne 58), modifier :</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// AVANT</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">activeFilters</span><span class="p">.</span><span class="nx">tags</span><span class="p">.</span><span class="nx">length</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">pagefindFilters</span><span class="p">.</span><span class="nx">tags</span> <span class="o">=</span> <span class="nx">activeFilters</span><span class="p">.</span><span class="nx">tags</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1">// APRÈS</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">activeFilters</span><span class="p">.</span><span class="nx">tags</span><span class="p">.</span><span class="nx">length</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
    <span class="kd">const</span> <span class="nx">filterMode</span> <span class="o">=</span> <span class="nb">window</span><span class="p">.</span><span class="nx">filterEnhancements</span><span class="p">?.</span><span class="nx">getFilterMode</span><span class="p">()</span> <span class="o">||</span> <span class="dl">'</span><span class="s1">OR</span><span class="dl">'</span><span class="p">;</span>

    <span class="k">if</span> <span class="p">(</span><span class="nx">filterMode</span> <span class="o">===</span> <span class="dl">'</span><span class="s1">AND</span><span class="dl">'</span><span class="p">)</span> <span class="p">{</span>
        <span class="c1">// Mode ET : tous les tags doivent être présents</span>
        <span class="nx">pagefindFilters</span><span class="p">.</span><span class="nx">tags</span> <span class="o">=</span> <span class="nx">activeFilters</span><span class="p">.</span><span class="nx">tags</span><span class="p">;</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
        <span class="c1">// Mode OU : au moins un tag doit être présent</span>
        <span class="nx">pagefindFilters</span><span class="p">.</span><span class="nx">tags</span> <span class="o">=</span> <span class="nx">activeFilters</span><span class="p">.</span><span class="nx">tags</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="ajouter-les-suggestions-après-le-filtrage">Ajouter les suggestions après le filtrage</h3>

<p>Dans la fonction <code class="language-plaintext highlighter-rouge">toggleTagFilter</code> (ligne 372), après <code class="language-plaintext highlighter-rouge">updateActiveFiltersUI()</code> :</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Mettre à jour les suggestions</span>
<span class="k">if</span> <span class="p">(</span><span class="nb">window</span><span class="p">.</span><span class="nx">filterEnhancements</span><span class="p">?.</span><span class="nx">updateTagSuggestions</span><span class="p">)</span> <span class="p">{</span>
    <span class="nb">window</span><span class="p">.</span><span class="nx">filterEnhancements</span><span class="p">.</span><span class="nx">updateTagSuggestions</span><span class="p">(</span><span class="nx">activeFilters</span><span class="p">.</span><span class="nx">tags</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="ajouter-le-tri-par-pertinence">Ajouter le tri par pertinence</h3>

<p>Dans la fonction <code class="language-plaintext highlighter-rouge">displaySearchResults</code> (ligne 132), avant <code class="language-plaintext highlighter-rouge">updatePagination()</code> :</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Trier les résultats par pertinence</span>
<span class="k">if</span> <span class="p">(</span><span class="nb">window</span><span class="p">.</span><span class="nx">filterEnhancements</span><span class="p">?.</span><span class="nx">sortResultsByRelevance</span><span class="p">)</span> <span class="p">{</span>
    <span class="nb">window</span><span class="p">.</span><span class="nx">filterEnhancements</span><span class="p">.</span><span class="nx">sortResultsByRelevance</span><span class="p">(</span>
        <span class="nx">postsContainer</span><span class="p">,</span>
        <span class="nx">activeFilters</span><span class="p">.</span><span class="nx">tags</span><span class="p">,</span>
        <span class="nx">query</span>
    <span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="3-exposer-les-fonctions-nécessaires">3. Exposer les fonctions nécessaires</h2>

<p>À la fin de <code class="language-plaintext highlighter-rouge">blog-search-pagefind.js</code>, exposer les fonctions globalement :</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Exposer les fonctions pour les améliorations</span>
<span class="nb">window</span><span class="p">.</span><span class="nx">toggleTagFilter</span> <span class="o">=</span> <span class="nx">toggleTagFilter</span><span class="p">;</span>
<span class="nb">window</span><span class="p">.</span><span class="nx">activeFilters</span> <span class="o">=</span> <span class="nx">activeFilters</span><span class="p">;</span>
</code></pre></div></div>

<h2 id="4-test-des-améliorations">4. Test des améliorations</h2>

<h3 id="test-du-script-de-normalisation">Test du script de normalisation</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 1. Prévisualiser les changements</span>
ruby scripts/normalize_tags.rb

<span class="c"># Vous devriez voir quelque chose comme :</span>
<span class="c"># 📄 _posts/2025/06/2025-06-15-vibe-coding.md</span>
<span class="c">#    Avant: IA, AI, développement</span>
<span class="c">#    Après: IA, développement</span>

<span class="c"># 2. Si tout est correct, appliquer</span>
ruby scripts/normalize_tags.rb <span class="nt">--apply</span>
</code></pre></div></div>

<h3 id="test-des-suggestions-de-tags">Test des suggestions de tags</h3>

<ol>
  <li>Ouvrir <code class="language-plaintext highlighter-rouge">/blog/</code> dans votre navigateur</li>
  <li>Cliquer sur un tag (ex: #IA)</li>
  <li>Vérifier que des suggestions apparaissent en haut</li>
  <li>Cliquer sur une suggestion → le tag doit s’ajouter aux filtres actifs</li>
</ol>

<h3 id="test-du-mode-etou">Test du mode ET/OU</h3>

<ol>
  <li>Cliquer sur plusieurs tags</li>
  <li>Observer les résultats en mode OU (par défaut)</li>
  <li>Basculer en mode ET</li>
  <li>Observer que seuls les articles avec TOUS les tags s’affichent</li>
</ol>

<h3 id="test-du-tri-par-pertinence">Test du tri par pertinence</h3>

<ol>
  <li>Faire une recherche avec plusieurs tags</li>
  <li>Les articles les plus pertinents doivent apparaître en premier</li>
  <li>Les articles featured doivent avoir un bonus de pertinence</li>
</ol>

<h2 id="5-styles-à-personnaliser-optionnel">5. Styles à personnaliser (optionnel)</h2>

<p>Si vous voulez adapter les couleurs à votre charte graphique, modifier dans <code class="language-plaintext highlighter-rouge">filter-enhancements.css</code> :</p>

<div class="language-css highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">/* Couleur principale du gradient */</span>
<span class="nt">background</span><span class="o">:</span> <span class="nt">linear-gradient</span><span class="o">(</span><span class="err">135</span><span class="nt">deg</span><span class="o">,</span> <span class="err">#667</span><span class="nt">eea</span> <span class="err">0</span><span class="o">%,</span> <span class="err">#764</span><span class="nt">ba2</span> <span class="err">100</span><span class="o">%);</span>
<span class="c">/* → Remplacer par vos couleurs */</span>

<span class="c">/* Couleur des tags actifs */</span>
<span class="nc">.tag-pill-large.active-filter</span> <span class="p">{</span>
    <span class="nl">background</span><span class="p">:</span> <span class="n">linear-gradient</span><span class="p">(</span><span class="m">135deg</span><span class="p">,</span> <span class="m">#667eea</span> <span class="m">0%</span><span class="p">,</span> <span class="m">#764ba2</span> <span class="m">100%</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="6-déploiement">6. Déploiement</h2>

<h3 id="commit-des-changements">Commit des changements</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git add scripts/ assets/ _includes/ FILTER_IMPROVEMENTS.md INTEGRATION_EXAMPLE.md
git commit <span class="nt">-m</span> <span class="s2">"feat: Ajouter améliorations des filtres Pagefind

- Script de normalisation des tags
- Suggestions de tags liés basées sur la co-occurrence
- Mode de filtrage ET/OU
- Tri des résultats par pertinence
- Documentation complète

Impact attendu:
- Consolidation des tags (IA: 73→91 articles)
- Meilleure découvrabilité du contenu
- Expérience de filtrage plus intuitive"</span>

git push
</code></pre></div></div>

<h3 id="intégration-progressive">Intégration progressive</h3>

<p>Si vous préférez tester progressivement :</p>

<p><strong>Étape 1 : Normalisation seule</strong></p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ruby scripts/normalize_tags.rb <span class="nt">--apply</span>
git add _posts scripts/normalize_tags.rb
git commit <span class="nt">-m</span> <span class="s2">"chore: Normaliser les tags du blog"</span>
git push
</code></pre></div></div>

<p><strong>Étape 2 : Attendre le rebuild et tester</strong></p>

<p><strong>Étape 3 : Ajouter les améliorations JS/CSS</strong></p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git add assets/ _includes/
git commit <span class="nt">-m</span> <span class="s2">"feat: Ajouter suggestions et tri des filtres"</span>
git push
</code></pre></div></div>

<h2 id="7-vérifications-post-déploiement">7. Vérifications post-déploiement</h2>

<p><strong>Checklist</strong> :</p>

<ul class="task-list">
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Les tags sont normalisés dans les articles</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />L’index Pagefind a été régénéré (vérifier les logs CI/CD)</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />La recherche fonctionne toujours</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Les suggestions de tags apparaissent</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Le toggle ET/OU fonctionne</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Le tri par pertinence est actif</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Les styles sont corrects sur mobile et desktop</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Pas d’erreurs dans la console du navigateur</li>
</ul>

<h2 id="8-rollback-si-nécessaire">8. Rollback si nécessaire</h2>

<p>Si quelque chose ne fonctionne pas :</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Revenir au commit précédent</span>
git reset <span class="nt">--hard</span> HEAD~1

<span class="c"># Ou revenir à un commit spécifique</span>
git reset <span class="nt">--hard</span> &lt;commit-hash&gt;

<span class="c"># Push force (attention, à utiliser avec précaution)</span>
git push <span class="nt">--force</span>
</code></pre></div></div>

<h2 id="9-support-et-debugging">9. Support et debugging</h2>

<h3 id="console-du-navigateur">Console du navigateur</h3>

<p>Les scripts affichent des logs utiles :</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">🏷️  20 tags configurés comme filtres</span><span class="dl">'</span><span class="p">)</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">✨ Améliorations des filtres chargées</span><span class="dl">'</span><span class="p">)</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">🔍 Recherche Pagefind: "MCP"</span><span class="dl">'</span><span class="p">)</span>
</code></pre></div></div>

<h3 id="vérifier-que-les-filtres-sont-bien-indexés">Vérifier que les filtres sont bien indexés</h3>

<p>Après le build, inspecter un article HTML généré :</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cat </span>_site/articles/2025/06/15/vibe-coding-prompt-driven-development.html | <span class="nb">grep </span>data-pagefind-filter
</code></pre></div></div>

<p>Vous devriez voir :</p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code>data-pagefind-filter="tags:IA"
data-pagefind-filter="tags:développement"
data-pagefind-filter="tags:prompt engineering"
</code></pre></div></div>

<h2 id="10-optimisations-futures">10. Optimisations futures</h2>

<h3 id="script-de-validation-pre-commit">Script de validation pre-commit</h3>

<p>Créer <code class="language-plaintext highlighter-rouge">.git/hooks/pre-commit</code> :</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/bash</span>
ruby scripts/normalize_tags.rb <span class="nt">--check</span>
<span class="k">if</span> <span class="o">[</span> <span class="nv">$?</span> <span class="nt">-ne</span> 0 <span class="o">]</span><span class="p">;</span> <span class="k">then
    </span><span class="nb">echo</span> <span class="s2">"❌ Des tags non normalisés ont été détectés"</span>
    <span class="nb">echo</span> <span class="s2">"Exécutez: ruby scripts/normalize_tags.rb --apply"</span>
    <span class="nb">exit </span>1
<span class="k">fi</span>
</code></pre></div></div>

<h3 id="analytics">Analytics</h3>

<p>Tracker l’usage des filtres avec Google Analytics :</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Dans blog-search-pagefind.js</span>
<span class="kd">function</span> <span class="nx">toggleTagFilter</span><span class="p">(</span><span class="nx">tag</span><span class="p">)</span> <span class="p">{</span>
    <span class="c1">// ... code existant ...</span>

    <span class="c1">// Track dans GA4</span>
    <span class="k">if</span> <span class="p">(</span><span class="nb">window</span><span class="p">.</span><span class="nx">gtag</span><span class="p">)</span> <span class="p">{</span>
        <span class="nx">gtag</span><span class="p">(</span><span class="dl">'</span><span class="s1">event</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">filter_tag</span><span class="dl">'</span><span class="p">,</span> <span class="p">{</span>
            <span class="dl">'</span><span class="s1">tag_name</span><span class="dl">'</span><span class="p">:</span> <span class="nx">tag</span><span class="p">,</span>
            <span class="dl">'</span><span class="s1">filter_action</span><span class="dl">'</span><span class="p">:</span> <span class="nx">activeFilters</span><span class="p">.</span><span class="nx">tags</span><span class="p">.</span><span class="nx">includes</span><span class="p">(</span><span class="nx">tag</span><span class="p">)</span> <span class="p">?</span> <span class="dl">'</span><span class="s1">add</span><span class="dl">'</span> <span class="p">:</span> <span class="dl">'</span><span class="s1">remove</span><span class="dl">'</span>
        <span class="p">});</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="-cest-terminé-">🎉 C’est terminé !</h2>

<p>Votre système de filtres est maintenant optimisé pour offrir une meilleure expérience utilisateur.</p>

    </div>
    
</div> <!-- ✅ Indexé : tout le contenu -->

      <div data-pagefind-ignore>Schemas SEO</div>
    </article>

    <!-- NON INDEXÉ -->
    <div data-pagefind-ignore>Maillage interne</div>
    <div data-pagefind-ignore>Ressources liées</div>
    <div data-pagefind-ignore>Partage social</div>
  </div>
</article>

🚀 Résultat attendu

Avant ces optimisations

Recherche: "MCP"
- ❌ Trouvait aussi "MCP" dans les titres d'articles liés
- ❌ Trouvait "MCP" dans les breadcrumbs
- ❌ Trouvait "MCP" dans la navigation
→ Résultats pollués, moins pertinents

Après ces optimisations

Recherche: "MCP"
- ✅ Trouve "MCP" uniquement dans le titre et contenu
- ✅ Filtres par tags normalisés et cohérents
- ✅ Résultats plus précis et pertinents
→ Meilleure expérience de recherche

🔧 Processus de build

# Lors du déploiement GitHub Actions
1. Harmonize tags (Python)
2. ✨ Normalize tags (Ruby) ← NOUVEAU
3. Generate tag pages
4. Build Jekyll
5. Build Pagefind index
   - Index uniquement data-pagefind-body
   - Exclut data-pagefind-ignore
   - Crée les filtres par tags/catégories

✅ Vérification post-déploiement

Pour vérifier que l’indexation fonctionne correctement :

  1. Console du navigateur sur /blog/ :
    // Doit afficher les filtres configurés
    console.log('Tags configurés comme filtres')
    
  2. Test de recherche :
    • Rechercher un terme présent dans le titre → doit trouver
    • Rechercher un terme présent dans le contenu → doit trouver
    • Rechercher un terme uniquement dans le breadcrumb → ne doit PAS trouver
  3. Test des filtres :
    • Cliquer sur un tag → doit filtrer correctement
    • Les tags normalisés doivent regrouper tous les articles

🎯 Métriques de succès

Métrique Avant Après
Précision de la recherche Moyenne Élevée
Résultats parasites Oui Non
Tags consolidés Non Oui (IA: 91+)
Recherche dans titre Oui Oui ✅
Recherche dans contenu Oui Oui ✅
Pollution navigation Oui Non ✅

📚 Documentation Pagefind

🔄 Maintenance continue

Bonnes pratiques

  1. Toujours utiliser les tags normalisés dans les nouveaux articles
  2. Éviter d’ajouter du contenu recherchable dans les zones de navigation
  3. Tester la recherche après chaque modification majeure du layout

Scripts disponibles

# Prévisualiser la normalisation
ruby scripts/normalize_tags.rb

# Appliquer la normalisation manuellement (si besoin)
ruby scripts/normalize_tags.rb --apply