WP_Query : guide complet des requêtes WordPress personnalisées
Maîtrisez WP_Query pour créer des requêtes WordPress personnalisées : paramètres, tax_query, meta_query, pagination et optimisation des performances.
Introduction à WP_Query : la classe centrale de WordPress
WP_Query est la classe PHP qui gère toutes les requêtes de récupération de contenu dans WordPress. Chaque fois qu’une page se charge, une instance de WP_Query est créée pour récupérer les articles, pages ou contenus personnalisés. Comprendre WP_Query vous permet de créer des affichages totalement sur mesure sans plugins tiers.
Ce guide couvre l’instanciation, tous les paramètres essentiels (post_type, tax_query, meta_query, date_query), la gestion de la pagination, les bonnes pratiques de performances et des exemples concrets.
Instancier WP_Query : la syntaxe de base
<?php
$args = array(
'post_type' => 'post',
'posts_per_page' => 10,
'post_status' => 'publish',
);
$ma_requete = new WP_Query( $args );
if ( $ma_requete->have_posts() ) {
while ( $ma_requete->have_posts() ) {
$ma_requete->the_post();
echo '<h2>' . get_the_title() . '</h2>';
echo get_the_excerpt();
}
wp_reset_postdata(); // TOUJOURS réinitialiser
} else {
echo 'Aucun article trouvé.';
}
?>
wp_reset_postdata() est indispensable pour restaurer les données globales de l’article original et éviter des bugs sur les sidebars et widgets.
Paramètres post_type, post_status, orderby
$args = array(
'post_type' => array( 'post', 'produit', 'portfolio' ),
'post_status' => array( 'publish', 'private' ),
'posts_per_page' => 5,
'offset' => 10,
'orderby' => 'date', // date, title, rand, menu_order, meta_value_num
'order' => 'DESC',
'author' => 3,
's' => 'WordPress',
);
tax_query : filtrer par taxonomie
$args = array(
'post_type' => 'post',
'tax_query' => array(
'relation' => 'AND',
array(
'taxonomy' => 'category',
'field' => 'slug',
'terms' => array( 'wordpress', 'php' ),
'operator' => 'IN', // IN, NOT IN, AND, EXISTS, NOT EXISTS
),
array(
'taxonomy' => 'post_tag',
'field' => 'slug',
'terms' => 'tutoriel',
),
),
);
meta_query : filtrer par champ personnalisé
$args = array(
'post_type' => 'produit',
'meta_query' => array(
'relation' => 'AND',
array(
'key' => '_prix',
'value' => array( 10, 100 ),
'type' => 'NUMERIC',
'compare' => 'BETWEEN',
),
array(
'key' => '_stock',
'value' => 0,
'type' => 'NUMERIC',
'compare' => '>',
),
),
'orderby' => 'meta_value_num',
'meta_key' => '_prix',
'order' => 'ASC',
);
date_query et pagination
// Filtrer par date
$args = array(
'date_query' => array(
array(
'after' => array( 'year' => 2025, 'month' => 1, 'day' => 1 ),
'before' => 'today',
'inclusive' => true,
),
),
);
// Pagination correcte
$paged = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;
$args = array(
'post_type' => 'post',
'posts_per_page' => 6,
'paged' => $paged,
);
$requete = new WP_Query( $args );
// Après la boucle :
echo paginate_links( array(
'base' => str_replace( 999999999, '%#%', esc_url( get_pagenum_link( 999999999 ) ) ),
'format' => '?paged=%#%',
'current' => max( 1, get_query_var( 'paged' ) ),
'total' => $requete->max_num_pages,
) );
wp_reset_postdata();
Optimiser les performances de WP_Query
| Paramètre | Impact | Quand l’utiliser |
|---|---|---|
| no_found_rows => true | Supprime le COUNT SQL | Sans pagination |
| fields => ‘ids’ | Requête minimale | Traitement en masse |
| update_post_meta_cache => false | Moins de requêtes | Si pas besoin des méta |
| update_post_term_cache => false | Moins de requêtes | Si pas besoin des termes |
| ignore_sticky_posts => true | Ignore les sticky | Requêtes secondaires |
$args = array(
'post_type' => 'post',
'posts_per_page' => 10,
'fields' => 'ids',
'no_found_rows' => true,
'update_post_meta_cache' => false,
'update_post_term_cache' => false,
'ignore_sticky_posts' => true,
);
$ids_query = new WP_Query( $args );
foreach ( $ids_query->posts as $post_id ) {
echo get_the_title( $post_id );
}
Exemples concrets : afficher des articles par méta et catégorie
// Articles mis en avant d'une catégorie
$args = array(
'post_type' => 'post',
'posts_per_page' => 9,
'cat' => 5,
'meta_query' => array(
array( 'key' => 'mise_en_avant', 'value' => '1', 'compare' => '=' ),
),
);
$requete = new WP_Query( $args );
if ( $requete->have_posts() ) :
echo '<div class="grille">';
while ( $requete->have_posts() ) : $requete->the_post();
printf(
'<article><a href="%s"><h3>%s</h3></a><p>%s</p></article>',
esc_url( get_permalink() ),
esc_html( get_the_title() ),
esc_html( get_the_excerpt() )
);
endwhile;
echo '</div>';
wp_reset_postdata();
endif;
Pour des développements WordPress avancés incluant des requêtes complexes, faites appel à notre développeur WordPress Paris.
Questions fréquentes sur WP_Query
Quelle est la différence entre WP_Query, get_posts() et query_posts() ?
WP_Query est la classe complète recommandée pour les requêtes secondaires. get_posts() est un wrapper simplifié retournant un tableau, pratique pour des listes simples. query_posts() est à éviter absolument car il modifie la requête principale globale et provoque des bugs de pagination. Utilisez le hook pre_get_posts pour modifier la requête principale.
Comment utiliser WP_Query avec un Custom Post Type ?
Remplacez 'post_type' => 'post' par le slug de votre CPT : 'post_type' => 'mon_cpt'. Vérifiez que votre CPT a 'publicly_queryable' => true dans son register_post_type(). Pour plusieurs CPT simultanément : 'post_type' => array('post', 'mon_cpt').
Pourquoi ma pagination WP_Query ne fonctionne pas ?
Causes fréquentes : 1) Oublier le paramètre 'paged'. 2) Confondre get_query_var('page') (page statique) et get_query_var('paged') (blog). 3) Avoir 'no_found_rows' => true qui désactive le calcul du total. 4) Un conflit avec la requête principale.
Comment modifier la requête principale sans WP_Query secondaire ?
Utilisez le hook pre_get_posts pour modifier la requête principale. C’est plus efficace que de créer une requête secondaire car WordPress ne lance qu’une seule requête SQL. Exemple : add_action('pre_get_posts', function($q){ if(!is_admin() && $q->is_main_query() && $q->is_home()){ $q->set('posts_per_page', 12); } });