Quando usar WP_query (), query_posts () e pre_get_posts

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

  1. Quando devo usar @nacin “s pre_get_posts vs. WP_Query() ? Devo usar pre_get_posts para tudo agora?
  2. 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 possuir WP_Query() ? Ou modifico a saída usando pre_get_posts em meu arquivo functions.php?

tl; dr

As regras tl; dr Eu “gostaria de extrair disso:

  1. Nunca use query_posts mais
  2. Ao executar várias consultas em uma única página, use WP_Query()
  3. 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

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

  1. Use pre_get_posts para alterar sua consulta principal. Use um objeto WP_Query separado (método 2) para loops secundários nas páginas de modelo.
  2. 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:

  1. Você deseja exibir uma lista de postagens ou postagens personalizadas em uma página (usando um modelo de página)

  2. 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?

  1. É mais intuitivo para um administrador (seu cliente?) – eles podem ver a página nas “Páginas”

  2. É melhor para adicioná-la aos menus (sem a página, eles teriam para adicionar o url diretamente)

  3. 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 objeto WP_Query, então isso ainda está correto. e WP_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.

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *