Saltar al contenido

Wordpress – ¿Cómo arreglar la paginación para bucles personalizados?

Hola usuario de nuestra web, hallamos la respuesta a tu interrogante, has scroll y la obtendrás un poco más abajo.

Solución:

El problema

De forma predeterminada, 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 independiente:

$custom_query = new WP_Query( $custom_query_args );

Y esa consulta se emite a través de un bucle completamente separado:

if ( $custom_query->have_posts() ) : 
    while ( $custom_query->have_posts() ) : 
        $custom_query->the_post();

Pero las etiquetas de plantilla de paginación, incluidas previous_posts_link(), next_posts_link(), posts_nav_link(), y paginate_links(), basan su salida en el objeto de consulta principal, $wp_query. Esa consulta principal puede estar paginada o no. Si el contexto actual es una plantilla de página personalizada, por ejemplo, la $wp_query El objeto consistirá solo en un publicación única – el del ID de la página a la que está asignada 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 la paginación, lo que lleva a la siguiente parte del problema: para la $wp_query objeto, WordPress pasará un paged parámetro a la consulta, basado en el paged Variable de consulta de URL. Cuando se recupera la consulta, paged El parámetro se utilizará para determinar qué conjunto de publicaciones paginadas devolver. Si se hace clic en un enlace de paginación mostrado y se carga la página siguiente, 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 usa una matriz de argumentos:

$custom_query_args = array(
    // Custom query parameters go here
);

Deberá pasar la correcta paged parámetro a la matriz. Puede hacerlo obteniendo 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 usar page en lugar de paged como una portada estática utiliza page y no paged. Esto es lo que debería tener para una portada estática

$custom_query_args['paged'] = get_query_var( 'page' ) 
    ? get_query_var( 'page' ) 
    : 1;

Ahora, cuando se obtenga 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 de página anterior / siguiente en relación con la consulta personalizada, WordPress debe estar obligado a reconocer la consulta personalizada. Esto requiere un poco de “truco”: reemplazar el principal $wp_query objeto con el objeto de consulta personalizado, $custom_query:

Hackear el objeto de consulta principal

  1. Haga una copia de seguridad del objeto de consulta principal: $temp_query = $wp_query
  2. Nulo el objeto de consulta principal: $wp_query = NULL;
  3. Cambie la consulta personalizada al objeto de consulta principal: $wp_query = $custom_query;

    $temp_query = $wp_query;
    $wp_query   = NULL;
    $wp_query   = $custom_query;
    

Este “truco” debe hacerse antes de llamar a cualquier función de paginación

Restablecer el objeto de consulta principal

Una vez que se hayan generado las funciones de paginación, restablezca el objeto de consulta principal:

$wp_query = NULL;
$wp_query = $temp_query;

Correcciones de la función de paginación

los previous_posts_link() La 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 corrección para next_posts_link() para generar correctamente. Esto es porque next_posts_link() usa el max_num_pages parámetro:


Al igual que con otros parámetros de consulta, de forma predeterminada, la función utilizará max_num_pages para el principal $wp_query objeto. Para forzar next_posts_link() para dar cuenta de la $custom_query objeto, tendrá que pasar el max_num_pages a la función. Puede obtener este valor del $custom_query objeto: $custom_query->max_num_pages:

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 con query_posts()?

query_posts() para bucles secundarios

Si estas usando query_posts() para generar un bucle personalizado, en lugar de crear una instancia de un objeto separado para la consulta personalizada a través de WP_Query()entonces eres _doing_it_wrong(), y se encontrará con varios problemas (no el menos de los cuales serán problemas de paginación). El primer paso para resolver esos problemas será convertir el uso indebido de query_posts() a un adecuado WP_Query() llama.

Utilizando query_posts() para modificar el bucle principal

