Eu li @nacin “s Você não sabe o Query ontem e foi enviado por uma pequena toca de coelho. Antes de ontem, eu estava (incorretamente) usando query_posts()
para todas as minhas necessidades de consulta. Agora, sou um pouco mais sábio sobre o uso de WP_Query()
, mas ainda tenho algumas áreas cinzentas.
O que acho que sei com certeza:
Se eu “estiver tornando adicional faz loops em qualquer lugar da página – na barra lateral, no rodapé, em qualquer tipo de “postagens relacionadas”, etc. – eu quero usar WP_Query()
. Posso usar isso repetidamente em uma única página sem nenhum dano. (direita?).
O que não sei ao certo
- Quando devo usar @nacin “s
pre_get_posts
vs.WP_Query()
? Devo usarpre_get_posts
para tudo agora? - Quando eu quiser modificar o loop em uma página de modelo – digamos que eu queira modificar uma página de arquivo de taxonomia – eu removo a parte
if have_posts : while have_posts : the_post
e escrevo meu possuirWP_Query()
? Ou modifico a saída usandopre_get_posts
em meu arquivo functions.php?
tl; dr
As regras tl; dr Eu “gostaria de extrair disso:
- Nunca use
query_posts
mais - Ao executar várias consultas em uma única página, use
WP_Query()
- Ao modificar um loop, faça isso __________________.
Obrigado por qualquer sabedoria
Terry
ps: Eu vi e li: Quando você deve usar WP_Query vs query_posts () vs get_posts ()? O que adiciona outra dimensão – get_posts
. Mas não lida com pre_get_posts
de forma alguma .
Comentários
- Possível duplicata de Quando você deve usar WP_Query vs query_posts () vs get_posts ( )?
- @saltcod, agora é diferente, o WordPress evoluiu, adicionei alguns comentários em comparação com a resposta aceita aqui .
Resposta
Você está certo em dizer:
Nunca use
query_posts
mais
pre_get_posts
pre_get_posts
é um filtro para alterar qualquer consulta. É mais frequentemente usado para alterar apenas a “consulta principal”:
add_action("pre_get_posts","wpse50761_alter_query"); function wpse50761_alter_query($query){ if( $query->is_main_query() ){ //Do something to main query } }
(Eu também verificaria se is_admin()
retorna falso – embora isso possa ser redundante.). A consulta principal aparece em seus modelos como:
if( have_posts() ): while( have_posts() ): the_post(); //The loop endwhile; endif;
Se você sentir necessidade de editar este loop – use pre_get_posts
. ou seja, se você ficar tentado a usar query_posts()
– use pre_get_posts
em vez disso.
WP_Query
A consulta principal é uma instância importante de um WP_Query object
. O WordPress usa para decidir qual modelo usar, por exemplo, e quaisquer argumentos passados no url (por exemplo, paginação) são todos canalizados para aquela instância do objeto WP_Query
.
Para loops secundários (por exemplo, em barras laterais ou listas de “postagens relacionadas”), você “desejará criar sua própria instância separada do objeto WP_Query
. Por exemplo,
$my_secondary_loop = new WP_Query(...); if( $my_secondary_loop->have_posts() ): while( $my_secondary_loop->have_posts() ): $my_secondary_loop->the_post(); //The secondary loop endwhile; endif; wp_reset_postdata();
Aviso wp_reset_postdata();
– isso ocorre porque o loop secundário substituirá o $post
variável que identifica o “post atual”. Isso essencialmente redefine isso para o $post
em que estamos.
get_posts ()
Este é essencialmente um wrapper para uma instância separada de um objeto WP_Query
. Isso retorna uma matriz de objetos de postagem. Os métodos usados no loop acima não estão mais disponíveis para você. Este isn ” ta “Loop”, simplesmente uma matriz de objeto de postagem.
<ul> <?php global $post; $args = array( "numberposts" => 5, "offset"=> 1, "category" => 1 ); $myposts = get_posts( $args ); foreach( $myposts as $post ) : setup_postdata($post); ?> <li><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></li> <?php endforeach; wp_reset_postdata(); ?> </ul>
Em resposta às suas perguntas
- Use
pre_get_posts
para alterar sua consulta principal. Use um objetoWP_Query
separado (método 2) para loops secundários nas páginas de modelo. - Se você deseja alterar a consulta do loop principal, use
pre_get_posts
.
Comentários
- Então, há algum cenário em que alguém vá direto para get_posts () em vez de WP_Query?
- @drtanz – sim. Digamos, por exemplo, que você não ‘ precise de paginação ou de postagens fixas no topo – nesses casos,
get_posts()
é mais eficiente. - Mas não ‘ isso adicionaria uma consulta extra onde poderíamos apenas modificar pre_get_posts para modificar a consulta principal?
- @drtanz – você não ‘ não use
get_posts()
para a consulta principal – é para consultas secundárias. - @StephenHarris Right =) Se você usar next_post () no objeto em vez de usar the_post, você não ‘ pisa na consulta global e não ‘ não precisa se lembrar de use wp_reset_postdata depois.
Resposta
Existem dois contextos diferentes para loops:
- main loop que acontece com base na solicitação de URL e é processado antes que os modelos sejam carregados
- secundário
loops que acontecem de qualquer outra forma, chamados de arquivos de modelo ou de outra forma
Problema com query_posts()
é que é um laço secundário que tenta ser o principal e falha miseravelmente. Portanto, esqueça que existe.
Para modificar o loop principal
- não use
query_posts()
- use
pre_get_posts
filtro com$query->is_main_query()
verificar - alternativamente use
request
filtro ( um pouco grosseiro, então acima é melhor)
Para executar o loop secundário
Use new WP_Query
ou get_posts()
que são praticamente intercambiáveis (o último é um wrapper fino para o anterior).
Para limpar
Use wp_reset_query()
se você usou query_posts()
ou mexeu com global $wp_query
diretamente – então você quase nunca precisará.
Use wp_reset_postdata()
se você usou the_post()
ou setup_postdata()
ou mexeu com e precisa restaurar o estado inicial das coisas pós-relacionadas.
Comentários
- Raramente significava
wp_reset_postdata()
Resposta r
Existem cenários legítimos para usar query_posts($query)
, por exemplo:
-
Você deseja exibir uma lista de postagens ou postagens personalizadas em uma página (usando um modelo de página)
-
Você deseja fazer a paginação dessas postagens funcionar
Agora, por que você deseja exibi-lo em uma página em vez de usar um modelo de arquivo?
-
É mais intuitivo para um administrador (seu cliente?) – eles podem ver a página nas “Páginas”
-
É melhor para adicioná-la aos menus (sem a página, eles teriam para adicionar o url diretamente)
-
Se desejar exibir conteúdo adicional (texto, miniatura da postagem ou qualquer metaconteúdo personalizado) no modelo, você pode obtê-lo facilmente no página (e tudo faz mais sentido para o cliente também). Veja se você usou um modelo de arquivo, você “precisa codificar o conteúdo adicional ou usar, por exemplo, opções de tema / plug-in (o que o torna menos intuitivo para o cliente)
Aqui está um exemplo de código simplificado (que estaria em seu modelo de página – por exemplo, page-page-of-posts.php):
/** * Template Name: Page of Posts */ while(have_posts()) { // original main loop - page content the_post(); the_title(); // title of the page the_content(); // content of the page // etc... } // now we display list of our custom-post-type posts // first obtain pagination parametres $paged = 1; if(get_query_var("paged")) { $paged = get_query_var("paged"); } elseif(get_query_var("page")) { $paged = get_query_var("page"); } // query posts and replace the main query (page) with this one (so the pagination works) query_posts(array("post_type" => "my_post_type", "post_status" => "publish", "paged" => $paged)); // pagination next_posts_link(); previous_posts_link(); // loop while(have_posts()) { the_post(); the_title(); // your custom-post-type post"s title the_content(); // // your custom-post-type post"s content } wp_reset_query(); // sets the main query (global $wp_query) to the original page query (it obtains it from global $wp_the_query variable) and resets the post data // So, now we can display the page-related content again (if we wish so) while(have_posts()) { // original main loop - page content the_post(); the_title(); // title of the page the_content(); // content of the page // etc... }
Agora, para ser perfeitamente claro, poderíamos evitar usar query_posts()
aqui também e usar WP_Query
em vez disso – assim:
// ... global $wp_query; $wp_query = new WP_Query(array("your query vars here")); // sets the new custom query as a main query // your custom-post-type loop here wp_reset_query(); // ...
Mas, por que faríamos isso se temos uma pequena função tão legal disponível para ele?
Comentários
- Brian, obrigado por isso. Eu ‘ tenho me esforçado para fazer pre_get_posts funcionar em uma página EXATAMENTE o cenário que você descreve: o cliente precisa adicionar campos / conteúdo personalizados ao que de outra forma seria uma página de arquivo, então um ” página ” precisa ser criada; o cliente precisa ver algo para adicionar ao menu de navegação, já que adicionar um link personalizado os escapa; etc. +1 de mim!
- Isso também pode ser feito usando ” pre_get_posts “. Fiz isso para ter uma ” página inicial estática ” listando meus tipos de postagem personalizados em um pedido personalizado e com um filtro personalizado. Esta página também é paginada. Confira esta pergunta para ver como funciona: wordpress.stackexchange.com / questions / 30851 / … Então, em resumo, ainda não há cenário mais legítimo para usar query_posts;)
- Porque ” Deve-se observar que usar isso para substituir a consulta principal em uma página pode aumentar o tempo de carregamento da página, no pior dos cenários, mais do que dobrando a quantidade de trabalho necessária ou mais. Embora seja fácil de usar, a função também está sujeita a confusão e problemas posteriormente. ” Fonte codex.wordpress.org/Function_Reference/ query_posts
- Essa resposta está totalmente errada. Você pode criar uma ” Página ” no WP com o mesmo URL do tipo de postagem personalizada. EX: se o seu CPT for Bananas, você pode obter uma página chamada Bananas com o mesmo URL. Então você ‘ d acabaria com siteurl.com/bananas. Contanto que você tenha archive-bananas.php em sua pasta de tema, ele usará o modelo e ” substituirá ” essa página . Conforme declarado em um dos outros comentários, usar este ” método ” cria o dobro da carga de trabalho para WP, portanto, NÃO deve ser usado.
Resposta
Modifico a consulta do WordPress em functions.php:
//unfortunately, "IS_PAGE" condition doesn"t work in pre_get_posts (it"s WORDPRESS behaviour) //so you can use `add_filter("posts_where", ....);` OR modify "PAGE" query directly into template file add_action( "pre_get_posts", "myFunction" ); function myFunction($query) { if ( ! is_admin() && $query->is_main_query() ) { if ( $query->is_category ) { $query->set( "post_type", array( "post", "page", "my_postType" ) ); add_filter( "posts_where" , "MyFilterFunction_1" ) && $GLOBALS["call_ok"]=1; } } } function MyFilterFunction_1($where) { return (empty($GLOBALS["call_ok"]) || !($GLOBALS["call_ok"]=false) ? $where : $where . " AND ({$GLOBALS["wpdb"]->posts}.post_name NOT LIKE "Journal%")"; }
Comentários
- estaria interessado em ver este exemplo, mas onde a cláusula está no meta personalizado.
Resposta
Apenas para descrever algumas melhorias na resposta aceita, já que o WordPress evoluiu ao longo do tempo e algumas coisas são diferentes agora (cinco anos depois) :
pre_get_posts
é um filtro para alterar qualquer consulta. É mais frequentemente usado para alterar apenas a “consulta principal”:
Na verdade, é um gancho de ação. Não é um filtro e afetará qualquer consulta.
A consulta principal aparece em seus modelos como:
if( have_posts() ): while( have_posts() ): the_post(); //The loop endwhile; endif;
Na verdade, isso também não é verdade. A função have_posts
itera o objeto global $wp_query
que não está relacionado apenas à consulta principal. global $wp_query;
também pode ser alterado com as consultas secundárias.
function have_posts() { global $wp_query; return $wp_query->have_posts(); }
get_posts ()
Este é essencialmente um wrapper para uma instância separada de um objeto WP_Query.
Na verdade, hoje em dia WP_Query
é uma classe, então temos uma instância de uma classe.
Para concluir: Na época, @StephenHarris escreveu muito provavelmente tudo isso era verdade, mas com o tempo as coisas no WordPress foram mudando.
Comentários
- Tecnicamente, ‘ s todos os filtros sob o capô, as ações são apenas um filtro simples. Mas você está correto aqui, é ‘ uma ação que passa um argumento por referência, que é como ele difere de ações mais simples.
-
get_posts
retorna uma matriz de objetos de postagem, não um objetoWP_Query
, então isso ainda está correto. eWP_Query
sempre foi uma classe, instância de uma classe = objeto. - Obrigado, @Milo, correto por algum motivo, eu tinha um modelo simplificado em minha cabeça.