Le WordPress d'aujourd'hui, décodé pour les développeurs

SEO & GEO

no_found_rows=true dans WP_Query : le paramètre qui casse un sitemap maison

Un paramètre de performance de WP_Query, très recommandé partout, désactive silencieusement le comptage total dont dépend la pagination d'un générateur de sitemap fait main.

Par WordPress Développement • 18 décembre 2023 • 5 min de lecture • Aucun commentaire
no_found_rows=true dans WP_Query : le paramètre qui casse un sitemap maison

'no_found_rows' => true. Cette ligne traîne dans la moitié des tutoriels d’optimisation WordPress, et à raison : elle évite à MySQL de recalculer le nombre total de lignes correspondant à une requête, un calcul coûteux sur une grosse table wp_posts. Le problème survient quand ce même réglage se retrouve, par copier-coller, dans le script qui génère un sitemap personnalisé.

Un générateur de sitemap fait main a besoin de deux choses : la liste des articles d’une page, et le nombre total de pages pour savoir quand s’arrêter. La seconde information vient précisément de ce que no_found_rows désactive. Résultat : le script boucle une fois, ne trouve rien à itérer de plus, et livre un sitemap tronqué sans qu’aucune erreur ne remonte.

Ce que fait réellement no_found_rows

Quand ce paramètre vaut true, WordPress n’ajoute pas la clause SQL_CALC_FOUND_ROWS à la requête SQL générée par WP_Query. Concrètement, les propriétés found_posts et max_num_pages de l’objet requête restent à zéro, quelle que soit la quantité réelle de contenus correspondants. C’est un gain de performance réel et mesurable, surtout sur des tables de plusieurs dizaines de milliers de lignes, parce que SQL_CALC_FOUND_ROWS oblige MySQL à parcourir l’ensemble du jeu de résultats avant de le limiter avec LIMIT.

Le hic, c’est que ce comportement est documenté dans le Codex mais rarement lu jusqu’au bout par qui copie une configuration « performance » trouvée ailleurs. Un script de sitemap type ressemble à ceci :

$query = new WP_Query( array(
    'post_type'      => 'post',
    'posts_per_page' => 500,
    'paged'          => $page,
    'no_found_rows'  => true,
) );

for ( $i = 1; $i <= $query->max_num_pages; $i++ ) {
    // générer la page $i du sitemap
}

Avec no_found_rows à true, max_num_pages vaut systématiquement 0. La boucle for ne s’exécute jamais, ou une seule fois si la condition est mal écrite avec un do…while. Le sitemap final ne référence que la première tranche de cinq cents articles, et personne ne s’en aperçoit tant que le nombre total de contenus reste sous ce seuil.

L'essentiel à retenir : no_found_rows désactive found_posts et max_num_pages ; Un script de sitemap qui boucle sur max_num_pages s'arrête à la première page ; Il faut calculer le total autrement, avec un COUNT dédié

Le bon calcul du nombre de pages

La solution consiste à séparer les deux besoins : une requête légère pour le comptage, une requête paginée pour le contenu. Pour le comptage, mieux vaut une requête SQL directe plutôt qu’un WP_Query complet, qui charge des objets WP_Post inutiles pour un simple total :

global $wpdb;

$total = (int) $wpdb->get_var(
    "SELECT COUNT(ID) FROM {$wpdb->posts}
     WHERE post_type = 'post' AND post_status = 'publish'"
);

$per_page       = 500;
$total_pages    = (int) ceil( $total / $per_page );

Ce total sert ensuite à piloter la boucle de génération, indépendamment du comportement de found_posts. Si l’on tient malgré tout à garder un seul objet WP_Query pour éviter deux systèmes de requêtage distincts, il suffit de passer no_found_rows à false uniquement pour la requête de comptage, quitte à payer le coût du SQL_CALC_FOUND_ROWS une seule fois par génération de sitemap plutôt qu’à chaque chargement de page publique.

Un piège voisin : le cache de found_posts

Autre subtilité : sur un site utilisant un cache d’objets persistant, found_posts peut aussi être mis en cache par des extensions tierces qui interceptent posts_results. Si le total change (nouvel article publié) sans que le cache soit invalidé, le sitemap continuera de se baser sur un compte obsolète. Un test simple : générer le sitemap juste après une publication et vérifier que le nombre d’URL a bien augmenté.

Vérifier avant de déployer

  • Compter manuellement les articles publiés via wp post list --post_type=post --post_status=publish --format=count en WP-CLI.
  • Comparer ce chiffre au nombre d’URL réellement présentes dans le sitemap généré.
  • Si les deux ne correspondent pas, chercher no_found_rows dans le script avant toute autre piste.
  • Ajouter un test automatisé qui échoue si le nombre d’URL du sitemap descend sous un seuil connu.

Sur un sitemap fait main, ne jamais faire confiance à max_num_pages sans avoir vérifié, au moins une fois, qu’il correspond au comptage manuel de la table. C’est un contrôle de deux minutes qui évite des semaines d’indexation partielle silencieuse.

En résumé

Le paramètre no_found_rows est une bonne pratique de performance, mais il ne doit jamais cohabiter, dans le même objet WP_Query, avec une logique de pagination qui dépend de max_num_pages. Pour un sitemap maison, la méthode la plus sûre reste de séparer explicitement le comptage total, via une requête SQL dédiée, de la récupération paginée des contenus. Ce découpage évite un bug silencieux qui n’apparaît que quand le catalogue dépasse la taille d’une seule page de résultats, c’est-à-dire précisément le moment où un sitemap devient réellement utile.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Partager :

À propos de l'auteur

WordPress Développement

Développeur WordPress, passionné par Elementor, le FSE et l’automatisation par IA.

Voir tous ses articles

Dans la même veine

À lire aussi