Comment effectuer une boucle secondaire dans WordPress ?

Introduction

Nous abordons dans ce nouveau tutoriel vidéo le traitement d’une boucle secondaire. Mais qu’entendons-nous par boucle secondaire ?

Rappelons qu’avec WordPress, les paramètres de l’URL passée dans le navigateur indique quel type de page nous voulons afficher ; à savoir un article, une page, une archive… Avec ces paramètres, WordPress effectue la requête pour récupérer les données recherchées. Puis, il va chercher le template dans sa hiérarchie correspondant à l’URL. Cette notion a déjà été abordée dans un précédent tutoriel qui expliquait la distinction entre la home page versus la front page.

Hiérarchie de templates WordPress

Dans le template, une boucle (loop) est effectuée pour afficher les différents posts résultants de la requête. Dans ce cas, nous parlons de requête principale (main query).

La requête s’effectue automatiquement (core de WordPress) mais la boucle, elle, dépend du template. Dans ce processus standard, le développeur ne se charge que des templates et de la boucle.

Seulement voilà, ce processus remplit à merveille de nombreuses tâches mais n’est pas suffisant pour d’autres beaucoup plus spécifiques comme par exemple un glossaire, un répertoire, un lexique

Notre étude de cas est dans la continuité de notre gestion des biens immobiliers abordée dans les tutoriels les custom post types pourquoi et comment ? et les ACF.

Aujourd’hui, nous allons traiter le cas où nous voudrions qu’une page répertoire affiche tous les biens immobiliers. Il y a aura donc une requête principale pour afficher la page répertoire et une autre, secondaire, pour afficher tous les biens.

WordPress nous offre la possibilité de traiter les requêtes secondaires avec trois instructions différentes :

Pour nous aider à comprendre ces trois fonctions de WordPress, nous allons nous aider du très bon schéma fournit dans l’article Andrey “Rarst” Savchenko Make sense of WordPress query functions.

Query functions

Dans le tutoriel, nous examinerons ce schéma pour les trois fonctions prises une à une et selon le découpage récupération des données (get), boucle (loop) et affichage, et restitution (cleanup) en fin de traitement.

De ces trois fonctions, seule query_posts est déconseillée car elle altère la requête principale (à l’exception du cas d’un traitement dans le back office – wp-admin – de WordPress).

Étudions maintenant notre code source.

La première partie s’intéressera à la création d’un template de page pour la page répertoire. La seconde traitera la boucle secondaire avec un exemple pour chacune des trois fonctions de WordPress pour effectuer un query.

Template de page pour la page répertoire

Dans ce template, nous procéderons à la requête principale et afficherons les informations propres à cette page à savoir le titre et le contenu de la page.

page-repertoire.php
<?php
/**
 * Template Name: Template Répertoire
 *
 * Description: Une page qui affiche tous les biens immobiliers par lieu classé par ordre alphabétique.
 *
 * @package WordPress
 * @subpackage Babel_Web_Tutoriels
 * @since Babel Web Tutoriels 1.0
 */

?>
<?php get_header(); ?>
<div id="primary" class="content-area">
	<main id="main" class="site-main" role="main">

	<?php if ( have_posts() ) : ?>
		<?php while ( have_posts() ) : the_post(); ?>

		<header class="page-header">
			<?php the_title( '<h1 class="entry-title">', '</h1>' ); ?>
			<?php the_content(); ?>
		</header><!-- .page-header -->

		<div id="immo-directory" class="immo-directory">
			<?php get_template_part( 'template-parts/content', 'page' ); ?>
		</div> <!-- .immo-grid -->
		
		<?php endwhile;	?>
	<?php endif; ?>
	</main><!-- .site-main -->
</div><!-- .content-area -->

<?php get_sidebar(); ?>
<?php get_footer(); ?>

Les parties surlignées du code indique premièrement, dans la partie commentaire, comment créer un template de page qui soit reconnu comme modèle pour une page. Puis, vient le traitement de la boucle principale.

C’est dans un sous templatetemplate-parts/content-page – qu’interviendra le traitement de la requête secondaire (ligne 27). Le sous template n’est pas obligatoire et nous aurions pu faire le code à la suite mais nous avons préféré les séparer afin de rendre le code plus lisible.

