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

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_querypeut 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.