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

@scribu d'altra parte 'get_posts' funzionerà anche se non consigliato: http://core.trac.wordpress.org/ticket/16545

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

Non riesco a liberarmi dalla sensazione che questo sia il post più geniale e votato su WPSE. Dovrebbe essere anche nel Codex.

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

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!

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.

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

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.

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

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 il loop in quella domanda è sbagliato e c'è una risposta che spiega il perché.

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.

Ho trovato questo test di velocità tra wp_query e get_posts http://www.wpclocked.com/

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.

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.

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_posts
passa'no_found_rows' => true
di default aWP_Query
, il quale salta/rompe legalmente la paginazione. Con'no_found_rows' => true
,WP_Query
ottiene 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_Query
dovrebbe essere utilizzato per tutte le query paginateget_posts()
non è influenzato dai filtriposts_*
mentreWP_Query
ne è influenzato. Il motivo è cheget_posts
, di default, passa'suppress_filters' => true
aWP_Query
get_posts
ha alcuni parametri extra comeinclude
,exclude
,numberposts
ecategory
. Questi parametri vengono convertiti in parametri validi perWP_Query
prima di essere passati aWP_Query
.include
viene convertito inpost__in
,exclude
inpost__not_in
,category
incat
enumberposts
inposts_per_page
. Solo una nota, tutti i parametri che possono essere passati aWP_Query
funzionano conget_posts
, puoi ignorare e non utilizzare i parametri di default diget_posts
get_posts
restituisce solo la proprietà$posts
diWP_Query
mentreWP_Query
restituisce 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_posts
non utilizza il loop, ma un cicloforeach
per visualizzare i post. Inoltre, nessun template tag è disponibile di default.setup_postdata( $post )
deve essere utilizzato per rendere disponibili i template tag.WP_Query
utilizza il loop e i template tag sono disponibili di defaultget_posts
passa'ignore_sticky_posts' => 1
aWP_Query
, quindiget_posts
di 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.

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.

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.
