Quando utilizzare WP_query (), query_posts () e pre_get_posts

Ho letto @nacin “s Non conosci Query ieri ed è stato inviato un po come una tana di coniglio. Prima di ieri, utilizzavo (erroneamente) query_posts() per tutte le mie esigenze di query. Ora sono “un po più saggio sullutilizzo di WP_Query() , ma ho ancora alcune aree grigie.

Quello che penso di sapere per certo:

Se “sto facendo addizionali scorre in un punto qualsiasi di una pagina (nella barra laterale, in un piè di pagina, qualsiasi tipo di “post correlati” e così via – Voglio utilizzare WP_Query() . Posso usarlo ripetutamente su una singola pagina senza alcun danno. (giusto?).

Quello che non “non so per certo

  1. Quando devo utilizzare @nacin “s pre_get_posts rispetto a WP_Query() ? Devo usare pre_get_posts per tutto adesso?
  2. Quando voglio modificare il ciclo in una pagina modello, diciamo che voglio modificare una pagina di archivio di tassonomia, rimuovo la parte if have_posts : while have_posts : the_post e scrivo il mio possiedi WP_Query() ? Oppure modifico loutput utilizzando pre_get_posts nel mio file functions.php?

tl; dr

Le regole tl; dr Vorrei trarre ispirazione da questo sono:

  1. Non utilizzare mai query_posts più
  2. Quando esegui più query su una singola pagina, utilizza WP_Query()
  3. Quando modifichi un ciclo, fallo __________________.

Grazie per la saggezza

Terry

ps: Ho visto e letto: Quando dovresti utilizzare WP_Query vs query_posts () vs get_posts ()? Che aggiunge unaltra dimensione – get_posts . Ma non si occupa di pre_get_posts .

Commenti

Risposta

Hai ragione a dire:

Non utilizzare mai più query_posts

pre_get_posts

pre_get_posts è un filtro per modificare qualsiasi query. Viene spesso utilizzato per modificare solo la “query principale”:

add_action("pre_get_posts","wpse50761_alter_query"); function wpse50761_alter_query($query){ if( $query->is_main_query() ){ //Do something to main query } } 

(vorrei anche controllare che is_admin() restituisce false , anche se potrebbe essere ridondante.). La query principale appare nei tuoi modelli come:

if( have_posts() ): while( have_posts() ): the_post(); //The loop endwhile; endif; 

Se hai mai sentito il bisogno di modificare questo ciclo, usa pre_get_posts. ad esempio, se sei tentato di utilizzare query_posts(), usa pre_get_posts.

WP_Query

La query principale è unistanza importante di WP_Query object . WordPress lo utilizza per decidere quale modello utilizzare, ad esempio, e tutti gli argomenti passati nellURL (ad esempio limpaginazione) vengono tutti canalizzati in quellistanza delloggetto WP_Query.

Per i cicli secondari (ad es. nelle barre laterali o negli elenchi di “articoli correlati”) dovrai creare la tua istanza separata delloggetto WP_Query. Ad es.

$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(); 

Avviso wp_reset_postdata();: questo perché il ciclo secondario sovrascriverà il $post variabile che identifica il “post corrente”. Questo essenzialmente lo reimposta al $post su cui ci troviamo.

get_posts ()

Questo è essenzialmente un wrapper per unistanza separata di un oggetto WP_Query. Restituisce un array di oggetti post. I metodi utilizzati nel ciclo precedente non sono più disponibili. Questo non è ” ta “Loop”, semplicemente un array di oggetti post.

<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> 

In risposta alle tue domande

  1. Utilizza pre_get_posts per modificare la query principale. Utilizza un oggetto WP_Query separato (metodo 2) per i cicli secondari nelle pagine del modello.
  2. Se desideri modificare la query del ciclo principale, utilizza pre_get_posts.

Commenti

  • Quindi cè qualche scenario in cui si andrebbe direttamente a get_posts () invece che a WP_Query?
  • @drtanz – sì. Supponiamo ad esempio che ‘ non necessiti di impaginazione o di post appiccicosi in alto: in questi casi get_posts() è più efficiente.
  • Ma ‘ non aggiungerebbe una query extra in cui potremmo semplicemente modificare pre_get_posts per modificare la query principale?
  • @drtanz – non lo faresti ‘ non stai utilizzando get_posts() per la query principale, è per le query secondarie.
  • @StephenHarris Right =) Se utilizzi next_post () sulloggetto invece di usare the_post, non ‘ passare alla query globale e non ‘ non devi ricordarti di usa wp_reset_postdata in seguito.

Risposta

Esistono due diversi contesti per i cicli:

  • main ciclo che si verifica in base alla richiesta URL e viene elaborato prima del caricamento dei modelli
  • secondario

loop che si verificano in qualsiasi altro modo, richiamati da file modello o in altro modo

Problema con query_posts() è che è il ciclo secondario che cerca di essere quello principale e fallisce miseramente. Quindi dimentica che esiste.

Per modificare il ciclo principale

  • non usare query_posts()
  • usa pre_get_posts filtro con $query->is_main_query() check
  • utilizza alternativamente request filtro ( un po troppo approssimativo quindi sopra è meglio)

Per eseguire il ciclo secondario

Usa new WP_Query o get_posts() che sono praticamente intercambiabili (il secondo è un involucro sottile per il primo).

Per pulire

Usa wp_reset_query() se hai utilizzato query_posts() o hai fatto confusione con $wp_query globale direttamente, quindi non ne avrai quasi mai bisogno.

Usa wp_reset_postdata() se hai utilizzato the_post() o setup_postdata() o hai sbagliato con $post e devi ripristinare lo stato iniziale delle cose correlate.

Commenti

  • Rarst mean wp_reset_postdata()

Answe r

Esistono scenari legittimi per lutilizzo di query_posts($query), ad esempio:

  1. Desideri visualizzare un elenco di post o post di tipo post personalizzato su una pagina (utilizzando un modello di pagina)

  2. Desideri che limpaginazione di tali post funzioni

Ora, perché dovresti visualizzarlo su una pagina invece di utilizzare un modello di archivio?

  1. È più intuitivo per un amministratore (il tuo cliente?) – possono vedere la pagina nelle “Pagine”

  2. È meglio aggiungerla ai menu (senza la pagina, avrebbero ” per aggiungere direttamente lURL)

  3. Se desideri visualizzare contenuto aggiuntivo (testo, miniatura del post o qualsiasi meta contenuto personalizzato) sul modello, puoi ottenerlo facilmente dal pagina (e tutto ha più senso anche per il cliente). Verifica se hai utilizzato un modello di archivio, devi o codificare il contenuto aggiuntivo o utilizzare ad esempio le opzioni del tema / plug-in (il che lo rende meno intuitivo per il cliente)

Ecco “un codice di esempio semplificato (che sarebbe sul tuo modello di pagina – ad es. 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... }  

Ora, per essere perfettamente chiari, potremmo evitare di utilizzare query_posts() anche qui e utilizzare WP_Query invece – in questo modo:

// ... 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(); // ... 

Ma perché dovremmo farlo quando abbiamo a disposizione una piccola funzione così carina?

Commenti

  • Brian, grazie per questo. ‘ ho lottato per far funzionare pre_get_posts su una pagina ESATTAMENTE nello scenario che descrivi: il cliente deve aggiungere campi / contenuti personalizzati a quella che altrimenti sarebbe una pagina di archivio, quindi un La ” pagina ” deve essere creata; il cliente ha bisogno di vedere qualcosa da aggiungere al menu di navigazione, poiché laggiunta di un collegamento personalizzato gli sfugge; ecc. +1 da me!
  • Questo può essere fatto anche utilizzando ” pre_get_posts “. Lho fatto per avere una ” prima pagina statica ” che elencava i miei tipi di post personalizzati in un ordine personalizzato e con un filtro personalizzato. Anche questa pagina è impaginata. Dai unocchiata a questa domanda per vedere come funziona: wordpress.stackexchange.com / questions / 30851 / … Quindi, in breve, non esiste ancora uno scenario più legittimo per lutilizzo di query_posts;)
  • Perché ” Va notato che luso di questo per sostituire la query principale su una pagina può aumentare i tempi di caricamento della pagina, nei casi peggiori più del doppio della quantità di lavoro necessaria o più. Sebbene sia facile da usare, la funzione è anche soggetta a confusione e problemi in seguito. ” Fonte codex.wordpress.org/Function_Reference/ query_posts
  • Questa risposta è di tutti i tipi sbagliata. Puoi creare una ” pagina ” in WP con lo stesso URL del tipo di post personalizzato. Ad esempio, se il tuo CPT è Bananas, puoi ottenere una pagina denominata Bananas con lo stesso URL. Quindi ‘ ti ritroverai con siteurl.com/bananas. Finché hai archive-bananas.php nella cartella del tema, utilizzerà il modello e ” sovrascriverà ” quella pagina . Come affermato in uno degli altri commenti, lutilizzo di questo ” metodo ” crea il doppio del carico di lavoro per WP, quindi NON dovrebbe mai essere utilizzato.

Risposta

Modifico la query di WordPress da 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%")"; } 