Si simplemente desea modificar los parámetros del consulta del bucle principal – como cambiar las publicaciones por página o excluir una categoría – puede tener la tentación de usar query_posts(). Pero aún no deberías. Cuando usas query_posts(), obligas a WordPress a reemplazar el objeto de consulta principal. (WordPress en realidad hace una segunda consulta y sobrescribe $wp_query.) El problema, sin embargo, es que hace este reemplazo demasiado tarde en el proceso para actualizar la paginación.

La solucion es filtrar la consulta principal antes de que se obtengan las publicaciones, mediante el 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 del 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 ya modificado $wp_query objeto al determinar la paginación, sin necesidad de modificar la plantilla.

Cuando usar que función

Investigue esta pregunta y respuesta y esta pregunta y respuesta para comprender cómo y cuándo usar WP_Query, pre_get_posts, y query_posts().

Utilizo este código para un bucle personalizado con paginación:

 'post', 
    'posts_per_page' => get_option('posts_per_page'),
    'paged' => $paged,
    'post_status' => 'publish',
    'ignore_sticky_posts' => true,
    //'category_name' => 'custom-cat',
    'order' => 'DESC', // 'ASC'
    'orderby' => 'date' // modified | title | name | ID | rand
);
$custom_query = new WP_Query( $custom_query_args );

if ( $custom_query->have_posts() ) :
    while( $custom_query->have_posts() ) : $custom_query->the_post(); ?>

        

    

    max_num_pages > 1) : // custom pagination  ?>
        
        
        
    

'.__('Sorry, no posts matched your criteria.').'

'; endif; ?>

Fuente:

  • Bucle personalizado de WordPress con paginación

Impresionante como siempre Chip. Como apéndice 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 va seguida de una subconsulta que desea que se pague.

Usando paginate_links () como mencionaste anteriormente, con la mayoría de los valores predeterminados, (y asumiendo que tienes bonitos enlaces permanentes activados) tus enlaces de paginación serán predeterminados. mysite.ca/page-slug/page/# que es encantador pero arrojará 404 errores porque WordPress no conoce esa estructura de URL en particular y de hecho buscará una página secundaria de “page” que sea hija de “page-slug”.

El truco aquí es insertar una regla de reescritura ingeniosa que solo se aplique a esa página de “pseudo página de archivo” en particular que acepta la /page/#/ estructura y la reescribe en una cadena de consulta que WordPress PUEDE entender, a saber mysite.ca/?pagename=page-slug&paged=#. Nota pagename y paged no name y page (¡lo que me causó literalmente HORAS de dolor, lo que motivó esta respuesta aquí!).

Aquí está la regla de redireccionamiento:

add_rewrite_rule( "page-slug/page/([0-9]1,)/?$", 'index.php?pagename=page-slug&paged=$matches[1]', "top" );

Como siempre, al cambiar las reglas de reescritura, recuerde enjuague sus enlaces permanentes visitando Configuración> Enlaces permanentes en el back-end del administrador.

Si tiene varias páginas que se comportarán de esta manera (por ejemplo, cuando se trata de varios tipos de publicaciones personalizadas), es posible que desee evitar la creación de una nueva regla de reescritura para cada slug de página. Podemos escribir una expresión regular más genérica que funcione para cualquier slug de página que identifique.

Un enfoque es el siguiente:

function wpse_120407_pseudo_archive_rewrite()", $pseudo_archive_pages );
    add_rewrite_rule( "($slug_clause)/page/([0-9]1,)/?$", 'index.php?pagename=$matches[1]&paged=$matches[2]', "top" );

add_action( 'init', 'wpse_120407_pseudo_archive_rewrite' );

Desventajas / Advertencias

Una desventaja de este enfoque que me hace vomitar un poco en la boca es la codificación rígida de la babosa Page. Si un administrador alguna vez cambia el slug de la página de esa página de pseudoarchivo, estás listo: 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 si fuera la plantilla de página global la que de alguna manera activara la regla de reescritura. Algún día puedo volver a revisar esta respuesta si nadie más ha roto esa nuez en particular.

Si te apasiona la programación, tienes la habilidad dejar una sección acerca de qué te ha parecido esta sección.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *