Când să folosești WP_Query vs query_posts() vs get_posts() în WordPress?
Se pare că jumătate din tutorialele din Codex și de pe bloguri folosesc query_posts()
, iar cealaltă jumătate folosește WP_Query
.
Toate fac lucruri similare, așa că când ar trebui să folosesc una în locul celorlalte?

query_posts()
este o metodă prea simplistă și problematică de a modifica interogarea principală a unei pagini prin înlocuirea ei cu o nouă instanță a interogării. Este ineficientă (re-execută interogările SQL) și va eșua în anumite circumstanțe (mai ales când vine vorba de paginarea postărilor). Orice cod WP modern ar trebui să utilizeze metode mai fiabile, cum ar fi folosirea hook-uluipre_get_posts
, în acest scop. TL;DR nu folosiți niciodată query_posts().get_posts()
este foarte similar în utilizare și acceptă aceleași argumente (cu unele nuanțe, cum ar fi valorile implicite diferite), dar returnează un array de postări, nu modifică variabilele globale și este sigur de utilizat oriunde.WP_Query
este clasa care stă la baza ambelor funcții, dar puteți crea și lucra cu propria instanță a acesteia. Un pic mai complexă, mai puține restricții, de asemenea sigură de utilizat oriunde.
Sursa imaginii: https://www.rarst.net/images/query_functions.png

(1) "și este sigur de utilizat oriunde" --> dar nu utilizați aceasta pentru bucla PRINCIPALĂ. (2) nu uitați să folosiți global $query_string; înaintea liniei care conține query_posts();

@scribu din nou 'get_posts' va funcționa deși nu este recomandat: http://core.trac.wordpress.org/ticket/16545

Cred că query_posts
este de asemenea mai puțin eficient deoarece va rula interogări suplimentare, în timp ce dacă utilizați doar WP_Query
pentru bucla principală, va rula doar interogarea pe care o alegeți în WP_Query.

@jjeaton query_posts()
este o mică funcție wrapper pentru WP_Query
, singurul lucru suplimentar pe care îl face (conform diagramei) este suprascrierea variabilei globale $wp_query

@Rarst Mă refeream la această secțiune din Codex pentru query_posts, totuși, este posibil să greșesc în legătură cu efectul asupra performanței. Cu excepția cazului în care utilizarea WP_Query în fișierul template va avea același rezultat (adică renunțarea la interogarea ta și reexecutarea ei)

@jjeaton Înlocuirea query_posts()
cu WP_Query
nu va face nicio diferență în performanță, interogarea originală a paginii va rula în continuare deoarece aceasta face parte din încărcarea de bază. Aceste interogări vor rula chiar dacă fișierul tău template nu conține deloc buclă.

Nu pot scăpa de sentimentul că acesta este cel mai genial și apreciat post de pe WPSE. Ar trebui să fie și în Codex.

Ok, după ce m-am uitat la el mai mult decât destul de mult, cred că query_posts()
îi lipsește o variabilă statică care să fie setată pe true după prima utilizare și - dacă este folosită de două ori - ar trebui să declanșeze _doing_it_wrong();
. Cred că o să deranjez tipii de la wp-hacker sau trac cu asta.

@kaiser ei bine... folosirea query_posts()
de două ori este la fel de rea ca o dată, nu contează prea mult pentru mine. :) apropo, Andrew Nacin va ține o prezentare despre interogări și a spus că ar putea propune unele îmbunătățiri la organigramă, așa că versiunea a doua ar putea veni în viitorul apropiat.

Voi adăuga cea mai clară descriere a problemei "performanței lui query_posts()": Folosirea query_posts() sau WP_Query într-un fișier de șablon va avea același cost de performanță: interogarea pe care tocmai ai efectuat-o. Problema discutată în articolul codex este că dacă chiar vrei să înlocuiești interogarea, ar trebui să o faci prin filtrarea query_posts() original cu filtrul 'parse_query'. În acest fel vei avea doar o singură interogare originală și dorită, în loc să faci o a doua interogare pentru a o înlocui stânjenitor. query_posts() NU ESTE NICIODATĂ SOLUȚIA!! NICIODATĂ!

Acest lucru nu menționează filtrul 'request', care este o modalitate excelentă de a modifica interogarea principală. Avantajul față de query_posts este că acea funcție șterge interogarea originală și generează una nouă - la fel ca și cum ai folosi WP_Query. Prin utilizarea filtrului request, modifici interogarea originală înainte ca aceasta să fie trimisă. Cred că la asta se referă @JeremyClarke mai sus.

