O problema
Por padrão, em qualquer contexto, o WordPress usa a consulta principal para determinar a paginação. O objeto de consulta principal é armazenado no $wp_query
global, que também é usado para gerar o loop de consulta principal:
if ( have_posts() ) : while ( have_posts() ) : the_post();
Ao usar uma consulta personalizada , você cria um objeto de consulta totalmente separado:
$custom_query = new WP_Query( $custom_query_args );
E essa consulta é emitida através de um loop totalmente separado:
if ( $custom_query->have_posts() ) :
while ( $custom_query->have_posts() ) :
$custom_query->the_post();
Mas template tags pagination, incluindo previous_posts_link()
, next_posts_link()
, posts_nav_link()
, e paginate_links()
, baseiam a sua saída no objeto de consulta principal , $wp_query
. Essa consulta principal pode ou não ser paginada. Se o contexto atual for um modelo de página personalizado, por exemplo, o $wp_query
objeto principal consistirá em apenas uma única postagem - a do ID da página à qual o modelo de página personalizado está atribuído.
Se o contexto atual for um índice de arquivo de algum tipo, o principal $wp_query
poderá consistir em postagens suficientes para causar paginação, o que leva à próxima parte do problema: para o $wp_query
objeto principal , o WordPress passará um paged
parâmetro para a consulta, com base no paged
Variável de consulta de URL. Quando a consulta é buscada, esse paged
parâmetro será usado para determinar qual conjunto de postagens paginadas retornar. Se um link de paginação exibido for clicado e a próxima página carregada, sua consulta personalizada não terá como saber que a paginação foi alterada .
A solução
Passando o parâmetro paginado correto para a consulta personalizada
Supondo que a consulta personalizada use uma matriz args:
$custom_query_args = array(
// Custom query parameters go here
);
Você precisará passar o paged
parâmetro correto para a matriz. Você pode fazer isso buscando a variável de consulta da URL usada para determinar a página atual, via get_query_var()
:
get_query_var( 'paged' );
Em seguida, você pode anexar esse parâmetro à sua matriz de argumentos de consulta personalizada:
$custom_query_args['paged'] = get_query_var( 'paged' )
? get_query_var( 'paged' )
: 1;
Nota: Se a sua página for uma página estática , certifique-se de usá-la, e page
não paged
como a página inicial estática page
e não paged
. Isto é o que você deve ter para uma primeira página estática
$custom_query_args['paged'] = get_query_var( 'page' )
? get_query_var( 'page' )
: 1;
Agora, quando a consulta personalizada for buscada, o conjunto correto de postagens paginadas será retornado.
Usando objeto de consulta personalizado para funções de paginação
Para que as funções de paginação produzam a saída correta - por exemplo, links anterior / seguinte / página relativos à consulta personalizada - o WordPress precisa ser forçado a reconhecer a consulta personalizada. Isso requer um pouco de um "hack": substituindo o principal $wp_query
objeto com o objeto de consulta personalizada, $custom_query
:
Hackear o objeto de consulta principal
- Faça backup do objeto de consulta principal:
$temp_query = $wp_query
- Anule o objeto de consulta principal:
$wp_query = NULL;
Troque a consulta personalizada no objeto de consulta principal: $wp_query = $custom_query;
$temp_query = $wp_query;
$wp_query = NULL;
$wp_query = $custom_query;
Este "hack" deve ser feito antes de chamar qualquer função de paginação
Redefinir o objeto de consulta principal
Após a saída das funções de paginação, redefina o objeto de consulta principal:
$wp_query = NULL;
$wp_query = $temp_query;
Correções da função de paginação
A previous_posts_link()
função funcionará normalmente, independentemente da paginação. Apenas determina a página atual e, em seguida, gera o link para page - 1
. No entanto, é necessária uma correção para next_posts_link()
a saída correta. Isso ocorre porque next_posts_link()
usa o max_num_pages
parâmetro:
<?php next_posts_link( $label , $max_pages ); ?>
Como com outros parâmetros de consulta, por padrão, a função será usada max_num_pages
para o $wp_query
objeto principal . Para forçar next_posts_link()
a contabilizar o $custom_query
objeto, você precisará passar o max_num_pages
para a função. Você pode buscar esse valor no $custom_query
objeto $custom_query->max_num_pages
:
<?php next_posts_link( 'Older Posts' , $custom_query->max_num_pages ); ?>
Juntando tudo
A seguir, é apresentada uma construção básica de um loop de consulta personalizado com funções de paginação funcionando corretamente:
// 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;
Adendo: Sobre o quê query_posts()
?
query_posts()
para loops secundários
Se você estiver usando query_posts()
para gerar um loop personalizado, em vez de instanciar um objeto separado para a consulta personalizada por meio de WP_Query()
, então você estará _doing_it_wrong()
e terá vários problemas ( dos quais o menor será problemas de paginação). O primeiro passo para resolver esses problemas será converter o uso inadequado de query_posts()
em uma WP_Query()
chamada adequada .
Usando query_posts()
para modificar o loop principal
Se você deseja apenas modificar os parâmetros para a consulta de loop principal - como alterar as postagens por página ou excluir uma categoria -, você pode se sentir tentado a usá-lo query_posts()
. Mas você ainda não deveria. Ao usar query_posts()
, você força o WordPress a substituir o objeto de consulta principal. (O WordPress realmente faz uma segunda consulta e sobrescreve $wp_query
.) O problema, porém, é que ele faz essa substituição tarde demais no processo para atualizar a paginação.
A solução é filtrar a consulta principal antes que as postagens sejam buscadas , através do pre_get_posts
gancho.
Em vez de adicionar isso ao arquivo de modelo de categoria ( category.php
):
query_posts( array(
'posts_per_page' => 5
) );
Adicione o seguinte 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' );
Em vez de adicionar isso ao arquivo de modelo de índice de postagens do blog ( home.php
):
query_posts( array(
'cat' => '-5'
) );
Adicione o seguinte 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' );
Dessa forma, o WordPress usará o $wp_query
objeto já modificado ao determinar a paginação, sem necessidade de modificação de modelo.
Quando usar qual função
Pesquisa esta pergunta e resposta e esta pergunta e resposta para compreender como e quando usar WP_Query
, pre_get_posts
e query_posts()
.