Commenti

  • sarebbe interessato a vedere questo esempio, ma la clausola è nel meta personalizzato.

Risposta

Giusto per delineare alcuni miglioramenti alla risposta accettata poiché WordPress si è evoluto nel tempo e alcune cose sono diverse ora (cinque anni dopo) :

pre_get_posts è un filtro per modificare qualsiasi query. Viene spesso utilizzato per modificare solo la “query principale”:

In realtà è un action hook. Non è un filtro e influirà su qualsiasi query.

La query principale viene visualizzata nei modelli come:

if( have_posts() ): while( have_posts() ): the_post(); //The loop endwhile; endif; 

In realtà, anche questo non è vero. La funzione have_posts itera loggetto global $wp_query che non è correlato solo alla query principale. global $wp_query; potrebbe essere modificato anche con le query secondarie.

function have_posts() { global $wp_query; return $wp_query->have_posts(); } 

get_posts ()

Questo è essenzialmente un wrapper per unistanza separata di un oggetto WP_Query.

In realtà, oggigiorno WP_Query è una classe, quindi abbiamo unistanza di una classe.


Per concludere: allepoca @StephenHarris scrisse molto probabilmente tutto questo era vero, ma nel tempo le cose in WordPress sono state cambiate.

Commenti

  • Tecnicamente, ‘ s tutti i filtri sotto il cofano, le azioni sono solo un semplice filtro. Ma hai ragione qui, ‘ è unazione che passa un argomento per riferimento, che è il modo in cui differisce dalle azioni più semplici.
  • get_posts restituisce un array di oggetti post, non un oggetto WP_Query, quindi è ancora corretto. e WP_Query è sempre stata una classe, istanza di un oggetto class =.
  • Grazie, @Milo, corretto da qualche motivo per cui avevo un modello troppo semplificato nella mia testa.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *