Quando dovresti usare WP_Query rispetto a query_posts() e get_posts()? - Guida WordPress
Sembra che metà dei tutorial nel Codex e nel blogosphere utilizzino query_posts() e l'altra metà usi WP_Query.
Tutti fanno cose simili, quindi quando dovrei usare uno piuttosto che gli altri?
query_posts()è eccessivamente semplicistico e un modo problematico per modificare la query principale di una pagina sostituendola con una nuova istanza della query. È inefficiente (ri-esegue le query SQL) e in alcuni casi fallirà completamente (spesso quando si ha a che fare con l'impaginazione dei post). Qualsiasi codice WP moderno dovrebbe utilizzare metodi più affidabili, come sfruttare l'hookpre_get_posts, per questo scopo. TL;DR non usare mai query_posts().get_posts()è molto simile nell'utilizzo e accetta gli stessi argomenti (con alcune differenze, come valori predefiniti diversi), ma restituisce un array di post, non modifica le variabili globali ed è sicuro da usare ovunque.WP_Queryè la classe che gestisce entrambi dietro le quinte, ma puoi anche creare e lavorare con la tua istanza personalizzata. Un po' più complesso, meno restrizioni, anch'esso sicuro da usare ovunque.
Fonte immagine: https://www.rarst.net/images/query_functions.png
(1) "ed è sicuro da usare ovunque" --> ma non usarlo per il loop PRINCIPALE. (2) ricorda di usare global $query_string; prima della riga che contiene query_posts();
edelwater
@scribu d'altra parte 'get_posts' funzionerà anche se non consigliato: http://core.trac.wordpress.org/ticket/16545
edelwater
Credo che query_posts sia anche meno efficiente in quanto eseguirà query aggiuntive, mentre se usi solo WP_Query per il tuo loop principale, eseguirà solamente la query che hai scelto in WP_Query.
jjeaton
@jjeaton query_posts() è una piccola funzione wrapper per WP_Query, l'unica cosa extra che fa (come per il diagramma di flusso) è sovrascrivere la variabile globale $wp_query
Rarst
@Rarst Mi riferivo a questa sezione nel Codex per query_posts tuttavia, potrei essermi sbagliato riguardo all'effetto sulle prestazioni. A meno che usare WP_Query nel tuo file template non abbia lo stesso risultato (cioè scartare la tua query e rieseguirla)
jjeaton
@jjeaton Sostituire query_posts() con WP_Query non farà alcuna differenza nelle prestazioni, la query originale della pagina verrà comunque eseguita perché fa parte del caricamento del core. Quelle query verranno eseguite anche se il tuo file template non ha alcun loop.
Rarst
Non riesco a liberarmi dalla sensazione che questo sia il post più geniale e votato su WPSE. Dovrebbe essere anche nel Codex.
kaiser
Ok, dopo averlo guardato per più di un bel po' di tempo, penso che a query_posts() manchi una variabile statica che viene impostata su true dopo il primo uso e - se usata due volte - dovrebbe attivare _doing_it_wrong();. Credo che segnalerò questa cosa ai ragazzi di wp-hacker o trac.
kaiser
@kaiser beh... usare query_posts() due volte è più o meno dannoso come usarla una volta, non fa molta differenza secondo me. :) comunque Andrew Nacin farà una presentazione sulle query e ha detto che potrebbe proporre alcuni miglioramenti al diagramma di flusso, quindi una versione due potrebbe arrivare in futuro.
Rarst
Aggiungerò la mia descrizione più chiara del problema della "performance di query_posts()": Usare query_posts() o WP_Query all'interno di un file template avrà lo stesso costo in termini di performance: la query che hai appena eseguito. Il problema discusso nell'articolo del codex è che se vuoi davvero sostituire la query dovresti farlo filtrando la query_posts() originale con il filtro 'parse_query'. In questo modo avrai solo la singola query originale e desiderata, piuttosto che eseguire una seconda query per sostituirla in modo scomodo. query_posts() NON È MAI LA SOLUZIONE!! MAI!
jerclarke
Questo non menziona il filtro 'request', che è un ottimo modo per modificare la query principale. Il vantaggio rispetto a query_posts è che questa funzione cancella la query originale e ne genera una nuova - esattamente come se usassi WP_Query. Usando il filtro request, stai modificando la query originale prima che venga mai inviata. Penso che sia questo ciò a cui si riferisce @JeremyClarke sopra.
eddiemoya
C'è una spiegazione fantastica di query_posts scritta da John James Jacoby sul blog developer.wordpress.com che supera tutte queste risposte. Il punto principale: query_posts non modifica affatto il main loop, lo sostituisce dopo che è già stato eseguito. Il modo migliore per modificare il main loop è attraverso un filtro pre_get_posts.
http://developer.wordpress.com/2012/05/14/querying-posts-without-query_posts/
Dan Gayle
@Dan stai confondendo l'implementazione tecnica e lo scopo. query_posts() sostituisce l'oggetto del loop principale, ma il suo scopo è modificare il loop principale. Inoltre ho una grande simpatia per i filtri del loop, ma non era questo che chiedeva la domanda. C'è una domanda di follow-up da parte di un'altra persona su quel tema.
Rarst
La domanda era "Quando dovresti usare... query_posts()" e secondo la logica presentata da quel post del blog e dai commenti sopra, la risposta è probabilmente mai.
Dan Gayle
@Manny Fleurmond concettualmente query_posts() è un tentativo di semplificare i concetti del main loop al livello di un template tag (la facilità è uno dei punti forti della popolarità di WP). Il compito si è rivelato semplicemente troppo complesso per un template tag. Gli sviluppatori core hanno accennato alla possibilità di deprecarlo, ma non credo sia stata ancora presa una decisione al riguardo.
Rarst
In realtà non puoi usare WP_Query() "ovunque", ho appena provato e va ancora in crash con $thequery->have_posts(), ricorsione infinita, vedi http://wordpress.stackexchange.com/questions/34270
NoBugs
@NoBugs il loop in quella domanda è sbagliato e c'è una risposta che spiega il perché.
Rarst
Ahhh grazie per questo. Finalmente qualcosa che ha senso. Seriamente, WordPress e la loro pessima documentazione. Non so come un software così contorto e con standard di codifica scadenti sia diventato così popolare.
racl101
Ho trovato questo test di velocità tra wp_query e get_posts http://www.wpclocked.com/
Anagio
Mi fiderei di un test del genere... esattamente zero. :) La funzione è un wrapper molto leggero, qualsiasi differenza deriverebbe da lievi differenze negli argomenti e/o negli hook.
Rarst
Nessuna necessità di emozioni, query_posts() è una funzione con effetti collaterali: imposta una variabile globale. WordPress è pieno di funzioni con effetti collaterali. Questo non è un problema di prestazioni ma un problema di qualità del codice. Guarda https://developer.wordpress.org/reference/functions/query_posts/ e vedi cosa fa query_posts. Usa WP_Query a meno che tu non voglia scombussolare le variabili globali.
th00ht
query_posts - Non dovresti mai utilizzare query_posts. Oltre a quanto detto da @Rarst, il problema più grande con query_posts è che rompe l'oggetto della query principale (memorizzato in $wp_query). Molti plugin e codice personalizzato si basano sull'oggetto della query principale, quindi rompere l'oggetto della query principale significa che stai rompendo le funzionalità dei plugin e del codice personalizzato. Una di queste funzioni è l'importante funzione di paginazione, quindi se rompi la query principale, rompi la paginazione.
Per dimostrare quanto sia dannoso query_posts, in qualsiasi template, esegui il seguente codice e confronta i risultati
var_dump( $wp_query );
query_posts( '&posts_per_page=-1' );
var_dump( $wp_query );
get_posts e WP_Query sono il modo corretto per costruire query secondarie ( come post correlati, slider, contenuti in evidenza e contenuti su pagine frontali statiche ). È importante notare che non dovresti utilizzare nessuno dei due al posto della query principale nella home page, nella pagina singola o in qualsiasi tipo di pagina di archivio, poiché romperà la funzionalità della pagina. Se devi modificare la query principale, usa pre_get_posts per farlo, e non una query personalizzata. (AGGIORNAMENTO: Per le pagine frontali statiche e le pagine vere, vedi Usare pre_get_posts su pagine vere e pagine frontali statiche*)
In sostanza, WP_Query è utilizzato dalla query principale ed è anche utilizzato da get_posts, ma sebbene get_posts() utilizzi WP_Query, ci sono alcune differenze
get_postsè più veloce diWP_Query. Il margine dipende dalla quantità totale di post del sito. Il motivo è cheget_postspassa'no_found_rows' => truedi default aWP_Query, il quale salta/rompe legalmente la paginazione. Con'no_found_rows' => true,WP_Queryottiene il numero di post richiesti, poi interrompe, mentre di default cerca ulteriormente tutti i post corrispondenti alla query per calcolare la paginazione.Per questo motivo,
get_posts()dovrebbe essere utilizzato solo per query non paginate. Paginareget_postsè davvero un grosso pasticcio.WP_Querydovrebbe essere utilizzato per tutte le query paginateget_posts()non è influenzato dai filtriposts_*mentreWP_Queryne è influenzato. Il motivo è cheget_posts, di default, passa'suppress_filters' => trueaWP_Queryget_postsha alcuni parametri extra comeinclude,exclude,numberpostsecategory. Questi parametri vengono convertiti in parametri validi perWP_Queryprima di essere passati aWP_Query.includeviene convertito inpost__in,excludeinpost__not_in,categoryincatenumberpostsinposts_per_page. Solo una nota, tutti i parametri che possono essere passati aWP_Queryfunzionano conget_posts, puoi ignorare e non utilizzare i parametri di default diget_postsget_postsrestituisce solo la proprietà$postsdiWP_QuerymentreWP_Queryrestituisce l'oggetto completo. Questo oggetto è molto utile quando si tratta di condizionali, paginazione e altre informazioni utili che possono essere utilizzate all'interno del loop.get_postsnon utilizza il loop, ma un cicloforeachper visualizzare i post. Inoltre, nessun template tag è disponibile di default.setup_postdata( $post )deve essere utilizzato per rendere disponibili i template tag.WP_Queryutilizza il loop e i template tag sono disponibili di defaultget_postspassa'ignore_sticky_posts' => 1aWP_Query, quindiget_postsdi default ignora i post sticky
In base a quanto sopra, se utilizzare get_posts o WP_Query dipende da te e da ciò di cui hai effettivamente bisogno dalla query. Quanto sopra dovrebbe guidarti nella tua scelta
Vorrei poter mettere tra i preferiti le risposte. Questo spiega così tanto.
InanisAtheos
Ottima spiegazione!
"get_posts() dovrebbe essere usato solo per query non paginate. Paginare get_posts è davvero un grande casino. WP_Query dovrebbe essere usato per tutte le query paginate" è fondamentalmente tutto ciò che qualcuno ha bisogno di sapere secondo me.
Bullyen
La differenza fondamentale è che query_posts() è utile solo per modificare il Loop corrente. Una volta terminato, è necessario ripristinare il loop e lasciarlo proseguire. Questo metodo è anche un po' più semplice da comprendere, principalmente perché la tua "query" è sostanzialmente una stringa URL che passi alla funzione, in questo modo:
query_posts('meta_key=colore&meta_value=blu');
D'altra parte, WP_Query è uno strumento più generico e somiglia più alla scrittura diretta di query MySQL rispetto a query_posts(). Puoi usarlo ovunque (non solo nel Loop) e non interferisce con le query di articoli attualmente in esecuzione.
Personalmente, tendo a usare WP_Query più spesso. In definitiva, la scelta dipenderà dal tuo caso specifico.
Non c'è assolutamente bisogno di utilizzare query_posts(). Tutto ciò che fa è istanziare un nuovo oggetto WP_Query e riassegnare quel nuovo oggetto a global wp_query.
Per riferimento, la seguente è la funzione effettiva di query_posts().
function query_posts($query) {
$GLOBALS['wp_query'] = new WP_Query();
return $GLOBALS['wp_query']->query($query);
}
Istanzia il tuo oggetto WP_Query se vuoi creare uno script di query personalizzato avanzato. Oppure usa get_posts() se tutto ciò che devi fare è qualche leggera modifica qua e là.
In ogni caso, ti consiglio vivamente di farti un favore e andare in wp_includes/query.php e esaminare la classe WP_Query.
- query_posts(): potrebbe essere utilizzato in un unico caso se è necessario modificare la query principale. Imposta molte variabili globali;
- get_posts(): è molto simile nel funzionamento e accetta gli stessi argomenti, ma restituisce un array di post
- WP_Query: puoi creare e lavorare con un tuo oggetto di questa classe. Un po' più complesso, meno restrizioni, è sicuro da usare ovunque.