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())
);
},
},
});

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.