Le problème
Par défaut, dans n'importe quel contexte, WordPress utilise la requête principale pour déterminer la pagination. L'objet de requête principal est stocké dans le $wp_query
global, qui est également utilisé pour générer la boucle de requête principale:
if ( have_posts() ) : while ( have_posts() ) : the_post();
Lorsque vous utilisez une requête personnalisée , vous créez un objet de requête entièrement séparé:
$custom_query = new WP_Query( $custom_query_args );
Et cette requête est sortie via une boucle entièrement séparée:
if ( $custom_query->have_posts() ) :
while ( $custom_query->have_posts() ) :
$custom_query->the_post();
Mais les balises de modèle, y compris de la pagination previous_posts_link()
, next_posts_link()
, posts_nav_link()
et paginate_links()
, la base de leur sortie sur le principal objet de requête , $wp_query
. Cette requête principale peut ou non être paginée. Si le contexte actuel est un modèle de page personnalisé, par exemple, l' $wp_query
objet principal ne sera composé que d'une seule publication , celle de l'ID de la page à laquelle le modèle de page personnalisé est affecté.
Si le contexte actuel est un index d'archive d'une certaine sorte, l' $wp_query
élément principal peut comporter suffisamment de publications pour provoquer la pagination, ce qui conduit à la partie suivante du problème: pour l' $wp_query
objet principal , WordPress passera un paged
paramètre à la requête, en fonction du paged
Variable de requête URL. Lorsque la requête est extraite, ce paged
paramètre sera utilisé pour déterminer quel ensemble de publications paginées à renvoyer. Si vous cliquez sur un lien de pagination affiché et que la page suivante est chargée, votre requête personnalisée n'aura aucun moyen de savoir que la pagination a été modifiée .
La solution
Passage du paramètre paginé correct à la requête personnalisée
En supposant que la requête personnalisée utilise un tableau args:
$custom_query_args = array(
// Custom query parameters go here
);
Vous devrez passer le paged
paramètre correct au tableau. Vous pouvez le faire en récupérant la variable de requête d'URL utilisée pour déterminer la page en cours, via get_query_var()
:
get_query_var( 'paged' );
Vous pouvez ensuite ajouter ce paramètre à votre tableau args de requête personnalisé:
$custom_query_args['paged'] = get_query_var( 'paged' )
? get_query_var( 'paged' )
: 1;
Remarque: Si votre page est une page de garde statique , veillez à l'utiliser page
au lieu d' utiliser paged
comme page de garde statique page
et non paged
. Voici ce que vous devriez avoir pour une page de garde statique
$custom_query_args['paged'] = get_query_var( 'page' )
? get_query_var( 'page' )
: 1;
Désormais, lorsque la requête personnalisée est extraite, l'ensemble correct des publications paginées est renvoyé.
Utilisation d'un objet de requête personnalisé pour les fonctions de pagination
Pour que les fonctions de pagination produisent le résultat correct, c'est-à-dire les liens précédent / suivant / page relatifs à la requête personnalisée, WordPress doit obligatoirement reconnaître la requête personnalisée. Cela nécessite un peu d'un « hack »: remplacer le principal $wp_query
objet avec l'objet de requête personnalisée, $custom_query
:
Pirater l'objet de requête principal
- Sauvegardez l'objet de requête principal:
$temp_query = $wp_query
- Null l'objet de requête principal:
$wp_query = NULL;
Échangez la requête personnalisée dans l'objet de requête principal: $wp_query = $custom_query;
$temp_query = $wp_query;
$wp_query = NULL;
$wp_query = $custom_query;
Ce "hack" doit être fait avant d'appeler une fonction de pagination
Réinitialiser l'objet de requête principal
Une fois les fonctions de pagination générées, réinitialisez l’objet de requête principal:
$wp_query = NULL;
$wp_query = $temp_query;
Corrections de la fonction de pagination
La previous_posts_link()
fonction fonctionnera normalement, quelle que soit la pagination. Il détermine simplement la page en cours, puis génère le lien pour page - 1
. Cependant, un correctif est requis pour next_posts_link()
pouvoir générer correctement. C'est parce que next_posts_link()
utilise le max_num_pages
paramètre:
<?php next_posts_link( $label , $max_pages ); ?>
Comme avec d'autres paramètres de requête, la fonction utilisera par défaut max_num_pages
pour l' $wp_query
objet principal . Afin de forcer next_posts_link()
à rendre compte de l' $custom_query
objet, vous devrez passer le max_num_pages
à la fonction. Vous pouvez extraire cette valeur de l' $custom_query
objet $custom_query->max_num_pages
:
<?php next_posts_link( 'Older Posts' , $custom_query->max_num_pages ); ?>
Mettre tous ensemble
Voici une construction de base d'une boucle de requête personnalisée avec des fonctions de pagination fonctionnant correctement:
// Define custom query parameters
$custom_query_args = array( /* Parameters go here */ );
// Get current page and append to custom query parameters array
$custom_query_args['paged'] = get_query_var( 'paged' ) ? get_query_var( 'paged' ) : 1;
// Instantiate custom query
$custom_query = new WP_Query( $custom_query_args );
// Pagination fix
$temp_query = $wp_query;
$wp_query = NULL;
$wp_query = $custom_query;
// Output custom query loop
if ( $custom_query->have_posts() ) :
while ( $custom_query->have_posts() ) :
$custom_query->the_post();
// Loop output goes here
endwhile;
endif;
// Reset postdata
wp_reset_postdata();
// Custom query loop pagination
previous_posts_link( 'Older Posts' );
next_posts_link( 'Newer Posts', $custom_query->max_num_pages );
// Reset main query object
$wp_query = NULL;
$wp_query = $temp_query;
Addendum: Qu'en est-il query_posts()
?
query_posts()
pour les boucles secondaires
Si vous utilisez query_posts()
la sortie d' une boucle personnalisée, plutôt instanciation alors un objet distinct pour la requête personnalisée via WP_Query()
, alors vous êtes _doing_it_wrong()
, et se déroulera en plusieurs problèmes (pas moins de ce qui sera des questions paginations). La première étape pour résoudre ces problèmes consistera à convertir l'utilisation inappropriée de query_posts()
en un WP_Query()
appel approprié .
Utiliser query_posts()
pour modifier la boucle principale
Si vous souhaitez simplement modifier les paramètres de la requête de la boucle principale , par exemple modifier les publications par page ou exclure une catégorie, vous pouvez être tenté de l’utiliser query_posts()
. Mais vous ne devriez toujours pas. Lorsque vous utilisez query_posts()
, vous forcez WordPress à remplacer l'objet de requête principal. (WordPress effectue en réalité une deuxième requête et écrase $wp_query
.) Le problème, cependant, est qu'il effectue ce remplacement trop tard dans le processus pour mettre à jour la pagination.
La solution consiste à filtrer la requête principale avant que les publications ne soient récupérées , via le pre_get_posts
hook.
Au lieu de l'ajouter au fichier de modèle de catégorie ( category.php
):
query_posts( array(
'posts_per_page' => 5
) );
Ajoutez ce qui suit à functions.php
:
function wpse120407_pre_get_posts( $query ) {
// Test for category archive index
// and ensure that the query is the main query
// and not a secondary query (such as a nav menu
// or recent posts widget output, etc.
if ( is_category() && $query->is_main_query() ) {
// Modify posts per page
$query->set( 'posts_per_page', 5 );
}
}
add_action( 'pre_get_posts', 'wpse120407_pre_get_posts' );
Au lieu d’ajouter ceci au fichier de modèle d’index des articles de blog ( home.php
):
query_posts( array(
'cat' => '-5'
) );
Ajoutez ce qui suit à functions.php
:
function wpse120407_pre_get_posts( $query ) {
// Test for main blog posts index
// and ensure that the query is the main query
// and not a secondary query (such as a nav menu
// or recent posts widget output, etc.
if ( is_home() && $query->is_main_query() ) {
// Exclude category ID 5
$query->set( 'category__not_in', array( 5 ) );
}
}
add_action( 'pre_get_posts', 'wpse120407_pre_get_posts' );
De cette façon, WordPress utilisera l' $wp_query
objet déjà modifié lors de la détermination de la pagination, sans aucune modification de modèle.
Quand utiliser quelle fonction
La recherche de cette question et la réponse et cette question et la réponse à comprendre comment et quand utiliser WP_Query
, pre_get_posts
et query_posts()
.