Când se utilizează WP_query (), query_posts () și pre_get_posts

Am citit @nacin „s Ieri nu știți Query și a fost trimis în jos o mică gaură de iepure. Înainte de ieri, foloseam (în mod greșit) query_posts() pentru toate nevoile mele de interogare. Acum sunt „puțin mai înțelept cu privire la utilizarea WP_Query() , dar mai am câteva zone gri.

Ce cred că știu sigur:

Dacă fac suplimentar bucle oriunde pe o pagină – în bara laterală, într-un subsol, orice fel de „postări corelate” etc. – vreau să folosesc WP_Query() . Îl pot folosi în mod repetat pe o singură pagină, fără niciun rău. (dreapta?).

Ce nu știu sigur

  1. Când folosesc @nacin „s pre_get_posts vs. WP_Query() ? Ar trebui să folosesc pre_get_posts pentru toate acum?
  2. Când vreau să modific bucla dintr-o pagină de șablon – să spunem că vreau să modific o pagină de arhivă taxonomică – elimin partea if have_posts : while have_posts : the_post și scriu propriu WP_Query() ? Sau modific ieșirea folosind pre_get_posts în fișierul meu functions.php?

tl; dr

Regulile tl; dr Aș dori să extrag din acestea sunt:

  1. Nu folosiți niciodată query_posts mai mult
  2. Când rulați mai multe interogări pe o singură pagină, utilizați WP_Query()
  3. Când modificați o buclă, faceți acest lucru __________________.

Vă mulțumim pentru orice înțelepciune

Terry

ps: Am văzut și am citit: Când ar trebui să utilizați WP_Query vs query_posts () vs get_posts ()? Care adaugă o altă dimensiune – get_posts . Dar nu se ocupă deloc de pre_get_posts .

Comentarii

Răspuns

Ai dreptate să spui:

Nu mai folosiți niciodată query_posts

pre_get_posts

pre_get_posts este un filtru, pentru modificarea orice interogare. Cel mai adesea este folosit pentru a modifica numai „interogarea principală”:

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

(aș verifica și dacă is_admin() returnează fals – deși acest lucru poate fi redundant.). Interogarea principală apare în șabloanele dvs. ca:

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

Dacă simțiți vreodată nevoia de a edita această buclă – utilizați pre_get_posts. De exemplu, dacă sunteți tentați să utilizați query_posts() – utilizați în schimb pre_get_posts.

WP_Query

Interogarea principală este o instanță importantă a unui WP_Query object . WordPress îl folosește pentru a decide ce șablon să utilizeze, de exemplu, și orice argumente transmise în adresa URL (de exemplu, paginare) sunt toate canalizate în acea instanță a obiectului WP_Query.

Pentru buclele secundare (de exemplu, în barele laterale sau listele „postări conexe”), veți dori să creați propria instanță separată a obiectului WP_Query. De ex.

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

Observați wp_reset_postdata(); – acest lucru se datorează faptului că bucla secundară va suprascrie $post variabilă care identifică „postarea curentă”. Aceasta în esență resetează faptul că la $post suntem.

get_posts ()

Acesta este în esență un wrapper pentru o instanță separată a unui obiect WP_Query. Aceasta returnează o matrice de obiecte post. Metodele utilizate în bucla de mai sus nu mai sunt disponibile pentru dvs. Nu este acest lucru ” ta „Buclă”, pur și simplu o serie de obiecte 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> 

Ca răspuns la întrebările dvs.

  1. Utilizați pre_get_posts pentru a modifica interogarea principală. Utilizați un obiect WP_Query separat (metoda 2) pentru buclele secundare din paginile șablon.
  2. Dacă doriți să modificați interogarea buclei principale, utilizați pre_get_posts.

Comentarii

  • Deci, există vreun scenariu când cineva ar merge direct la get_posts () în loc de WP_Query?
  • @drtanz – da. Spuneți, de exemplu, că nu ‘ nu aveți nevoie de paginare sau de postări lipicioase în partea de sus – în aceste cazuri get_posts() este mai eficient.
  • Dar ‘ nu ar adăuga o interogare suplimentară în care am putea modifica doar pre_get_posts pentru a modifica interogarea principală?
  • @drtanz – nu ați ‘ nu utilizați get_posts() pentru interogarea principală – pentru interogări secundare.
  • @StephenHarris Right =) Dacă utilizați next_post () pe obiect în loc să folosiți the_post, nu ‘ nu călcați pe interogarea globală și nu ‘ nu trebuie să vă amintiți să utilizați wp_reset_postdata după aceea.

Răspuns

Există două contexte diferite pentru bucle:

  • buclă principală care se întâmplă pe baza cererii URL și este procesată înainte de încărcarea șabloanelor
  • secundar

bucle care se întâmplă în orice alt mod, apelate din fișiere șablon sau altfel

Problemă cu query_posts() este că este o buclă secundară care încearcă să fie una principală și eșuează lamentabil. Așa că uitați că există.

Pentru a modifica bucla principală

  • nu utilizați query_posts()
  • pre_get_posts filtru cu $query->is_main_query() verificare
  • utilizează alternativ filtrul request ( un pic prea dur, așa că mai sus este mai bine)

Pentru a rula bucla secundară

Utilizați new WP_Query sau get_posts() care sunt aproape interschimbabile (ultima este o folie subțire pentru prima).

Pentru curățare

Utilizați wp_reset_query() dacă ați folosit query_posts() sau ați păcălit direct cu $wp_query direct – deci nu veți mai avea nevoie niciodată.