Există o explicație extrem de bună despre query_posts scrisă de John James Jacoby pe blogul developer.wordpress.com care depășește toate aceste răspunsuri. Ideea principală: query_posts
nu modifică bucla principală deloc, ci o înlocuiește după ce aceasta a rulat deja. Cea mai bună metodă de a modifica bucla principală este prin intermediul unui filtru pre_get_posts
.
http://developer.wordpress.com/2012/05/14/querying-posts-without-query_posts/

@Dan confunzi implementarea tehnică cu scopul. query_posts()
înlocuiește într-adevăr obiectul loop-ului principal, dar scopul său este de a modifica loop-ul principal. De asemenea, sunt un mare adept al filtrelor de loop, dar întrebarea nu era despre asta. Există o întrebare de follow-up de la altcineva pe această temă.

Întrebarea era "Când ar trebui să folosești... query_posts()" și conform logicii prezentate în acel articol de blog și comentariile de mai sus, răspunsul este probabil niciodată.

@Manny Fleurmond conceptual, query_posts()
este o încercare de a simplifica conceptele de buclă principală la nivelul unui tag de șablon de temă (ușurința fiind unul dintre punctele forte pentru popularitatea WP). Sarcina s-a dovedit pur și simplu prea complexă pentru ca un tag de șablon să o poată realiza. Dezvoltatorii de bază au exprimat posibilitatea ca aceasta să fie depreciată, dar nu cred că s-a luat încă o decizie în acest sens.

De fapt, nu poți „folosi oriunde” WP_Query(), tocmai am încercat și încă dă eroare la $thequery->have_posts(), recursivitate infinită, vezi http://wordpress.stackexchange.com/questions/34270

@NoBugs bucla din acea întrebare este greșită și există un răspuns care explică de ce.

Agghh mulțumesc pentru asta. În sfârșit, ceva care are sens. Serios, WordPress și documentația lor proastă. Nu știu cum un software atât de încâlcit și standarde de codare proaste au devenit atât de populare.

Am găsit acest test de viteză între wp_query și get_posts http://www.wpclocked.com/

Aș avea încredere într-un astfel de test... exact zero. :) Funcția este un înveliș foarte subțire, orice diferență va veni din mici diferențe în argumente și/sau hook-uri.

Nu este nevoie de emoții, query_posts() este o funcție cu efecte secundare: setează o variabilă globală. WordPress este plin de funcții cu efecte secundare. Aceasta nu este o problemă de performanță, ci o problemă de calitate a codului. Verifică https://developer.wordpress.org/reference/functions/query_posts/ și vezi ce face query_posts. Folosește WP_Query dacă nu vrei să încurci variabilele globale.

