vendredi 25 septembre 2026

À propos

Contact

FSE

Query Loop avancée : trier par champ personnalisé et exposer un filtre

Livrer un annuaire filtrable sans plugin de recherche tiers : comment combiner meta_query et un bloc de filtre côté Interactivity API, étape par étape.

Par Clément Hadrot • 28 octobre 2025 • 4 min de lecture • Aucun commentaire
Query Loop avancée : trier par champ personnalisé et exposer un filtre

Une chambre de commerce m’a confié la refonte de son annuaire d’entreprises adhérentes, avec une exigence précise : permettre de trier les fiches par date d’adhésion ou par nombre d’employés, deux champs personnalisés stockés en post_meta, et proposer un filtre par secteur d’activité, sans installer de plugin de recherche avancée jugé disproportionné pour un annuaire de deux cents entrées.

Voici la construction complète, en combinant un tri personnalisé côté serveur via pre_get_posts et un bloc de filtre construit avec l’Interactivity API pour une mise à jour fluide de la liste.

Étape 1 : exposer le tri par champ personnalisé à la Query Loop

Par défaut, l’interface de la Query Loop propose un tri par date de publication, titre ou ordre menu, mais aucun champ personnalisé n’apparaît nativement dans le sélecteur. Le contournement le plus fiable consiste à intercepter la requête via pre_get_posts, en lisant un paramètre d’URL dédié plutôt que de tenter de modifier l’inspecteur de blocs lui-même.

add_action( 'pre_get_posts', function( \WP_Query $query ) {
    if ( is_admin() || ! $query->is_main_query() ) {
        return;
    }
    if ( 'entreprise' !== $query->get( 'post_type' ) ) {
        return;
    }
    $tri = sanitize_key( $_GET['tri'] ?? '' );
    if ( 'employes' === $tri ) {
        $query->set( 'meta_key', 'nombre_employes' );
        $query->set( 'orderby', 'meta_value_num' );
        $query->set( 'order', 'DESC' );
    } elseif ( 'adhesion' === $tri ) {
        $query->set( 'meta_key', 'date_adhesion' );
        $query->set( 'orderby', 'meta_value' );
        $query->set( 'order', 'ASC' );
    }
} );

Cette approche conserve la Query Loop native de l’éditeur intacte, sans bloc personnalisé de remplacement, tout en pilotant le tri depuis un simple paramètre d’URL modifiable par le visiteur.

Étape 2 : filtrer par secteur d’activité avec meta_query

L'essentiel à retenir : Le tri par champ personnalisé passe par un filtre pre_get_posts ciblé ; Un bloc de filtre en Interactivity API met à jour l'URL sans rechargement ; La recherche plein texte reste hors périmètre de cette solution

Le secteur d’activité, stocké lui aussi en post_meta sous forme de terme unique par fiche, se filtre via une extension du même filtre pre_get_posts, avec une meta_query construite dynamiquement selon les paramètres présents dans l’URL :

add_action( 'pre_get_posts', function( \WP_Query $query ) {
    if ( is_admin() || ! $query->is_main_query() || 'entreprise' !== $query->get( 'post_type' ) ) {
        return;
    }
    $secteur = sanitize_text_field( $_GET['secteur'] ?? '' );
    if ( $secteur ) {
        $query->set( 'meta_query', array(
            array(
                'key'     => 'secteur_activite',
                'value'   => $secteur,
                'compare' => '=',
            ),
        ) );
    }
} );

Étape 3 : construire le bloc de filtre côté client

Plutôt qu’un simple formulaire HTML rechargeant toute la page, un petit bloc en Interactivity API permet de mettre à jour l’URL et de recharger uniquement la Query Loop, à condition que celle-ci ait bien son option Activer les mises à jour côté client cochée, disponible depuis la version 6.5.

<select
  data-wp-interactive="chambre-commerce/filtre"
  data-wp-on--change="actions.filtrerParSecteur"
>
  <option value="">Tous les secteurs</option>
  <option value="industrie">Industrie</option>
  <option value="services">Services</option>
  <option value="commerce">Commerce</option>
</select>
import { store } from '@wordpress/interactivity';

store( 'chambre-commerce/filtre', {
    actions: {
        filtrerParSecteur( evenement ) {
            const url = new URL( window.location.href );
            url.searchParams.set( 'secteur', evenement.target.value );
            window.history.pushState( {}, '', url );
            window.dispatchEvent( new PopStateEvent( 'popstate' ) );
        },
    },
} );

Le déclenchement d’un événement popstate synthétique permet à la Query Loop en mode interactif de détecter le changement d’URL et de rafraîchir son contenu côté client, sans rechargement complet, en réutilisant exactement le même mécanisme que la pagination native décrite dans un précédent article.

Combiner tri et filtre sans conflit

Les deux filtres pre_get_posts coexistent sans conflit puisqu’ils agissent sur des paramètres d’URL distincts (tri et secteur), combinables librement par l’utilisateur, chaque combinaison produisant une URL propre et partageable, ce qui a été un critère important pour la chambre de commerce souhaitant que ses membres puissent partager un lien filtré par courriel.

  • Un tri par champ personnalisé, sans bloc de remplacement de la Query Loop native.
  • Un filtre par secteur combinable librement avec le tri.
  • Des URL propres et partageables, contrairement à un filtrage purement JavaScript sans mise à jour de l’adresse.

La recherche plein texte reste un sujet distinct, qui dépasse ce que meta_query peut raisonnablement couvrir : au-delà d’un simple tri ou filtre par champ exact, une solution de recherche dédiée redevient pertinente.

En résumé

Un annuaire filtrable et triable par champ personnalisé ne nécessite ni plugin de recherche avancée ni bloc de remplacement de la Query Loop, à condition de combiner intelligemment pre_get_posts côté serveur et l’Interactivity API côté client pour une expérience fluide, sans jamais sacrifier la simplicité d’URL partageable qui reste précieuse pour ce type d’usage.

Partager :

À propos de l'auteur

Clément Hadrot

Développeur WordPress, passionné par Elementor, le FSE et l’automatisation par IA.

Voir tous ses articles

Dans la même veine

À lire aussi