El problema
Por defecto, en cualquier contexto dado, WordPress usa la consulta principal para determinar la paginación. El objeto de consulta principal se almacena en el $wp_query
global, que también se utiliza para generar el bucle de consulta principal:
if ( have_posts() ) : while ( have_posts() ) : the_post();
Cuando utiliza una consulta personalizada , crea un objeto de consulta completamente separado:
$custom_query = new WP_Query( $custom_query_args );
Y esa consulta se genera a través de un bucle completamente separado:
if ( $custom_query->have_posts() ) :
while ( $custom_query->have_posts() ) :
$custom_query->the_post();
Pero etiquetas de plantilla de paginación, incluyendo previous_posts_link()
, next_posts_link()
, posts_nav_link()
, y paginate_links()
, basan su producción en el principal objeto de consulta , $wp_query
. Esa consulta principal puede o no ser paginada. Si el contexto actual es una plantilla de página personalizada, por ejemplo, el $wp_query
objeto principal consistirá en una sola publicación : la ID de la página a la que se asigna la plantilla de página personalizada.
Si el contexto actual es un índice de archivo de algún tipo, el principal $wp_query
puede consistir en suficientes publicaciones para causar paginación, lo que lleva a la siguiente parte del problema: para el $wp_query
objeto principal , WordPress pasará un paged
parámetro a la consulta, basado en el paged
Variable de consulta de URL. Cuando se recupera la consulta, ese paged
parámetro se usará para determinar qué conjunto de publicaciones paginadas devolver. Si se hace clic en un enlace de paginación mostrado y se carga la siguiente página, su consulta personalizada no tendrá forma de saber que la paginación ha cambiado .
La solución
Pasar el parámetro paginado correcto a la consulta personalizada
Suponiendo que la consulta personalizada utiliza una matriz de argumentos:
$custom_query_args = array(
// Custom query parameters go here
);
Deberá pasar el paged
parámetro correcto a la matriz. Puede hacerlo buscando la variable de consulta de URL utilizada para determinar la página actual, a través de get_query_var()
:
get_query_var( 'paged' );
Luego puede agregar ese parámetro a su matriz de argumentos de consulta personalizada:
$custom_query_args['paged'] = get_query_var( 'paged' )
? get_query_var( 'paged' )
: 1;
Nota: Si su página es una portada estática , asegúrese de usarla en page
lugar de paged
como usa una portada estática page
y no paged
. Esto es lo que debe tener para una portada estática
$custom_query_args['paged'] = get_query_var( 'page' )
? get_query_var( 'page' )
: 1;
Ahora, cuando se recupera la consulta personalizada, se devolverá el conjunto correcto de publicaciones paginadas.
Uso de objetos de consulta personalizados para funciones de paginación
Para que las funciones de paginación produzcan el resultado correcto, es decir, enlaces anteriores / siguientes / de página relacionados con la consulta personalizada, WordPress debe verse obligado a reconocer la consulta personalizada. Esto requiere un poco de un "hack": reemplazar el principal $wp_query
objeto con el objeto de consulta personalizada, $custom_query
:
Hackear el objeto de consulta principal
- Copia de seguridad del objeto de consulta principal:
$temp_query = $wp_query
- Anula el objeto de consulta principal:
$wp_query = NULL;
Intercambie la consulta personalizada en el objeto de consulta principal: $wp_query = $custom_query;
$temp_query = $wp_query;
$wp_query = NULL;
$wp_query = $custom_query;
Este "hack" debe hacerse antes de llamar a cualquier función de paginación
Restablecer el objeto de consulta principal
Una vez que se han generado las funciones de paginación, restablezca el objeto de consulta principal:
$wp_query = NULL;
$wp_query = $temp_query;
Correcciones de funciones de paginación
La previous_posts_link()
función funcionará normalmente, independientemente de la paginación. Simplemente determina la página actual y luego genera el enlace para page - 1
. Sin embargo, se requiere una solución para next_posts_link()
que salga correctamente. Esto se debe a que next_posts_link()
usa el max_num_pages
parámetro:
<?php next_posts_link( $label , $max_pages ); ?>
Al igual que con otros parámetros de consulta, por defecto la función se usará max_num_pages
para el $wp_query
objeto principal . Para forzar next_posts_link()
a dar cuenta del $custom_query
objeto, deberá pasarlo max_num_pages
a la función. Puede obtener este valor del $custom_query
objeto $custom_query->max_num_pages
::
<?php next_posts_link( 'Older Posts' , $custom_query->max_num_pages ); ?>
Poniendolo todo junto
La siguiente es una construcción básica de un bucle de consulta personalizado con funciones de paginación que funcionan correctamente:
// 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;
Anexo: ¿Qué pasa query_posts()
?
query_posts()
para bucles secundarios
Si está utilizando query_posts()
a la salida de un bucle de encargo, en lugar de crear instancias de un objeto separado para la consulta personalizada a través de WP_Query()
, a continuación, usted es _doing_it_wrong()
, y se encontrará con varios problemas (no al menos, de los cuales serán cuestiones de paginación). El primer paso para resolver esos problemas será convertir el uso inadecuado de query_posts()
una WP_Query()
llamada adecuada .
Usar query_posts()
para modificar el bucle principal
Si simplemente desea modificar los parámetros para la consulta del bucle principal , como cambiar las publicaciones por página o excluir una categoría, puede tener la tentación de usarla query_posts()
. Pero aún no deberías. Cuando lo usas query_posts()
, obligas a WordPress a reemplazar el objeto de consulta principal. (WordPress en realidad hace una segunda consulta y la sobrescribe $wp_query
). Sin embargo, el problema es que hace este reemplazo demasiado tarde en el proceso para actualizar la paginación.
La solución es filtrar la consulta principal antes de recuperar las publicaciones , a través del pre_get_posts
gancho.
En lugar de agregar esto al archivo de plantilla de categoría ( category.php
):
query_posts( array(
'posts_per_page' => 5
) );
Agregue lo siguiente a 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' );
En lugar de agregar esto al archivo de plantilla de índice de publicaciones de blog ( home.php
):
query_posts( array(
'cat' => '-5'
) );
Agregue lo siguiente a 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 esa manera, WordPress usará el $wp_query
objeto ya modificado al determinar la paginación, sin necesidad de modificar la plantilla.
Cuándo usar qué función
La investigación esta pregunta y respuesta , y esta pregunta y respuesta para entender cómo y cuándo usar WP_Query
, pre_get_posts
y query_posts()
.