Dans cet article, je décrirai quatres techniques différentes pour modifier la Query par défaut de WordPress. Ce sont des techniques de programmation WordPress assez avancées, donc avant de plonger dedans, assurez-vous d’être familier avec les concepts suivants :

  • Les Hooks dans WordPress
  • La Query WordPress

Modification de la Query par défaut dans WordPress

Il y a plusieurs façons de récupérer des Posts dans WordPress, mais nous pouvons distinguer deux techniques :

  • Modifier la requête par défaut de WordPress dans un contexte particulier => ce que nous allons faire ici
  • Créer une nouvelle requête à partir de zéro avec get_posts() ou une nouvelle WP_query par exemple. Ce sujet ne sera pas traité ici.


Ci dessous les différentes techniques pour modifier la requête par défaut de WordPress :

  • Hook sur l’action pre_get_posts
  • Utilisation de la fonction query_posts
  • Filtre sur la requête SQL
  • Hook sur l’action wp_the_query

Etude de cas : ajout d’une deuxième page à la page d’accueil

Supposons que vous ayez défini une page statique comme page d’accueil et que vous vouliez afficher une autre page en dessous.

Comment utiliser ce code ? Les extraits de code suivants doivent être copiés et collés dans le fichier functions.php de votre thème enfant.

La méthode pre_get_posts

C’est la façon la plus simple et la plus recommandée de modifier la requête principale. Ce hook pre_get_posts est appelé après la création de l’objet variable de requête, mais avant l’exécution de la query.

add_action('pre_get_posts','alter_query');
 
function alter_query($query) {
	//gets the global query var object
	global $wp_query;
 
	//gets the front page id set in options
	$front_page_id = get_option('page_on_front');
 
	if ( 'page' != get_option('show_on_front') || $front_page_id != $wp_query->query_vars['page_id'] )
		return;
 
	if ( !$query->is_main_query() )
		return;
 
	$query-> set('post_type' ,'page');
	$query-> set('post__in' ,array( $front_page_id , [YOUR SECOND PAGE ID]  ));
	$query-> set('orderby' ,'post__in');
	$query-> set('p' , null);
	$query-> set( 'page_id' ,null);
 
	//we remove the actions hooked on the '__after_loop' (post navigation)
	remove_all_actions ( '__after_loop');
}

La méthode query_posts()

query_posts() est destiné à modifier la boucle principale. Pour ce faire, il remplace la requête utilisée pour générer le contenu de la boucle principale. Une fois que vous utilisez query_posts(), les variables globales et les balises de modèle associées à vos posts seront modifiées. Les balises conditionnelles qui sont appelées après l’appel de query_posts() seront également modifiées – ceci peut ou non être le résultat voulu.

Même si ce n’est pas la meilleure façon de modifier la requête, cette technique montre comment utiliser certains hooks intéressants avant et après la boucle dans le thème.

//those hooks are located in the index.php template of the theme
add_action( '__before_loop' , 'alter_query' );
add_action( '__after_loop'  , 'alter_query' );
 
function alter_query() {
	//we call the global query variable from the current instance of WP_query class.
	global $wp_query;
 
	//gets the front page id set in options
	$front_page_id = get_option('page_on_front');
 
	//checks the context before altering the query
	if ( 'page' != get_option('show_on_front') || $front_page_id != $wp_query->query_vars['page_id'] )
		return;
 
	//this switch statement allows us to use the same call back function for two different hooks
	switch ( current_filter() ) {
		case '__before_loop':
 
			$args = array( 
				'post_type' 	=> 'page', 
				'post__in' 		=> array( $front_page_id , [YOUR SECOND PAGE ID]  ),
				'orderby'		=> 'post__in'//we want to keep the order defined in the 'post__in' array
			);
 
			//execute the 
			query_posts( $args );
 
			//set global $wp_query object back initial values for boolean and front page id
			$wp_query->is_page 					= true;
			$wp_query->is_singular 				= true;
			$wp_query->query_vars['p']  		= $front_page_id;
			$wp_query->query_vars['page_id']  	= $front_page_id;
			break;
 
		case '__after_loop':
			//reset the custom query
			wp_reset_query();
			break;
	}
}

Ce problème de query_posts() est bien expliqué par Andrew Nacin (développeur du noyau WP), ici : http://wordpress.tv/2013/03/15/andrew-nacin-wp_query-wordpress-in-depth/