Traitements de la requête secondaire

Je vous laisse regarder le tutoriel vidéo qui vous explique chacune des instructions. Je ne souligne ici que le code final.

WP_QUERY

WP_Query
<?php

/**
 * WP_Query est une classe définie dans wp-includes/query.php qui traite avec subtilité la demande d'un post (ou d'une page). 
 * Cette classe fournit l'objet $wp_query définissant la requête en cours, 
 * puis $wp_query détermine quel type de requête il a affaire (peut-être une archive de la catégorie, les archives datées ou la recherche), 
 * et récupère les posts demandés. 
 * Il conserve beaucoup d'informations sur la requête qui peuvent être utilisées plus tard.
 */
?>
<h2>WP_Query</h2>
<?php
$dir_args = array(
	'post_status' 		=> 'publish',
	'post_type' 		=> 'immo',
	'posts_per_page' 	=> -1,
	'no_found_rows' 	=> true,
	'meta_key' 			=> 'lieu',
	'orderby' 			=> 'meta_value',
	'order' 			=> 'desc',
);

$dir = new WP_Query( $dir_args );
if ( $dir->have_posts() ) :
?>

<div class="dir-immo">
	<table>
		<thead>
			<tr>
				<th>post_title</th>
				<th>get_the_title</th>
				<th>ID</th>
				<th>Adresse</th>
				<th>Surface</th>
			</tr>
		</thead>
	<?php 
		while ( $dir->have_posts() ) : $dir->the_post(); 
			$map = get_field('lieu');
	?>
		<tr>
			<td><?php echo $post->post_title; ?></td>
			<td><?php the_title(); ?></td>
			<td><?php echo $post->ID; ?></td>
			<td><?php echo $map["address"]; ?></td>
			<td><?php echo esc_html(get_field('surface')). " m²"; ?></td>
		</tr>
	<?php endwhile;	?>
	</table>
	<p><mark>ID : <?php the_ID() ?> </mark></p>
	<?php
		/**
		 * wp_reset_postdata : après avoir parcourue une boucle sur une requête distincte, cette fonction restaure
		 * la globale $post sur le post actuel de la requête principale.
		 */
		wp_reset_postdata();
	?>
	<p><mark>ID : <?php the_ID() ?> </mark></p>
</div>
<?php endif; ?>

Notons qu’il existe une aide en ligne forte utile pour nous aider à « compiler » les arguments de WP_Query generatewp.com.

QUERY_POSTS

query_posts
<?php
/*
 * query_posts définit la boucle avec les paramètres de la requête.
 *
 * Remarque: Cette fonction remplacera complètement la requête principale et n'est pas destinée à être utilisée
 * par des plugins ou des thèmes. Son approche trop simpliste pour modifier la requête principale peut être
 * problématique et doit être évitée autant que possible. Dans la plupart des cas, il existe en mieux,
 * des options plus performantes pour modifier la requête principale par exemple via les actions pour le WP_Query
 * {@voir 'pre_get_posts'}.
 * 
 * Ne doit pas être utilisée dans la boucle de WordPress.
 *
 * Afin de modifier la requête principale, il est fortement recommandé que vous utilisiez l'action 'pre_get_posts' à la place, 
 * et verifier si on est bien dans la requête principale avec is_main_query().
 */
?>
<h2>query_posts</h2>
<?php
$dir_args = array(
	'post_status' 		=> 'publish',
	'post_type' 		=> 'immo',
	'posts_per_page' 	=> -1,
	'no_found_rows' 	=> true,
	'meta_key' 			=> 'lieu',
	'orderby' 			=> 'meta_value',
	'order' 			=> 'desc',
);

