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()
.
paged
fichier global n’était pas mis à jour (quelque chose à voir avec admin- ajax.php environment) donc j’ai ajouté ceci:global $paged; $paged = $custom_query_args['paged'];
et cela a fonctionné :)J'utilise ce code pour une boucle personnalisée avec pagination:
La source:
la source
Génial comme toujours Chip. En tant qu'additif à ceci, considérons la situation dans laquelle vous utilisez un modèle de page global attaché à une page pour un "texte d'introduction" suivi d'une sous-requête que vous souhaitez paginer.
En utilisant paginate_links () comme vous le dites ci-dessus, avec la plupart des valeurs par défaut (et en supposant que vous ayez de jolis permaliens activés), vos liens de pagination seront par défaut
mysite.ca/page-slug/page/#
très jolis, mais généreront des404
erreurs car WordPress ne connaît pas cette structure d'URL particulière et cherche une page enfant de "page" qui est un enfant de "page-slug".L'astuce consiste ici à insérer une règle de réécriture astucieuse qui s'applique uniquement à ce slug de page "pseudo archive" qui accepte la
/page/#/
structure et la réécrit en une chaîne de requête que WordPress peut comprendre, à savoirmysite.ca/?pagename=page-slug&paged=#
. Notezpagename
etpaged
nonname
etpage
(ce qui m'a littéralement causé des HEURES de chagrin, motivant cette réponse ici!).Voici la règle de redirection:
Comme toujours, lorsque vous modifiez les règles de réécriture, n'oubliez pas de vider vos permaliens en accédant à Paramètres> Permaliens dans le back-end de l'administrateur.
Si vous avez plusieurs pages qui vont se comporter de cette manière (par exemple, lorsque vous traitez avec plusieurs types de publication personnalisés), vous pouvez éviter de créer une nouvelle règle de réécriture pour chaque slug de page. Nous pouvons écrire une expression régulière plus générique qui fonctionne pour n'importe quel slug de page que vous identifiez.
Une approche est ci-dessous:
Inconvénients / mises en garde
Un inconvénient de cette approche qui me fait vomir un peu dans la bouche est le codage en dur de la limace de page. Si un administrateur change jamais le slug de page de cette page de pseudo-archive, vous êtes grillé - la règle de réécriture ne correspond plus et vous obtenez le redoutable 404.
Je ne suis pas sûr de pouvoir imaginer une solution de contournement pour cette méthode, mais ce serait bien si c'était le modèle de page global qui avait déclenché la règle de réécriture. Un jour, je pourrai revoir cette réponse si personne d'autre n'a réussi à percer ce problème.
la source
_wp_page_template
, puis ajouter une autre règle de réécriture et de vidage.Excellente réponse La puce créée doit être modifiée aujourd'hui.
Pendant un certain temps, nous avons une
$wp_the_query
variable qui devrait être égale à la variable$wp_query
globale juste après l'exécution de la requête principale.C'est pourquoi cette partie de la réponse de la puce:
n'est plus nécessaire. Nous pouvons oublier cette partie avec la création de la variable temporaire.
Alors maintenant, nous pouvons appeler:
ou mieux encore, nous pouvons appeler:
Tout ce que Chip décrit ci-dessus reste. Après cette partie de réinitialisation de requête, vous pouvez appeler les fonctions de pagination qui sont
f($wp_query)
, elles dépendent de$wp_query
global.Afin d'améliorer encore les mécanismes de pagination et de donner plus de liberté à la
query_posts
fonction, j'ai créé cette amélioration possible:https://core.trac.wordpress.org/ticket/39483
la source
la source