WordPress 6.1, sorti en novembre 2022, a généralisé une optimisation qui existait déjà partiellement dans les versions précédentes : la mise en cache des résultats de WP_Query via l’argument cache_results, désormais activé par défaut pour la quasi-totalité des requêtes de contenu. Pour la majorité des sites, ce changement est invisible et strictement bénéfique. Pour certaines extensions construisant des requêtes personnalisées avec des paramètres dynamiques ou non déterministes, il mérite une vérification.
Ce que change concrètement cache_results
Avant ce changement, chaque appel à WP_Query avec les mêmes paramètres réexécutait systématiquement la requête SQL correspondante, même si un appel strictement identique venait d’avoir lieu quelques lignes plus haut dans le même chargement de page, un scénario fréquent quand plusieurs blocs ou widgets interrogent indépendamment le même contenu.
$requete = new WP_Query( array(
'post_type' => 'article',
'posts_per_page' => 5,
'orderby' => 'date',
// cache_results est désormais true par défaut, plus besoin de le préciser
) );
Avec cache_results activé, WordPress met en cache le tableau d’identifiants de posts retournés par la requête SQL, ainsi que les objets post correspondants, en s’appuyant sur le cache d’objets standard. Sans cache d’objets persistant installé, ce cache reste limité à la durée du chargement de page en cours, mais évite déjà les requêtes SQL redondantes au sein d’une même exécution.
Un comportement qui suit le cache d’objets disponible

Sur un hébergement sans Redis ni Memcached, ce cache disparaît intégralement à la fin de chaque chargement de page : chaque nouvelle visite déclenche à nouveau les requêtes SQL nécessaires, sans effet de bord persistant. Sur un site équipé d’un cache d’objets persistant, en revanche, ces résultats peuvent survivre bien au-delà d’un seul chargement de page, exactement comme n’importe quelle autre donnée mise en cache via wp_cache_set.
C’est précisément cette persistance qui a révélé un bug sur un projet d’agenda d’événements que j’accompagne : une requête personnalisée filtrant les événements par un paramètre meta_query comparant une date de fin à current_time( 'mysql' ) retournait, sur un site équipé de Redis, des résultats figés au moment de la première exécution, plutôt que de refléter l’heure réelle de chaque nouvelle requête.
Le piège des requêtes non déterministes
// Problématique avec un cache d'objets persistant depuis la 6.1
$evenements_a_venir = new WP_Query( array(
'post_type' => 'evenement',
'meta_query' => array(
array(
'key' => '_date_fin',
'value' => current_time( 'mysql' ),
'compare' => '>=',
'type' => 'DATETIME',
),
),
) );
La clé de cache générée par WP_Query dépend des paramètres de la requête, mais current_time( 'mysql' ) change à chaque appel, à la seconde près. Dans les faits, cela devrait plutôt empêcher toute réutilisation du cache plutôt que produire un résultat figé. Le vrai problème identifié sur ce projet était plus subtil : un plugin tiers de mise en cache de page complète capturait la sortie HTML générée à partir de ce premier résultat, et servait cette page en cache pendant plusieurs heures, sans lien direct avec cache_results lui-même mais révélé au même moment par l’enquête.
Ce cas illustre un principe plus large : depuis la 6.1, il devient plus important que jamais de bien distinguer les différentes couches de cache d’un site (résultats de requête, objets, page complète) pour diagnostiquer correctement un affichage de données obsolètes.
Désactiver le cache pour une requête spécifique
Pour une requête dont on sait qu’elle ne doit jamais être mise en cache, par exemple une requête utilisée uniquement dans un contexte d’administration où la fraîcheur absolue prime sur la performance, l’argument reste disponible pour être explicitement désactivé.
$requete_admin = new WP_Query( array(
'post_type' => 'commande',
'post_status' => 'toutes',
'cache_results' => false,
) );
Ce réglage reste l’exception plutôt que la règle : pour l’immense majorité des requêtes de contenu, laisser cache_results à sa valeur par défaut est la décision la plus performante, et c’est précisément pour cette raison que l’équipe cœur en a fait le comportement par défaut à partir de cette version.
Ce que les extensions doivent vérifier
- Repérer les requêtes personnalisées dont les résultats dépendent d’un état qui change plus vite que le cache susceptible de les envelopper (horodatage, session utilisateur, géolocalisation)
- Invalider explicitement le cache concerné, via
clean_post_cache()ou une purge ciblée, plutôt que de désactivercache_resultspar précaution sur l’ensemble des requêtes - Tester le comportement de l’extension avec et sans cache d’objets persistant actif : un bug invisible en développement local peut apparaître uniquement en production équipée de Redis
Un bug de données obsolètes découvert après une montée de version majeure du cœur n’est pas toujours causé directement par cette version : elle peut simplement révéler, en généralisant un comportement, un problème d’invalidation de cache qui existait déjà latent dans l’extension.
En résumé
Le cache des résultats de WP_Query, généralisé par défaut depuis WordPress 6.1, apporte un gain de performance réel sans configuration supplémentaire pour la grande majorité des sites. Il mérite en revanche une vérification ciblée pour toute extension construisant des requêtes personnalisées dont le résultat dépend d’un état changeant rapidement, en particulier sur les sites équipés d’un cache d’objets persistant où les effets de ce cache dépassent la durée d’un simple chargement de page.