$dir2 = query_posts( $dir_args );
?>
<div class="dir-immo">
	<table>
		<thead>
			<tr>
				<th>post_title</th>
				<th>get_the_title</th>
				<th>ID</th>
				<th>Adresse</th>
				<th>Surface</th>
			</tr>
		</thead>
	<?php 
		foreach ( $dir2 as $post) :
			/**
			 * setup_postdata définit les données globales du post.
			 *
			 * setup_postdata() n'attribue pas la variable globale $post.
			 * Il est donc important que vous le fassiez vous-même. 
			 * Ne pas le faire peut causer des problèmes avec des hooks qui utilisent l'une des globales ci-dessus 
			 * avec la globale $post, car ils se réfèrent à des entités distinctes.
			 *
			 * @global int             $id
			 * @global WP_User         $authordata
			 * @global string|int|bool $currentday
			 * @global string|int|bool $currentmonth
			 * @global int             $page
			 * @global array           $pages
			 * @global int             $multipage
			 * @global int             $more
			 * @global int             $numpages
			 */
			setup_postdata( $post ); 
			$map = get_field('lieu');
	?>
		<tr>
			<td><?php echo $post->post_title; ?></td>
			<td><?php echo get_the_title(); ?></td>
			<td><?php echo $post->ID; ?></td>
			<td><?php echo $map["address"]; ?></td>
			<td><?php echo esc_html(get_field('surface')). " m²"; ?></td>
		</tr>
	<?php 
		endforeach;	
		/**
		 * wp_reset_query détruit la requête précédente et met en place une nouvelle requête.
		 *
		 * Devrait être utilisée après un query_posts() et avant un autre query_posts().
		 * Cela permettra d'éliminer les bogues obscurs qui se produisent lorsque l'objet WP_Query précédent
		 * n'est pas détruit correctement avant qu'un autre soit mis en place.
		 */
		wp_reset_query();
	?>
	</table>
	<p><mark>ID : <?php the_ID() ?> </mark></p>
</div>

GET_POSTS

get_posts
<h2>get_posts</h2>
<?php
$dir_args = array(
	'post_status' 		=> 'publish',
	'post_type' 		=> 'immo',
	'posts_per_page' 	=> -1,
	'no_found_rows' 	=> true,
	'meta_key' 			=> 'lieu',
	'orderby' 			=> 'meta_value',
	'order' 			=> 'desc',
);

/**
 * get_posts récupère les posts basés sur les variables de la requête.
 *
 * Il y a quelques filtres et des actions qui peuvent être utilisés pour modifier la requête sur le post
 *
 */
$dir2 = get_posts( $dir_args );
?>
<div class="dir-immo">
	<table>
		<thead>
			<tr>
				<th>post_title</th>
				<th>get_the_title</th>
				<th>ID</th>
				<th>Adresse</th>
				<th>Surface</th>
			</tr>
		</thead>
	<?php 
		foreach ( $dir2 as $post) :
			/**
			 * setup_postdata définit les données globales du post.
			 *
			 * setup_postdata() n'attribue pas la variable globale $post.
			 * Il est donc important que vous le fassiez vous-même. 
			 * Ne pas le faire peut causer des problèmes avec des hooks qui utilisent l'une des globales ci-dessus 
			 * avec la globale $post, car ils se réfèrent à des entités distinctes.
			 *
			 * @global int             $id
			 * @global WP_User         $authordata
			 * @global string|int|bool $currentday
			 * @global string|int|bool $currentmonth
			 * @global int             $page
			 * @global array           $pages
			 * @global int             $multipage
			 * @global int             $more
			 * @global int             $numpages
			 */
			setup_postdata( $post ); 
			$map = get_field('lieu');
	?>
		<tr>
			<td><?php echo $post->post_title; ?></td>
			<td><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></td>
			<td><?php echo $post->ID; ?></td>
			<td><?php echo $map["address"]; ?></td>
			<td><?php echo esc_html(get_field('surface')). " m²"; ?></td>
		</tr>
	<?php 
		endforeach;	
		/**
		 * wp_reset_postdata : après avoir parcourue une boucle sur une requête distincte, cette fonction restaure
		 * la globale $post sur le post actuel de la requête principale.
		 */
		wp_reset_postdata();
	?>
	</table>
	<p><mark>ID : <?php the_ID() ?> </mark></p>
</div>

 

Le résultat final

Personnaliser le query

Téléchargement des sources

Vous pouvez télécharger les sources sur GitHub.

Y a plus qu’à ! 🙂

Pour en savoir plus

Je vous souhaite un bon visionnage de ce tutoriel vidéo et n’hésitez pas à laisser vos commentaires et à partager sur les réseaux sociaux.

A bientôt.