# fields à « ids » dans WP_Query : alléger les requêtes d’une extension

> Charger des objets WP_Post complets pour compter ou lister des identifiants gaspille de la mémoire et du temps. Un paramètre change tout.

- Auteur : Clément Hadrot
- Publié le : 2024-01-04
- Mis à jour le : 2024-01-04
- Catégorie : Extensions
- URL : https://wpmoderne.dev.wordpress-developpement.fr/extensions/fields-ids-wp-query-alleger-requetes-extension/

## L’essentiel

- fields=ids évite l'hydratation complète des objets post
- found_posts suffit souvent sans charger un seul contenu
- Le cache d'objets reste alimenté différemment selon le mode choisi

Une extension de gestion de stock que nous maintenons affichait un tableau de bord avec sept compteurs : nombre de produits en rupture, nombre de commandes en attente, nombre d'articles sans image, et ainsi de suite. Le code d'origine construisait sept instances de `WP_Query`, chacune récupérant l'intégralité des objets correspondants avant de simplement compter `$query->post_count`. Sur un catalogue de dix mille produits, ce tableau de bord mettait plus de deux secondes à s'afficher.

Le correctif tient en un seul paramètre, souvent ignoré parce qu'il ne change rien visuellement à un affichage classique de liste d'articles. Mais dès qu'une extension a seulement besoin d'un total ou d'une liste d'identifiants, ce paramètre transforme radicalement le travail demandé à WordPress et à MySQL.

## Ce que WP_Query fait par défaut

Sans précision, `WP_Query` exécute une requête `SELECT *` sur la table `wp_posts`, puis hydrate chaque ligne en objet `WP_Post` complet, avec l'ensemble de ses propriétés. Si l'appelant active en plus `update_post_meta_cache` ou `update_post_term_cache`, ce qui est le comportement par défaut, WordPress lance des requêtes supplémentaires pour précharger les métadonnées et les termes de taxonomie de chaque résultat, même si le code appelant ne les consultera jamais.

Pour un simple comptage ou une liste d'identifiants destinée à une autre requête, tout ce travail est perdu. C'est exactement le cas du tableau de bord de gestion de stock : aucun contenu d'article n'était affiché, seul le nombre de résultats comptait.

## Le paramètre fields et ses trois valeurs

Le paramètre `fields` de `WP_Query` accepte trois valeurs utiles au-delà du défaut :

| Valeur | Effet | Cas d'usage typique |
| --- | --- | --- |
| `''` (défaut) | Objets `WP_Post` complets | Affichage de contenu réel |
| `'ids'` | Tableau d'identifiants entiers | Comptage, exclusion, requêtes ultérieures |
| `'id=>parent'` | Tableau associatif ID vers ID parent | Reconstruction de hiérarchies |

> L'essentiel à retenir : fields=ids évite l'hydratation complète des objets post ; found_posts suffit souvent sans charger un seul contenu ; Le cache d'objets reste alimenté différemment selon le mode choisi

Avec `fields => 'ids'`, WordPress ne charge plus les objets complets : la requête SQL reste un `SELECT` sur la colonne d'identifiant uniquement, et surtout, les préchargements de métadonnées et de taxonomies sont automatiquement désactivés, sauf demande explicite contraire.

## Réécrire le tableau de bord

Voici la version corrigée d'un des sept compteurs du tableau de bord, celui des produits en rupture de stock :

```
$rupture = new WP_Query( array(
    'post_type'              => 'produit',
    'posts_per_page'         => 1, // seul found_posts nous intéresse
    'fields'                 => 'ids',
    'meta_key'               => 'stock_quantite',
    'meta_value'             => 0,
    'meta_compare'           => '<=',
    'no_found_rows'          => false, // il nous faut le total
    'update_post_meta_cache' => false,
    'update_post_term_cache' => false,
) );

$total_rupture = $rupture->found_posts;
```

Le détail qui compte ici est la combinaison de `posts_per_page => 1` avec `no_found_rows => false`. WordPress calcule tout de même le total réel via `SQL_CALC_FOUND_ROWS`, mais ne charge qu'une seule ligne de résultat en mémoire. Sur les sept compteurs du tableau de bord, cette réécriture a fait passer le temps d'affichage de deux secondes à un peu plus de trois cents millisecondes.

### Le piège inverse : no_found_rows mal utilisé

À l'inverse, si le besoin est uniquement une liste d'identifiants sans avoir besoin du total, il faut alors positionner `no_found_rows => true`, qui supprime purement et simplement le calcul `SQL_CALC_FOUND_ROWS`, plus coûteux que le tri lui-même sur de grandes tables. Confondre les deux réglages est une source fréquente de requêtes inutilement lentes.

## Ce que fields=ids ne remplace pas

Ce paramètre ne dispense pas de réfléchir à l'indexation des colonnes utilisées dans les clauses `meta_query`, ni de reconsidérer une architecture qui multiplierait les requêtes `meta_query` sur une table de métadonnées non structurée. Il agit uniquement sur la quantité de données hydratées et préchargées par PHP, pas sur le plan d'exécution SQL sous-jacent.

- Utiliser `fields => 'ids'` dès que le code n'a besoin ni du contenu, ni des métadonnées, ni des taxonomies de l'article.
- Combiner avec `update_post_meta_cache => false` et `update_post_term_cache => false` pour éviter les préchargements superflus, même quand des identifiants seulement sont demandés.
- Ne jamais appeler `get_post()` en boucle sur les identifiants obtenus si l'objectif reste un simple comptage : cela réintroduirait exactement le coût qu'on cherchait à éviter.

> Un réflexe qui nous sert sur chaque revue de code d'extension : avant d'écrire une nouvelle `WP_Query`, se demander ce que le code fera réellement du résultat. Si la réponse est « juste un nombre » ou « juste des identifiants », le paramètre `fields` doit apparaître dans la requête.

## En résumé

Le paramètre `fields` de `WP_Query` reste sous-utilisé alors qu'il coûte une seule ligne de code à ajouter. Sur un tableau de bord, un widget de statistiques ou une vérification d'existence, il transforme une requête coûteuse en une opération quasi instantanée, sans changer une seule ligne d'affichage côté utilisateur final.
