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
- Când folosesc @nacin „s
pre_get_posts
vs.WP_Query()
? Ar trebui să folosescpre_get_posts
pentru toate acum? - 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 propriuWP_Query()
? Sau modific ieșirea folosindpre_get_posts
în fișierul meu functions.php?
tl; dr
Regulile tl; dr Aș dori să extrag din acestea sunt:
- Nu folosiți niciodată
query_posts
mai mult - Când rulați mai multe interogări pe o singură pagină, utilizați
WP_Query()
- 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
- Posibil duplicat al Când ar trebui să utilizați WP_Query vs query_posts () vs get_posts ( )?
- @saltcod, acum este diferit, WordPress a evoluat, am adăugat câteva comentarii în comparație cu răspunsul acceptat aici .
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.
- Utilizați
pre_get_posts
pentru a modifica interogarea principală. Utilizați un obiectWP_Query
separat (metoda 2) pentru buclele secundare din paginile șablon. - 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:
-
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ă)
-
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ă?
-
Este mai intuitiv pentru un administrator (clientul dvs.?) – poate vedea pagina în „Pagini”
-
Este mai bine să o adăugați la meniuri (fără pagină, ar avea pentru a adăuga adresa URL direct)
-
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 obiectWP_Query
, deci este într-adevăr corect. șiWP_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.