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()
.
paged
búsqueda rápida descubrí que el global no se estaba actualizando (obviamente algo que tiene que ver con admin- ajax.php) así que agregué esto:global $paged; $paged = $custom_query_args['paged'];
y funcionó :)Yo uso este código para bucle personalizado con paginación:
Fuente:
fuente
Impresionante como siempre Chip. Como anexo a esto, considere la situación en la que está utilizando una plantilla de página global adjunta a una página para algún "texto de introducción" y le sigue una subconsulta que desea que se pagine.
Usando paginate_links () como mencionó anteriormente, con la mayoría de los valores predeterminados (y suponiendo que tenga los enlaces permanentes activados), sus enlaces de paginación estarán predeterminados, lo
mysite.ca/page-slug/page/#
cual es encantador, pero arrojará404
errores porque WordPress no conoce esa estructura URL particular y realmente busque una página secundaria de "página" que sea secundaria de "page-slug".El truco aquí es insertar una ingeniosa regla de reescritura que solo se aplica a esa ficha de página de "pseudo archivo" particular que acepta la
/page/#/
estructura y la reescribe en una cadena de consulta que WordPress PUEDE entender, a sabermysite.ca/?pagename=page-slug&paged=#
. Notapagename
ypaged
noname
ypage
(¡lo que me causó literalmente HORAS de dolor, motivando esta respuesta aquí!).Aquí está la regla de redireccionamiento:
Como siempre, al cambiar las reglas de reescritura, recuerde eliminar sus enlaces permanentes visitando Configuración> Enlaces permanentes en el back-end de Admin.
Si tiene varias páginas que se comportarán de esta manera (por ejemplo, cuando se trata de múltiples tipos de publicaciones personalizadas), es posible que desee evitar crear una nueva regla de reescritura para cada ficha de página. Podemos escribir una expresión regular más genérica que funcione para cualquier babosa de página que identifique.
Un enfoque está abajo:
Desventajas / Advertencias
Una desventaja de este enfoque que me hace vomitar un poco en mi boca es la codificación dura de la babosa de la página. Si un administrador alguna vez cambia el slug de la página de esa página de pseudoarchivo, eres tostado: la regla de reescritura ya no coincidirá y obtendrás el temido 404.
No estoy seguro de poder pensar en una solución alternativa para este método, pero sería bueno que fuera la plantilla de página global la que activara la regla de reescritura. Algún día podría volver a visitar esta respuesta si nadie más ha roto esa tuerca en particular.
fuente
_wp_page_template
, luego agregar otras reglas de reescritura y vaciado.Gran respuesta Chip creado debe modificarse hoy.
Durante algún tiempo tenemos una
$wp_the_query
variable que debería ser igual a la$wp_query
global justo después de que se ejecute la consulta principal.Es por eso que esta es la parte de la respuesta del Chip:
Ya no es necesario. Podemos olvidar esta parte con la creación de la variable temporal.
Entonces ahora podemos llamar:
o incluso mejor podemos llamar:
Todo lo demás que Chip describió se queda. Después de esa parte de consulta-restablecimiento, puede llamar a las funciones de paginación que son
f($wp_query)
, dependen de$wp_query
global.Para mejorar aún más la mecánica de paginación y dar más libertad a la
query_posts
función, creé esta posible mejora:https://core.trac.wordpress.org/ticket/39483
fuente
fuente