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()
.
paged
não estava sendo atualizado (obv algo a ver com o administrador- (ajax.php)), então eu adicionei isso:global $paged; $paged = $custom_query_args['paged'];
e funcionou :)Eu uso esse código para loop personalizado com paginação:
Fonte:
fonte
Incrível como sempre Chip. Como um adendo, considere a situação em que você está usando um modelo de página global anexado a uma Página para algum "texto de introdução" e é seguido por uma subconsulta que você deseja que seja paginada.
Usando paginate_links () como você mencionou acima, com a maioria dos padrões (e supondo que você tenha permalinks bastante ativados), seus links de paginação serão padronizados, o
mysite.ca/page-slug/page/#
que é adorável, mas gerará404
erros porque o WordPress não conhece essa estrutura de URL específica e realmente procure uma página filha de "página" que seja filha de "página-lesma".O truque aqui é inserir uma regra de reescrita bacana que se aplique apenas àquela lesma de página "pseudo archive page" que aceita a
/page/#/
estrutura e a reescreve em uma string de consulta que o WordPress PODE entender, a sabermysite.ca/?pagename=page-slug&paged=#
. Notepagename
epaged
nãoname
epage
(o que me causou literalmente HORAS de tristeza, motivando esta resposta aqui!).Aqui está a regra de redirecionamento:
Como sempre, ao alterar as regras de reescrita, lembre-se de liberar seus links permanentes visitando Configurações> Links permanentes no back-end do administrador.
Se você tiver várias páginas que se comportarão dessa maneira (por exemplo, ao lidar com vários tipos de postagem personalizados), convém evitar a criação de uma nova regra de reescrita para cada slug de página. Podemos escrever uma expressão regular mais genérica que funcione para qualquer página lesada que você identificar.
Uma abordagem está abaixo:
Desvantagens / Advertências
Uma desvantagem dessa abordagem que me faz vomitar um pouco na boca é a codificação da lesma da página. Se um administrador alterar a lesma de página dessa página de pseudo-arquivo, você está brindando - a regra de reescrita não será mais correspondente e você obterá o temido 404.
Não sei se consigo pensar em uma solução alternativa para esse método, mas seria bom se fosse o modelo de página global que de alguma forma acionou a regra de reescrita. Algum dia, posso revisitar essa resposta se ninguém mais tiver quebrado essa noz em particular.
fonte
_wp_page_template
e adicionar outras regras de reescrita e liberação.Ótima resposta que o Chip criado precisa ser modificado hoje.
Por algum tempo, temos
$wp_the_query
variáveis que devem ser iguais à$wp_query
global logo após a execução da consulta principal.É por isso que esta é a parte da resposta do Chip:
não é mais necessário. Podemos esquecer esta parte ao criar a variável temporária.
Então agora podemos ligar para:
ou melhor ainda, podemos chamar:
Tudo o que Chip descreveu permanece. Após essa consulta-redefinir-parte, você pode chamar as funções de paginação que são
f($wp_query)
, - elas dependem de$wp_query
global.Para melhorar ainda mais a mecânica da paginação e dar mais liberdade à
query_posts
função, criei esta possível melhoria:https://core.trac.wordpress.org/ticket/39483
fonte
fonte