vendredi 25 septembre 2026

À propos

Contact

Performance

get_field en boucle : comment ACF multiplie les requêtes sans cache de champs

Une boucle de 50 articles qui appelle get_field() pour chaque champ répété déclenche des centaines de requêtes. La solution passe par update_meta_cache.

Par Clément Hadrot • 11 mai 2021 • 4 min de lecture • Aucun commentaire
get_field en boucle : comment ACF multiplie les requêtes sans cache de champs

« La page catégorie met presque trois secondes à s’afficher, mais elle n’a rien de spécial. » C’est avec cette remarque qu’un client a signalé un ralentissement sur son site d’annuaire professionnel, dont chaque fiche affichait cinq champs ACF : logo, ville, spécialité, note moyenne et lien vers le site externe. La page catégorie affichait cinquante fiches par page, dans une boucle WP_Query classique.

L’onglet « Requêtes » de Query Monitor a immédiatement montré le problème : plus de 250 requêtes SQL pour cette seule page, la quasi-totalité concernant la table wp_postmeta, avec un motif répétitif qui trahissait un défaut classique d’utilisation d’Advanced Custom Fields.

Pourquoi get_field() multiplie les requêtes

La fonction get_field() s’appuie en interne sur get_post_meta(), qui lit la table wp_postmeta. WordPress dispose d’un mécanisme de cache des métadonnées par article, mais ce cache ne se remplit que pour les articles dont les métadonnées ont déjà été chargées en une fois, typiquement via la boucle principale de WP_Query lorsque l’option update_post_meta_cache est active, ce qui est le cas par défaut.

Le vrai problème sur ce projet venait d’ailleurs : la boucle d’affichage des fiches n’utilisait pas directement les résultats de la requête principale, mais rappelait get_posts() à l’intérieur de la boucle pour récupérer des informations complémentaires liées à chaque professionnel, ce qui cassait le préchargement natif et forçait une lecture individuelle des métadonnées pour chaque champ de chaque fiche.

Le rôle d’update_meta_cache

La fonction update_meta_cache(), appelée avec le type de méta concerné et un tableau d’identifiants d’articles, permet de précharger en une seule requête SQL l’ensemble des métadonnées de plusieurs articles à la fois, qui sont ensuite servies depuis le cache d’objet à chaque appel de get_field() ou get_post_meta() :

L'essentiel à retenir : get_field() sans précharge déclenche une requête par champ et par article ; update_meta_cache précharge tous les postmeta d'un lot en une requête ; Le gain grandit avec le nombre d'articles et de champs affichés
$ids = wp_list_pluck( $query->posts, 'ID' );
update_meta_cache( 'post', $ids );

foreach ( $query->posts as $post ) {
    $ville      = get_field( 'ville', $post->ID );
    $specialite = get_field( 'specialite', $post->ID );
    $note       = get_field( 'note_moyenne', $post->ID );
}

Avec ce préchargement explicite, ajouté juste après la récupération des résultats de la requête principale, les 250 requêtes constatées initialement sont tombées à une dizaine, la majeure partie du temps de chargement de la page se déplaçant vers le rendu HTML lui-même plutôt que vers la base de données.

Le cas particulier des appels get_posts() imbriqués

Le vrai correctif de fond a consisté à supprimer l’appel get_posts() imbriqué dans la boucle, qui récupérait un article lié pour afficher son titre. Cet appel a été remplacé par une jointure logique effectuée en amont, avant la boucle d’affichage, en récupérant tous les identifiants liés en une seule requête via WP_Query avec le paramètre post__in, puis en construisant un tableau associatif en mémoire :

$ids_lies = array_filter( array_map( function ( $post ) {
    return get_field( 'article_lie', $post->ID, false );
}, $query->posts ) );

$articles_lies = get_posts( array(
    'post__in'       => $ids_lies,
    'posts_per_page' => -1,
    'post_type'      => 'any',
) );
$titres_par_id = wp_list_pluck( $articles_lies, 'post_title', 'ID' );

Ce genre de restructuration demande un peu plus de code au moment de l’écriture, mais élimine la source la plus coûteuse de requêtes N+1 dans une boucle d’affichage.

Ce que cette optimisation ne couvre pas

Cette approche traite le préchargement des champs simples de type texte, nombre ou sélection. Les champs de relation ACF, qui pointent eux-mêmes vers d’autres articles avec leurs propres métadonnées, posent un problème de N+1 supplémentaire qui demande une stratégie de préchargement différente, non abordée ici.

En résumé

Un simple update_meta_cache() placé juste après la requête principale, combiné à la suppression des appels get_posts() imbriqués dans une boucle, a fait passer le temps de génération de la page catégorie de près de trois secondes à moins de 400 millisecondes côté serveur. C’est l’un des correctifs de performance ACF les plus rentables à mettre en œuvre, pour un coût de développement minime.

Partager :

À propos de l'auteur

Clément Hadrot

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

Voir tous ses articles

Dans la même veine

À lire aussi