La boucle principale de WordPress permet d’afficher les articles correspondant à l’adresse web utilisée par le visiteur du site. Il est possible de la modifier en utilisant le crochet « pre_get_posts » ou la fonction query_posts (déconseillé).
Le crochet pre_get_posts
Le crochet pre_get_posts permet de modifier la boucle principale avant qu’elle ne soit exécutée. Le codex décrit le fonctionnement de pre_get_posts (en anglais).
Nous allons voir quelques exemples de modification de la boucle principale.
Afficher un seul article en fonction de son identifiant (slug)
Code à insérer dans le fichier functions.php du thème actif :
Voici ce qui s’affiche lorsqu’on demande la page d’accueil :

Conformément au paramétrage défini dans la fonction associée au crochet ‘pre_get_ posts’ ($query->set( ‘name’, ‘article-5’ ), la boucle principale n’affiche que l’article dont l’identifiant est ‘article-5’.
Demandons l’affichage d’une catégorie d’articles. Voici ce qui s’affiche :

WordPress doit gérer deux conditions :
- la catégorie demandée dans l’adresse web,
- l’article 5 sélectionné par le crochet pre_get_posts.
Si l’article 5 ne fait pas partie de la catégorie demandée, WordPress ne trouve aucun article répondant simultanément aux deux conditions posées.
Voici, en partie, l’objet $query qui est passé en paramètre dans la fonction associée au crochet ‘pre_get_posts’ :
object(WP_Query)[1738]
public ‘query’ =>
array (size=1)
‘category_name’ => string ‘installation-wordpress’ (length=22)
public ‘query_vars’ =>
array (size=50)
‘category_name’ => string ‘installation-wordpress’ (length=22)
‘error’ => string » (length=0)
‘m’ => string » (length=0)
‘p’ => int 0
‘post_parent’ => string » (length=0)
‘subpost’ => string » (length=0)
‘subpost_id’ => string » (length=0)
‘attachment’ => string » (length=0)
‘attachment_id’ => int 0
‘name’ => string ‘article-5’ (length=9)
Pour éviter que le paramétrage soit pris en compte là où cela n’est pas souhaité, il est indispensable de compléter la fonction associée au crochet pre_get_posts :
La boucle principale n’est désormais modifiée que si trois conditions sont réunies : ne pas être dans l’administration [! is_admin()], être dans la boucle principale [is_main_query()] et demander l’affichage de la page d’accueil [is_home()]. Grâce à ces trois conditions, la page d’accueil affiche toujours le seul article 5, mais les autres pages ne sont plus impactées.
Afficher les articles de certaines catégories et modifier l’ordre
Code à insérer dans le fichier functions.php du thème actif :
Voici l’affichage correspondant de la page d’accueil :

- les articles affichés appartiennent aux catégories dont l’identifiant a été indiqué dans le crochet pre_get_posts : $query->set( ‘cat’, ‘3, 15, 18, 21’ )
- les articles sont affichés en commençant par les plus anciens : $query->set( ‘order’, ‘ASC’ )
En regardant l’objet $query, on constate que deux paramètres ont été modifiés :
cat’ => string ‘3, 15, 18, 21’ (length=13)
‘order’ => string ‘ASC’ (length=3)
Voici comment procéder :
- se rendre sur la page de gestion des catégories dans l’administration,
- survoler avec la souris l’option de modification de la catégorie,
- regarder la valeur de « tag_id » dans l’url qui apparaît.

Ce principe (faire apparaître l’identifiant dans l’url en survolant une option de modification) fonctionne pour d’autres identifiants : étiquette, média…
Afficher tous les articles associés à une étiquette avec tri sur le titre
Code à insérer dans le fichier functions.php du thème actif :
Voici l’affichage obtenu :

Paramètres modifiés dans l’objer $query :
‘tag_id’ => string ‘8’ (length=1)
‘posts_per_page’ => string ‘-1’ (length=2)
‘orderby’ => string ‘title’ (length=5)
‘order’ => string ‘ASC’ (length=3)
Il est important de noter la complémentarité des paramètres :
- order : qui permet de spécifier le sens ascendant ou descendant,
- orderby : qui permet de spécifier la valeur sur laquelle le tri va s’effectuer.
Par défaut, l’ordre est descendant et s’applique sur la date de publication.
Afficher les articles dans un ordre dépendant d’un champ personnalisé
Commençons par associer un champ personnalisé nommé « ordre » aux articles de la catégorie de démonstration avec pour valeur du champ personnalisé :
- pour les champs impairs : leur numéro d’article (1 pour l’article 1, 3 pour l’article 3…),
- pour les articles pairs : 10 plus leur numéro d’article (12 pour l’article 2, 14 pour l’article 4…).
Vérifier que la gestion des champs personnalisés soit bien activée dans les options de l’écran lors de la saisie des articles :

Créer un champ personnalisé pour chaque article et lui affecter la valeur prévue (exemple de l’article 2) :

Code à insérer dans le fichier functions.php du thème actif :
Remarques :
- la modification de la boucle n’impacte que la catégorie d’identifiant 21 : is_category(’21’),
- le nombre d’articles par page est limité à 4 : set( ‘posts_per_page’, ‘4’ ),
- le tri s’effectue sur le champ personnalisé (meta data) « ordre » : set( ‘meta_key’, ‘ordre’ ),
- le tri s’effectue sur la valeur numérique : set( ‘orderby’, ‘meta_value_num’ ). Il faut utiliser orderby / meta_value pour un tri alphanumérique.
Voici l’affichage obtenu (les articles pairs apparaissent avant les articles impairs, il n’y a que quatre articles sur la première page et l’ordre, non précisé, est descendant par défaut) :

Query_posts()
La fonction query_posts() permet de modifier la boucle principale. Elle n’est pas recommandée pour des questions de performance et d’effets de bord qu’il convient de maîtriser (notamment dans la gestion des pages). Il est préférable d’utiliser le crochet pre_get_posts pour modifier la boucle principale.
Voici un code permettant de n’afficher que 2 articles par page :
La page d’accueil n’affiche plus que deux articles du fait de « query_posts( ‘posts_per_page=2’ ) » :

Remarques :
- les paramètres disponibles sont les mêmes que pour pre_get_posts,
- query_posts() déclenche une nouvelle requête dans la base de données alors que pre_get_posts modifie la requête principale avant qu’elle ne soit exécutée, d’où un site plus lent à s’afficher avec query_posts().
Il est possible d’utiliser query_posts() indépendamment d’un crochet, l’essentiel étant de l’insérer avant l’affichage de la boucle principale. Voici un exemple de modification du fichier index.php :
Important : noter l’utilisation de la fonction wp_reset_query() qui permet de repositionner la boucle principale dans son état initial. De ce fait, query_posts() n’affecte que la première boucle.
Voici l’affichage obtenu :
- d’abord les titres des 3 plus anciens articles : ‘posts_per_page=3&order=ASC‘,
- puis l’affichage des articles les plus récents correspondant à l’affichage habituel de la boucle standard.

Les deux appels de fonction suivants sont équivalents :
- query_posts( ‘posts_per_page=3&order=ASC’ );
- query_posts( array( ‘posts_per_page’ => 3, ‘order’ => ‘ASC’ ) );
La deuxième écriture permet de passer aisément des paramètres dans des tableaux, comme dans l’exemple ci-dessous où on ne retient que les articles appartenant à la fois aux catégories 1 et 3 :
query_posts( array( ‘category__and’ => array(1,3), ‘posts_per_page’ => 2, ‘orderby’ => ‘title’, ‘order’ => ‘DESC’ ) );
Utiliser la query_string
La query_string est la partie de l’adresse web au delà de l’adresse du site qui définit ce que le visiteur souhaite afficher.
Code à insérer dans le fichier category.php du thème actif :
Demander l’affichage des articles d’une catégorie aura pour effet de n’afficher que les articles qui sont associés à la fois à cette catégorie et à la catégorie 15 du fait du paramètre « cat=15 » dans query_posts().
Par exemple, voici une url et la query_string correspondante pour l’affichage d’une catégorie :
- url : http://localhost/demo/sujet/categ_demo/
- query_string : string ‘category_name=categ_demo’ (length=24)
Utiliser le tableau query_vars
Les paramètres de requête sont stockés dans le tableau query_vars de l’objet $wp_query.
Code à insérer dans le fichier category.php du thème actif :
Ce code a le même effet que le précédant avec la query_string.
Voici les contenus impactés dans l’objet wp_query :
- issu de l’url : ‘category_name’ => string ‘categ_demo’ (length=10)
- modifié par le code ci-dessus :
- ‘cat’ => string ’15’ (length=2)
- ‘order’ => string ‘DESC’ (length=4)