La méthode de filtrage des instructions SQL

La 3ème méthode – mais pas des moindres – est une technique plus avancée qui offre plus de flexibilité si vous avez besoin de faire des requêtes complexes. Par exemple, cette technique est la meilleure façon de construire une requête qui compare les dates des champs personnalisés. (Je donnerai bientôt un exemple de cette approche)

Dans cet exemple, nous filtrons les instructions “where” et “orderby par sql. (Il n’est pas nécessaire de modifier l’instruction “jointure” mais ce serait également possible ici)

add_filter( 'posts_where' , 'posts_where_statement' );
 
function posts_where_statement( $where ) {
	//gets the global query var object
	global $wp_query;
 
	//gets the front page id set in options
	$front_page_id = get_option('page_on_front');
 
	//checks the context before altering the query
	if ( 'page' != get_option('show_on_front') || $front_page_id != $wp_query->query_vars['page_id'] )
		return $where;
 
	//changes the where statement
	$where = " AND wp_posts.ID IN ('{$front_page_id}', [YOUR SECOND PAGE ID] ) AND wp_posts.post_type = 'page' ";
 
	//removes the actions hooked on the '__after_loop' (post navigation)
	remove_all_actions ( '__after_loop');
 
	return $where;
}
 
add_filter( 'posts_orderby' , 'posts_orderby_statement' );
 
function posts_orderby_statement($orderby) {
	global $wp_query;
	$front_page_id = get_option('page_on_front');
 
	//checks the context before altering the query
	if ( 'page' != get_option('show_on_front') || $front_page_id != $wp_query->query_vars['page_id'] )
		return $orderby;
 
	//changes the orderby statement
	$orderby = " FIELD( wp_posts.ID, '{$front_page_id}' ,[YOUR SECOND PAGE ID] )";
 
    return $orderby;
}

La méthode $wp_the_query

L’extrait de code suivant utilise une variable globale appelée $wp_the_query où WordPress stocke soigneusement la requête principale initiale.

Voir le code principal dans wp-settings.

Le snippets utilise le hook wordpress template_redirect : il est défini dans wp-includes/template-loader.php.
Je l’aime bien parce qu’il est lancé une fois que la requête principale et les balises conditionnelles ont été entièrement configurées et avant l’action wp_head.
C’est vraiment l’endroit idéal pour installer des hooks qui géreront les conditions sur les principaux éléments de la requête.

//setup hooks in the template_redirect action => once the main WordPress query is set
add_action( 'template_redirect', 'hooks_setup' , 20 );
function hooks_setup() {
    if (! is_home() ) //<= you can also use any conditional tag here
        return;
    add_action( '__before_loop'     , 'set_my_query' );
    add_action( '__after_loop'      , 'set_my_query', 100 );
}
 
function set_my_query() {
    global $wp_query, $wp_the_query;
    switch ( current_filter() ) {
    	case '__before_loop':
    		//replace the current query by a custom query
		    //Note : the initial query is stored in another global named $wp_the_query
		    $wp_query = new WP_Query( array(
		    	'post_type'         => 'post',
				'post_status'       => 'publish',
		       //others parameters...
		    ) );
    	break;
 
    	default:
    		//back to the initial WP query stored in $wp_the_query
    		$wp_query = $wp_the_query;
    	break;
    }
}

Ces techniques s’adaptent facilement à de nombreux cas : types de postes personnalisés, taxonomies, champs personnalisés,….

Conclusion

Il existe de multitude de manières de surcharger une Query WordPress. Nous en avons listé 4 ensemble mais n’hésitez pas à me donner en commentaire vos techniques de surcharge de Query. Et dans tous les cas un petit retour sur les normes de codage WordPress ne fait jamais de mal 😉


siddhy

Développeur web full stack depuis une 15aine d'année dans une agence web du sud de la France et Geek depuis toujours, l'apprentissage et le partage font parti intégrante de ma philosophie au même titre que l'évolution personnelle et la sagesse bouddhiste.

2 commentaires

Greg · 14 juillet 2019 à 12 h 03 min

Merci de ce partage, notamment la gestion des hooks sur template_redirect

    siddhy · 15 juillet 2019 à 8 h 10 min

    Content que mon article ait pu te servir 😉

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *