Comment savoir, à l’intérieur d’un callback accroché à pre_get_posts, si l’on est en train de modifier la bonne requête et pas une autre ? La question revient sans cesse chez les développeurs qui découvrent ce hook : il se déclenche pour absolument toutes les instances de WP_Query, y compris celles qui affichent un widget « articles récents » dans la colonne latérale de l’administration ou celles générées par une extension tierce sur le front.
Sans garde-fou, une modification pensée pour la page d’accueil du site peut très bien s’appliquer à la liste des articles dans l’écran d’édition, avec des résultats déroutants : des contenus manquants, un tri différent, ou pire, un filtre par type de contenu qui masque des brouillons à un auteur qui cherche les siens.
Deux conditions à poser systématiquement
La combinaison qui protège de la quasi-totalité des effets de bord tient en deux vérifications, à placer en tout début de callback :
function wpm_filtrer_articles_recents( $query ) {
if ( is_admin() || ! $query->is_main_query() ) {
return;
}
if ( $query->is_home() ) {
$query->set( 'posts_per_page', 12 );
$query->set( 'meta_key', 'wpm_mis_en_avant' );
$query->set( 'orderby', 'meta_value_num date' );
$query->set( 'order', 'DESC' );
}
}
add_action( 'pre_get_posts', 'wpm_filtrer_articles_recents' );
is_admin() écarte tout ce qui se passe derrière l’écran d’administration, mais elle ne suffit pas seule : une extension peut très bien lancer une WP_Query secondaire sur le front, par exemple pour afficher des articles liés en pied de page. C’est là qu’intervient is_main_query(), qui ne renvoie true que pour la requête principale déclenchée par WordPress pour construire la page demandée par l’URL.
Cibler le bon type de page avant de toucher aux paramètres
Une fois ces deux conditions posées, il reste à choisir avec précision quelle page est concernée. Les méthodes conditionnelles de WP_Query couvrent la plupart des cas : is_home() pour la page d’accueil des articles, is_search() pour les résultats de recherche, is_post_type_archive() pour une archive de type personnalisé, is_tax() pour une taxonomie.

Une erreur fréquente consiste à tester is_home() seule alors que la page d’accueil du site a été configurée pour afficher une page statique. Dans ce cas, is_home() reste vraie pour la page qui liste les articles, mais ce n’est peut-être pas celle que le développeur croit viser. Un test rapide avec var_dump( $query->query_vars ) derrière un if ( WP_DEBUG ) permet de lever le doute avant de livrer.
Adapter une recherche sans exclure de contenus utiles
Sur une recherche, il est tentant de restreindre les types de contenus interrogés avec set( 'post_type', ... ). C’est légitime pour exclure des types techniques (des modèles internes, par exemple), mais il faut résister à l’envie de restreindre trop large : un visiteur qui cherche un mot précis s’attend à retrouver aussi bien un article qu’une page si elle contient ce mot.
- Toujours partir de
$query->get( 'post_type' )pour ne pas écraser une valeur déjà définie ailleurs - Combiner avec
tax_queryplutôt que de dupliquer la requête dans le thème - Documenter dans un commentaire pourquoi telle condition a été choisie, pour la personne qui reprendra le code
Vérifier les widgets et les requêtes secondaires du thème
Le piège le plus sournois n’est pas l’administration, déjà écartée par is_admin(), mais les requêtes secondaires lancées par le thème actif lui-même : un widget « articles à la une », une boucle de suggestions en pied d’article, un carrousel en page d’accueil. Chacune de ces boucles instancie sa propre WP_Query, et is_main_query() les exclut correctement du filtre pensé pour la requête principale.
Si l’objectif est justement de modifier l’une de ces requêtes secondaires, la bonne pratique consiste à passer un identifiant personnalisé dans les arguments de la requête, puis à le vérifier dans le callback plutôt que de retirer le test is_main_query() :
$args = array(
'post_type' => 'produit',
'wpm_widget' => 'suggestions',
);
$requete = new WP_Query( $args );
function wpm_filtrer_widget_suggestions( $query ) {
if ( 'suggestions' !== $query->get( 'wpm_widget' ) ) {
return;
}
$query->set( 'posts_per_page', 4 );
}
add_action( 'pre_get_posts', 'wpm_filtrer_widget_suggestions' );
Tester avant de livrer
Un plan de test minimal couvre quatre scénarios : la page d’accueil, une recherche avec un terme courant, une archive de type personnalisé et, surtout, l’écran « Tous les articles » de l’administration avec un compte auteur. Ce dernier test révèle immédiatement une éventuelle fuite du filtre côté back-office.
| Scénario | Résultat attendu | Piège fréquent |
|---|---|---|
| Page d’accueil | Tri personnalisé appliqué | Confusion avec une page statique |
| Recherche | Types de contenus élargis | Exclusion trop stricte des pages |
| Écran admin | Aucun changement | Oubli de is_admin() |
| Widget du thème | Non affecté par erreur | Oubli de is_main_query() |
Sur nos projets, la règle interne est simple : aucun callback accroché à
pre_get_postsn’est validé en revue de code sans les deux conditions de garde en première ligne.
En résumé
pre_get_posts reste l’un des hooks les plus puissants pour ajuster une requête sans dupliquer de code de boucle dans un thème, à condition de ne jamais oublier que ce hook parle à toutes les requêtes du site, sans distinction. Deux lignes de garde, un ciblage précis des pages concernées et un test systématique sur l’écran d’administration suffisent à éviter la quasi-totalité des régressions observées sur ce type de code.