query_posts
- Nu ar trebui să folosești niciodată query_posts
. Pe lângă ceea ce a menționat @Rarst, cea mai mare problemă cu query_posts
este că distruge obiectul principal al interogării (stocat în $wp_query
). Multe plugin-uri și cod personal se bazează pe obiectul principal al interogării, așa că distrugerea acestuia înseamnă că strici funcționalitățile plugin-urilor și ale codului personal. Doar una dintre aceste funcții este funcția extrem de importantă de paginare, deci dacă strici interogarea principală, strici paginarea.
Pentru a demonstra cât de rău este query_posts
, pe orice șablon, fă următoarele și compară rezultatele
var_dump( $wp_query );
query_posts( '&posts_per_page=-1' );
var_dump( $wp_query );
get_posts
și WP_Query
sunt metodele corecte pentru a construi interogări secundare ( precum postări înrudite, slide-uri, conținut recomandat și conținut pe pagini frontale statice ). Trebuie menționat că nu ar trebui să folosești niciuna dintre acestea în locul interogării principale pe pagina de start, pagina single sau orice tip de pagină de arhivă, deoarece va afecta funcționalitatea paginii. Dacă trebuie să modifici interogarea principală, folosește pre_get_posts
pentru a face acest lucru, și nu o interogare personalizată. (ACTUALIZARE: Pentru paginile frontale statice și paginile adevărate, vezi Folosirea pre_get_posts pe pagini adevărate și pagini frontale statice*)
În esență, WP_Query
este folosit de interogarea principală și este folosit și de get_posts
, dar deși get_posts()
utilizează WP_Query
, există câteva diferențe:
get_posts
este mai rapid decâtWP_Query
. Diferența depinde de numărul total de postări ale site-ului. Motivul pentru aceasta este căget_posts
trece implicit'no_found_rows' => true
cătreWP_Query
, ceea ce omite/întrerupe legal paginarea. Cu'no_found_rows' => true
,WP_Query
obține numărul de postări interogate, apoi se oprește, în timp ce implicit, continuă să caute toate postările care corespund interogării pentru a calcula paginarea.Din acest motiv,
get_posts()
ar trebui folosit doar pentru interogări ne-paginate. Paginareaget_posts
este o adevărată mizerie.WP_Query
ar trebui folosit pentru toate interogările paginate.get_posts()
nu sunt influențate de filtreleposts_*
, în timp ceWP_Query
este influențat de aceste filtre. Motivul este căget_posts
, implicit, trece'suppress_filters' => true
cătreWP_Query
.get_posts
are câțiva parametri extra precuminclude
,exclude
,numberposts
șicategory
. Acești parametri sunt transformați în parametri valizi pentruWP_Query
înainte de a fi pasați cătreWP_Query
.include
este transformat înpost__in
,exclude
înpost__not_in
,category
încat
șinumberposts
înposts_per_page
. Doar o notă, toți parametrii care pot fi pasați cătreWP_Query
funcționează și cuget_posts
, poți ignora și nu folosi parametrii impliciți aiget_posts
.get_posts
returnează doar proprietatea$posts
aWP_Query
, în timp ceWP_Query
returnează întregul obiect. Acest obiect este foarte util când vine vorba de condiționale, paginare și alte informații utile care pot fi folosite în interiorul buclei.get_posts
nu folosește bucla, ci o buclăforeach
pentru a afișa postările. De asemenea, niciun tag de șablon nu este disponibil implicit.setup_postdata( $post )
trebuie folosit pentru a face tag-urile de șablon disponibile.WP_Query
folosește bucla și tag-urile de șablon sunt disponibile implicit.get_posts
trece'ignore_sticky_posts' => 1
cătreWP_Query
, deciget_posts
ignoră implicit postările lipicioase.
Pe baza celor de mai sus, dacă să folosești get_posts
sau WP_Query
depinde de tine și de ce ai nevoie de fapt din interogare. Cele de mai sus ar trebui să te ghideze în alegerea ta.

Aș dori să pot marca răspunsurile ca favorite. Asta explică atât de multe.

Explicație excelentă!
"get_posts() ar trebui folosit doar pentru interogări nepaginate. Paginarea get_posts este cu adevărat o mare mizerie. WP_Query ar trebui utilizat pentru toate interogările paginate" este practic tot ce trebuie să știe cineva, după părerea mea.

Diferența de bază este că query_posts()
este destinat doar modificării buclei curente. După ce ai terminat, este necesar să resetezi bucla și să o lași să continue. Această metodă este și puțin mai ușor de înțeles, pur și simplu pentru că "interogarea" ta este practic un șir URL pe care îl transmiți funcției, astfel:
query_posts('meta_key=color&meta_value=blue');
Pe de altă parte, WP_Query
este mai mult un instrument de uz general și este mai aproape de scrierea directă a interogărilor MySQL decât query_posts()
. De asemenea, îl poți folosi oriunde (nu doar în buclă) și nu interferează cu nicio interogare de postări în curs.
Personal, tind să folosesc WP_Query
mai des. În realitate, totul se reduce la cazul tău specific.

Nu există absolut nicio necesitate de a folosi query_posts()
. Tot ce face această funcție este să instantieze un nou obiect WP_Query și să realoce acel obiect nou la global wp_query
.
Pentru referință, următoarea este funcția actuală query_posts()
.
function query_posts($query) {
$GLOBALS['wp_query'] = new WP_Query();
return $GLOBALS['wp_query']->query($query);
}
Instanțiați-vă propriul obiect WP_Query dacă doriți să creați un script personalizat de interogare în detaliu. Sau folosiți get_posts()
dacă tot ce trebuie să faceți este o ușoară manipulare aici și acolo.
În orice caz, vă recomand să vă faceți o favoare și să mergeți la wp_includes/query.php
și să parcurgeți clasa WP_Query
.

- query_posts(): poate fi utilizat într-un singur caz și numai dacă trebuie să modifici interogarea principală. Acesta setează multe variabile globale;
- get_posts(): este foarte similar ca mecanism și acceptă aceleași argumente, dar returnează un array de postări
- WP_Query: poți crea și lucra cu propriul obiect al acestuia. Un pic mai complex, mai puține restricții, este sigur să-l folosești oriunde.
