# WP_Query au quotidien : bien utiliser meta_query et tax_query

> Les requêtes personnalisées reviennent sans cesse dans un projet WordPress. Voici les schémas fiables pour meta_query et tax_query, avec leurs pièges de performance.

- Auteur : Clément Hadrot
- Publié le : 2020-04-14
- Mis à jour le : 2020-04-14
- Catégorie : Tips
- URL : https://wpmoderne.dev.wordpress-developpement.fr/tips/wp-query-meta-query-tax-query/

## L’essentiel

- meta_query combine plusieurs conditions sur les champs personnalisés
- tax_query filtre par taxonomie avec relation AND ou OR
- relevance et compare méritent d'être maîtrisés

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.

> L'essentiel à retenir : meta_query combine plusieurs conditions sur les champs personnalisés ; tax_query filtre par taxonomie avec relation AND ou OR ; relevance et compare méritent d'être maîtrisés

## 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_query` profondément imbriquées quand une taxonomie personnalisée ferait aussi bien l'affaire
- Toujours préciser `type` quand la comparaison porte sur un nombre ou une date
- Mettre en cache le résultat d'une requête coûteuse avec `wp_cache_get` et `wp_cache_set` si 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.