Utilizați wp_reset_postdata() dacă ați folosit the_post() sau setup_postdata() sau ați păcălit cu și trebuie să restabiliți starea inițială a lucrurilor post-legate.

Comentarii

  • Mai rar înseamnă wp_reset_postdata()

Answe r

Există scenarii legitime pentru utilizarea query_posts($query), de exemplu:

  1. Doriți să afișați o listă de postări sau postări personalizate de tip postare pe o pagină (folosind un șablon de pagină)

  2. Vreți ca paginarea acelor postări să funcționeze

Acum, de ce ați dori să îl afișați pe o pagină în loc să utilizați un șablon de arhivă?

  1. Este mai intuitiv pentru un administrator (clientul dvs.?) – poate vedea pagina în „Pagini”

  2. Este mai bine să o adăugați la meniuri (fără pagină, ar avea pentru a adăuga adresa URL direct)

  3. Dacă doriți să afișați conținut suplimentar (text, postare miniatură sau orice conținut meta personalizat) pe șablon, îl puteți obține cu ușurință din pagină (și totul are mai mult sens și pentru client). Vedeți dacă ați folosit un șablon de arhivă, fie trebuie să codificați conținutul suplimentar, fie să folosiți, de exemplu, opțiuni pentru temă / plugin (ceea ce îl face mai puțin intuitiv pentru client)

Aici „un exemplu de cod simplificat (care ar fi pe șablonul paginii dvs. – de ex. Pagina-pagină-a-posturilor.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... }  

Acum, pentru a fi perfect clar, am putea evita să folosim și query_posts() și aici și să folosim WP_Query în schimb – așa:

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

Dar, de ce am face asta când avem o funcție atât de frumoasă disponibilă pentru ea?

Comentarii

  • Brian, mulțumesc pentru asta. ‘ m-am străduit să fac ca pre_get_posts să funcționeze pe o pagină în EXACT scenariul pe care îl descrieți: clientul trebuie să adauge câmpuri / conținut personalizat la ceea ce altfel ar fi o pagină de arhivă, ” pagina ” trebuie creată; clientul trebuie să vadă ceva de adăugat în meniul de navigare, deoarece adăugarea unui link personalizat scapă de ele; etc. +1 de la mine!
  • Acest lucru se poate face și cu ” pre_get_posts „. Am făcut asta pentru a avea o ” prima pagină statică ” care enumeră tipurile mele de postări personalizate într-o ordine personalizată și cu un filtru personalizat. Această pagină este, de asemenea, paginată. Consultați această întrebare pentru a vedea cum funcționează: wordpress.stackexchange.com / questions / 30851 / … Deci, pe scurt, nu mai există încă un scenariu legitim pentru utilizarea query_posts;)
  • Deoarece ” Trebuie remarcat faptul că utilizarea acestui lucru pentru a înlocui interogarea principală dintr-o pagină poate crește timpul de încărcare a paginii, în cel mai rău caz scenarii mai mult decât dublarea cantității de muncă necesare sau mai mult. Deși este ușor de utilizat, funcția este predispusă la confuzii și probleme mai târziu. ” Sursă codex.wordpress.org/Function_Reference/ query_posts
  • Acest răspuns este tot felul de greșeli. Puteți crea o ” Pagină ” în WP cu aceeași adresă URL ca tipul de postare personalizată. De exemplu, dacă CPT-ul dvs. este Banane, puteți obține o pagină numită Banane cu aceeași adresă URL. Apoi, ‘ ați ajuns cu siteurl.com/bananas. Atâta timp cât aveți archive-bananas.php în folderul tematic, atunci acesta va utiliza șablonul și ” suprascrie ” pagina respectivă . După cum sa menționat într-unul din celelalte comentarii, utilizarea acestei metode ” ” creează dublul volumului de lucru pentru WP, deci NU trebuie folosit niciodată.

Răspuns

Modific interogarea WordPress din 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%")"; } 

Comentarii

  • ar fi interesat să vadă acest exemplu, dar unde clauza este pe meta personalizată.

Răspuns

Doar pentru a contura câteva îmbunătățiri ale răspunsului acceptat, deoarece WordPress a evoluat de-a lungul timpului și unele lucruri sunt diferite acum (cinci ani mai târziu) :

pre_get_posts este un filtru, pentru modificarea oricărei interogări. Cel mai adesea este folosit pentru a modifica doar „interogarea principală”:

De fapt este un cârlig de acțiune. Nu este un filtru și va afecta orice interogare.

Interogarea principală apare în șabloanele dvs. ca:

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

De fapt, acest lucru nu este adevărat. Funcția have_posts iterează obiectul global $wp_query care nu este legat numai de interogarea principală. global $wp_query; poate fi modificat și cu interogările secundare.

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

get_posts ()

Acesta este în esență un wrapper pentru o instanță separată a unui obiect WP_Query.

De fapt, în zilele noastre WP_Query este o clasă, deci avem o instanță a unei clase.


Pentru a concluziona: La momentul respectiv, @StephenHarris a scris cel mai probabil că toate acestea erau adevărate, dar de-a lungul timpului lucrurile din WordPress au fost schimbate.

Comentarii

  • Tehnic, este ‘ s toate filtrele de sub capotă, acțiunile sunt doar un simplu filtru. Dar aveți dreptate aici, este ‘ o acțiune care trece un argument prin referință, care diferă de acțiunile mai simple.
  • get_posts returnează o matrice de obiecte post, nu un obiect WP_Query, deci este într-adevăr corect. și WP_Query a fost întotdeauna o clasă, o instanță a unui obiect = class.
  • Mulțumesc, @Milo, corect dintr-un motiv pentru care am avut un model simplificat în cap.

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *