Dès qu’un projet WordPress dépasse le simple blog, WP_Query devient l’outil du quotidien : afficher les articles d’une catégorie croisée avec un champ personnalisé, exclure certains contenus, trier par une valeur de métadonnée. Ces besoins reviennent si souvent qu’il vaut la peine de bien maîtriser deux arguments en particulier : meta_query et tax_query.
Ce sont aussi deux arguments qui, mal utilisés, peuvent ralentir sérieusement un site : une requête avec plusieurs meta_query imbriquées sur une table wp_postmeta non indexée pour ces clés se paie cher en performance. Voici les schémas les plus fiables, avec leurs pièges.
La structure de base d’une meta_query
Une meta_query est un tableau de conditions, chacune portant sur une clé de métadonnée. Voici un exemple simple : récupérer les produits dont le prix est inférieur à 50 euros.
$query = new WP_Query( array(
'post_type' => 'produit',
'meta_query' => array(
array(
'key' => 'prix',
'value' => 50,
'compare' => '<',
'type' => 'NUMERIC',
),
),
) );
Le paramètre type est souvent oublié, mais il est essentiel : sans lui, WordPress compare les valeurs comme des chaînes de caractères, ce qui donne des résultats aberrants sur des nombres (« 9 » étant alors « supérieur » à « 100 »).
Combiner plusieurs conditions
Pour combiner plusieurs conditions, on ajoute une clé relation au tableau parent :
$query = new WP_Query( array(
'post_type' => 'produit',
'meta_query' => array(
'relation' => 'AND',
array(
'key' => 'prix',
'value' => array( 20, 50 ),
'compare' => 'BETWEEN',
'type' => 'NUMERIC',
),
array(
'key' => 'en_stock',
'value' => '1',
'compare' => '=',
),
),
) );
Les opérateurs compare les plus utiles au quotidien sont =, !=, BETWEEN et EXISTS. Ce dernier est pratique pour ne récupérer que les contenus où un champ a été renseigné, sans se soucier de sa valeur.

Filtrer par taxonomie avec tax_query
tax_query suit une logique similaire, appliquée aux taxonomies plutôt qu’aux champs personnalisés. Exemple : afficher les articles appartenant à la catégorie « actualites » et taggés « evenement ».
$query = new WP_Query( array(
'post_type' => 'post',
'tax_query' => array(
'relation' => 'AND',
array(
'taxonomy' => 'category',
'field' => 'slug',
'terms' => array( 'actualites' ),
),
array(
'taxonomy' => 'post_tag',
'field' => 'slug',
'terms' => array( 'evenement' ),
),
),
) );
Le champ field accepte slug, term_id ou name. En pratique, slug reste le plus lisible et le plus stable dans le code, car un identifiant numérique change d’un environnement à l’autre.
Exclure des termes
L’opérateur operator à l’intérieur d’une condition tax_query permet d’exclure plutôt que d’inclure :
array(
'taxonomy' => 'category',
'field' => 'slug',
'terms' => array( 'archive' ),
'operator' => 'NOT IN',
)
Combiner meta_query et tax_query dans la même requête
Rien n’empêche d’utiliser les deux arguments simultanément, tant que chacun garde sa propre structure de relation :
$query = new WP_Query( array(
'post_type' => 'produit',
'meta_query' => array(
array(
'key' => 'en_stock',
'value' => '1',
),
),
'tax_query' => array(
array(
'taxonomy' => 'categorie_produit',
'field' => 'slug',
'terms' => array( 'promotions' ),
),
),
) );
Le piège de la performance
Une meta_query génère une jointure SQL sur wp_postmeta pour chaque condition. Sur un site avec des dizaines de milliers de contenus, cela peut devenir lent, car cette table n’est indexée que sur meta_id et post_id, pas sur les valeurs elles-mêmes. Quelques réflexes limitent la casse :
- Éviter les
meta_queryprofondément imbriquées quand une taxonomie personnalisée ferait aussi bien l’affaire - Toujours préciser
typequand la comparaison porte sur un nombre ou une date - Mettre en cache le résultat d’une requête coûteuse avec
wp_cache_getetwp_cache_setsi elle s’exécute souvent - Envisager une table dédiée pour les cas de filtrage très fréquents sur un gros volume
Une taxonomie personnalisée, indexée nativement par WordPress, filtre souvent bien plus vite qu’un champ personnalisé équivalent utilisé dans une meta_query.
En résumé
meta_query et tax_query couvrent l’immense majorité des besoins de filtrage sur un site WordPress, à condition de connaître leurs pièges : le type de comparaison à préciser, la relation à structurer correctement, et le coût réel sur une base de données volumineuse. Sur un projet avec beaucoup de champs personnalisés filtrables, il vaut souvent mieux se poser la question, en amont, de transformer certains d’entre eux en taxonomies : le gain en lisibilité de requête et en performance est réel.