# Un filtre à facettes relié à une Query Loop du même thème

> Sur un catalogue simple, plusieurs filtres combinés devaient rester synchronisés avec la Query Loop affichée, sans installer de plugin de recherche dédié.

- Auteur : Clément Hadrot
- Publié le : 2026-01-14
- Mis à jour le : 2026-01-14
- Catégorie : Blocs Gutenberg
- URL : https://wpmoderne.dev.wordpress-developpement.fr/blocs/filtre-facettes-query-loop-meme-theme/

## L’essentiel

- Les filtres écrivent dans l'URL, la Query Loop se relit depuis ses paramètres
- La navigation côté client de l'Interactivity API évite un rechargement complet
- Combiner plusieurs facettes exige une fusion explicite des paramètres

Le catalogue de la Ferme du Clos reste volontairement modeste : une quarantaine de produits, quatre familles, deux modes de conditionnement. Installer un plugin de recherche à facettes complet pour un catalogue de cette taille semblait disproportionné, tant en coût qu'en complexité de configuration. Le besoin réel tenait en une phrase : des filtres par famille et par disponibilité, combinables, reliés à une Query Loop existante, sans rechargement complet de page à chaque changement.

## Le principe retenu : l'URL comme source de vérité

Plutôt que de gérer un état de filtre entièrement côté JavaScript déconnecté de la page, l'équipe a choisi de faire porter l'état des filtres par les paramètres de l'URL (`?famille=fruits&disponible=oui`), lus à la fois par la Query Loop côté rendu initial (PHP) et par les blocs de facette côté client. Cette approche garantit qu'un lien partagé ou une actualisation de page reproduit exactement le même résultat filtré.

## Le bloc de facette

Chaque facette est un bloc simple à base de cases à cocher, utilisant l'Interactivity API pour intercepter le clic et mettre à jour l'URL sans rechargement complet :

```
<div
  data-wp-interactive="clos/facette"
  data-wp-context='{ "parametre": "famille", "valeur": "fruits" }'
>
  <input
    type="checkbox"
    data-wp-bind--checked="state.estActif"
    data-wp-on--change="actions.basculerFacette"
  />
  Fruits
</div>
```

```
import { store, getContext } from '@wordpress/interactivity';

store('clos/facette', {
  actions: {
    *basculerFacette() {
      const { parametre, valeur } = getContext();
      const url = new URL(window.location.href);
      const valeurs = url.searchParams.getAll(parametre);

      if (valeurs.includes(valeur)) {
        url.searchParams.delete(parametre);
        valeurs.filter((v) => v !== valeur).forEach((v) => url.searchParams.append(parametre, v));
      } else {
        url.searchParams.append(parametre, valeur);
      }

      yield import('@wordpress/interactivity-router').then(({ actions }) =>
        actions.navigate(url.toString())
      );
    },
  },
});
```

> L'essentiel à retenir : Les filtres écrivent dans l'URL, la Query Loop se relit depuis ses paramètres ; La navigation côté client de l'Interactivity API évite un rechargement complet ; Combiner plusieurs facettes exige une fusion explicite des paramètres

La fonction `navigate` du routeur côté client de l'Interactivity API (utilisée aussi par la pagination améliorée de la Query Loop depuis WordPress 6.5) récupère la nouvelle page en arrière-plan et ne remplace que les régions marquées `data-wp-router-region`, évitant un rechargement complet et conservant l'état de défilement.

## Côté Query Loop : lire les paramètres au rendu

La Query Loop elle-même reste un bloc natif, mais son `render.php` (via un filtre `render_block_core/query` pour cette Query Loop précise, identifiée par une classe CSS personnalisée dans ses attributs) enrichit les arguments de la requête avec les paramètres d'URL présents :

```
add_filter( 'query_loop_block_query_vars', function ( $args, $block ) {
    if ( ! empty( $_GET['famille'] ) ) {
        $args['tax_query'][] = [
            'taxonomy' => 'famille_produit',
            'field'    => 'slug',
            'terms'    => array_map( 'sanitize_title', (array) $_GET['famille'] ),
        ];
    }
    if ( isset( $_GET['disponible'] ) && 'oui' === $_GET['disponible'] ) {
        $args['meta_key']   = 'en_stock';
        $args['meta_value'] = '1';
    }
    return $args;
}, 10, 2 );
```

## Combiner plusieurs facettes sans qu'elles s'écrasent

Le piège principal de cette approche apparaît dès la deuxième facette activée : sans précaution, chaque bloc de facette écrivant dans l'URL indépendamment risque d'effacer les paramètres posés par une autre facette. La fonction `basculerFacette` ci-dessus lit systématiquement l'URL courante avant de la modifier, plutôt que de la reconstruire depuis zéro, ce qui garantit que les facettes actives sur d'autres paramètres restent intactes.

- Toujours lire l'URL existante avant de la modifier, jamais la reconstruire à partir de rien.
- Vérifier que la Query Loop cible bien la bonne instance si plusieurs Query Loop coexistent sur la même page.
- Tester la navigation au clavier et avec JavaScript désactivé : dans ce dernier cas, les cases à cocher doivent rester de simples liens de secours fonctionnels.

> Un filtre qui ne survit pas à une actualisation de page n'est pas un filtre, c'est un gadget visuel.

## Ce que ce cas ne couvre pas

Le tri simple par champ unique (prix croissant, date de publication) repose sur un mécanisme plus direct déjà couvert séparément : ce cas concerne spécifiquement la combinaison de plusieurs facettes actives simultanément et leur synchronisation avec l'URL.

## En résumé

Quatre facettes combinables, aucune dépendance à un plugin de recherche, et un comportement qui reste utilisable sans JavaScript : la Ferme du Clos a évité l'installation d'un plugin dont la majorité des fonctionnalités seraient restées inutilisées pour un catalogue de cette taille.
