Domanda essenziale
Scavo di Let in trio: ::query_posts, ::get_postse class WP_Queryper capire ::query_postsmeglio.
La pietra angolare per ottenere i dati in WordPress è la WP_Queryclasse. Entrambi i metodi ::query_postse ::get_postsusano quella classe.
Nota che la classe WP_Querycontiene anche i metodi con lo stesso nome: WP_Query::query_postse WP_Query::get_posts, ma in realtà consideriamo solo i metodi globali, quindi non confonderti.

Capire il WP_Query
La classe chiamata WP_Queryè stata introdotta nel 2004. Tutti i campi con il segno umbrella (ombrello) erano presenti nel 2004. I campi aggiuntivi sono stati aggiunti in seguito.
Ecco la WP_Querystruttura:
class WP_Query (as in WordPress v4.7)
public $query; ☂
public $query_vars = array(); ☂
public $tax_query;
public $meta_query = false;
public $date_query = false;
public $queried_object; ☂
public $queried_object_id; ☂
public $request;
public $posts; ☂
public $post_count = 0; ☂
public $current_post = -1; ☂
public $in_the_loop = false;
public $post; ☂
public $comments;
public $comment_count = 0;
public $current_comment = -1;
public $comment;
public $found_posts = 0;
public $max_num_pages = 0;
public $max_num_comment_pages = 0;
public $is_single = false; ☂
public $is_preview = false; ☂
public $is_page = false; ☂
public $is_archive = false; ☂
public $is_date = false; ☂
public $is_year = false; ☂
public $is_month = false; ☂
public $is_day = false; ☂
public $is_time = false; ☂
public $is_author = false; ☂
public $is_category = false; ☂
public $is_tag = false;
public $is_tax = false;
public $is_search = false; ☂
public $is_feed = false; ☂
public $is_comment_feed = false;
public $is_trackback = false; ☂
public $is_home = false; ☂
public $is_404 = false; ☂
public $is_embed = false;
public $is_paged = false;
public $is_admin = false; ☂
public $is_attachment = false;
public $is_singular = false;
public $is_robots = false;
public $is_posts_page = false;
public $is_post_type_archive = false;
private $query_vars_hash = false;
private $query_vars_changed = true;
public $thumbnails_cached = false;
private $stopwords;
private $compat_fields = array('query_vars_hash', 'query_vars_changed');
private $compat_methods = array('init_query_flags', 'parse_tax_query');
private function init_query_flags()
WP_Query è il coltellino svizzero.
Alcune cose su WP_Query:
- è qualcosa che puoi controllare tramite argomenti passati
- è avido di default
- contiene la sostanza per il looping
- viene salvato nello spazio globale x2
- Può essere primaria o secondaria
- utilizza le classi di aiuto
- ha un pratico
pre_get_postsgancio
- ha anche il supporto per loop nidificati
- contiene la stringa di query SQL
- contiene il numero dei risultati
- contiene i risultati
- contiene l'elenco di tutti i possibili argomenti di query
- contiene le bandiere dei modelli
- ...
Non posso spiegare tutto questo, ma alcuni di questi sono difficili, quindi forniamo brevi suggerimenti.
WP_Query è qualcosa che puoi controllare tramite argomenti passati
The list of the arguments
---
attachment
attachment_id
author
author__in
author__not_in
author_name
cache_results
cat
category__and
category__in
category__not_in
category_name
comments_per_page
day
embed
error
feed
fields
hour
ignore_sticky_posts
lazy_load_term_meta
m
menu_order
meta_key
meta_value
minute
monthnum
name
no_found_rows
nopaging
order
p
page_id
paged
pagename
post__in
post__not_in
post_name__in
post_parent
post_parent__in
post_parent__not_in
post_type
posts_per_page
preview
s
second
sentence
static
subpost
subpost_id
suppress_filters
tag
tag__and
tag__in
tag__not_in
tag_id
tag_slug__and
tag_slug__in
tb
title
update_post_meta_cache
update_post_term_cache
w
year
Questo elenco di WordPress versione 4.7 cambierà sicuramente in futuro.
Questo sarebbe l'esempio minimo che crea l' WP_Queryoggetto dagli argomenti:
// WP_Query arguments
$args = array ( /* arguments*/ );
// creating the WP_Query object
$query = new WP_Query( $args );
// print full list of arguments WP_Query can take
print ( $query->query_vars );
WP_Query è goloso
Nato dall'idea, gli get all you cansviluppatori di WordPress hanno deciso di ottenere tutti i dati possibili in anticipo poiché ciò è positivo per le prestazioni . Questo è il motivo per cui, per impostazione predefinita, quando la query riceve 10 post dal database, otterrà anche i termini e i metadati per questi post tramite query separate. Termini e metadati verranno memorizzati nella cache (precaricati).
Si noti che la memorizzazione nella cache è solo per la durata della singola richiesta.
È possibile disattivare la memorizzazione nella cache se si imposta update_post_meta_cachee update_post_term_cacheai falsedurante l'impostazione degli WP_Queryargomenti. Quando la memorizzazione nella cache è disabilitata, i dati verranno richiesti dal database solo su richiesta.
Per la maggior parte dei blog di WordPress, la memorizzazione nella cache funziona bene, ma ci sono alcune occasioni in cui è possibile disabilitare la memorizzazione nella cache.
WP_Query usa le classi di aiuto
Se hai controllato i WP_Querycampi lì hai questi tre:
public $tax_query;
public $meta_query;
public $date_query;
Puoi immaginare di aggiungerne di nuovi in futuro.

WP_Query contiene la sostanza per il looping
In questo codice:
$query = new WP_Query( $args )
if ( $query->have_posts() ) {
while ( $query->have_posts() ) {
$query->the_post();
potresti notare che WP_Queryha la sostanza che puoi ripetere. Ci sono anche i metodi di supporto. Hai appena impostato il whileciclo.
Nota. fore i whileloop sono semanticamente equivalenti.
WP_Query primario e secondario
In WordPress hai una query primaria e zero o più secondarie .
È possibile non avere la query principale, ma questo va oltre lo scopo di questo articolo.
Query primaria nota come query principale o query normale . La query secondaria ha anche chiamato una query personalizzata .
WordPress utilizza la WP_Rewriteclasse in anticipo per creare gli argomenti della query in base all'URL. Sulla base di questi argomenti memorizza i due oggetti identici nello spazio globale. Entrambi conterranno la query principale.
global $wp_query @since WordPress 1.5
global $wp_the_query @since WordPress 2.1
Quando diciamo query principale pensiamo a queste variabili. Altre query possono essere definite secondarie o personalizzate.
È del tutto legale usare uno global $wp_queryo $GLOBALS['wp_query'], ma usare la seconda notazione è molto più notevole e salva la digitazione di una riga aggiuntiva all'interno dell'ambito delle funzioni.
$GLOBALS['wp_query']e $GLOBALS['wp_the_query']sono oggetti separati. $GLOBALS['wp_the_query']dovrebbe rimanere congelato.
WP_Queryha il pratico pre_get_postsgancio.
Questo è il gancio di azione. Si applicherà a qualsiasi WP_Query istanza. Lo chiami come:
add_action( 'pre_get_posts', function($query){
if ( is_category() && $query->is_main_query() ) {
// set your improved arguments
$query->set( ... );
...
}
return $query;
});
Questo hook è eccezionale e può modificare qualsiasi argomento di query.
Ecco cosa puoi leggere :
Viene generato dopo la creazione dell'oggetto variabile query, ma prima dell'esecuzione della query effettiva.
Quindi questo hook è gestore degli argomenti ma non può creare nuovi WP_Queryoggetti. Se hai avuto una query primaria e una secondaria, pre_get_postsnon puoi creare la terza. O se ne avevi solo uno primario, non è possibile creare il secondario.
Nota nel caso in cui sia necessario modificare la query principale, è possibile utilizzare anche l' requesthook.
WP_Query supporta loop nidificati
Questo scenario può verificarsi se si utilizzano plugin e si richiamano le funzioni dei plugin dal modello.
Ecco l'esempio vetrina di WordPress che ha funzioni di supporto anche per i loop nidificati:
global $id;
while ( have_posts() ) : the_post();
// the custom $query
$query = new WP_Query( array( 'posts_per_page' => 5 ) );
if ( $query->have_posts() ) {
while ( $query->have_posts() ) : $query->the_post();
echo '<li>Custom ' . $id . '. ' . get_the_title() . '</li>';
endwhile;
}
wp_reset_postdata();
echo '<li>Main Query ' . $id . '. ' . get_the_title() . '</li>';
endwhile;
L'output sarà così da quando ho installato i dati di test dell'unità tematica :
Custom 100. Template: Sticky
Custom 1. Hello world!
Custom 10. Markup: HTML Tags and Formatting
Custom 11. Markup: Image Alignment
Custom 12. Markup: Text Alignment
Custom 13. Markup: Title With Special Characters
Main Query 1. Hello world!
Anche se ho richiesto 5 post nella query $ personalizzata, ne restituirò sei, perché il post appiccicoso andrà avanti. Se wp_reset_postdatanell'esempio precedente non è presente l'output sarà così, perché $GLOBALS['post']non sarà valido.
Custom 1001. Template: Sticky
Custom 1. Hello world!
Custom 10. Markup: HTML Tags and Formatting
Custom 11. Markup: Image Alignment
Custom 12. Markup: Text Alignment
Custom 13. Markup: Title With Special Characters
Main Query 13. Markup: Title With Special Characters
WP_Queryha wp_reset_queryfunzione
Questo è come un pulsante di ripristino. $GLOBALS['wp_the_query']dovrebbe essere congelato tutto il tempo e plug-in o temi non dovrebbero mai modificarlo.
Ecco cosa wp_reset_queryfare:
function wp_reset_query() {
$GLOBALS['wp_query'] = $GLOBALS['wp_the_query'];
wp_reset_postdata();
}
Osservazioni su get_posts
get_posts sembra
File: /wp-includes/post.php
1661: function get_posts( $args = null ) {
1662: $defaults = array(
1663: 'numberposts' => 5,
1664: 'category' => 0, 'orderby' => 'date',
1665: 'order' => 'DESC', 'include' => array(),
1666: 'exclude' => array(), 'meta_key' => '',
1667: 'meta_value' =>'', 'post_type' => 'post',
1668: 'suppress_filters' => true
1669: );
... // do some argument parsing
1685: $r['ignore_sticky_posts'] = true;
1686: $r['no_found_rows'] = true;
1687:
1688: $get_posts = new WP_Query;
1689: return $get_posts->query($r);
I numeri di riga potrebbero cambiare in futuro.
E 'solo un involucro intorno WP_Queryche restituisce i messaggi oggetto query.
L' ignore_sticky_postsimpostazione su true indica che i post appiccicosi possono essere visualizzati solo in una posizione naturale. Non ci saranno messaggi appiccicosi nella parte anteriore. L'altro no_found_rowsimpostato su true indica che l'API del database WordPress non verrà utilizzata SQL_CALC_FOUND_ROWSper implementare l'impaginazione, riducendo il carico sul database per eseguire il conteggio delle righe trovate .
Questo è utile quando non è necessario l'impaginazione. Comprendiamo ora che possiamo imitare questa funzione con questa query:
$args = array ( 'ignore_sticky_posts' => true, 'no_found_rows' => true);
$query = new WP_Query( $args );
print( $query->request );
Ecco la richiesta SQL corrispondente:
SELECT wp_posts.ID FROM wp_posts WHERE 1=1 AND wp_posts.post_type = 'post' AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private') ORDER BY wp_posts.post_date DESC LIMIT 0, 10
Confronta ciò che abbiamo ora con la precedente richiesta SQL dove SQL_CALC_FOUND_ROWSesiste.
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts WHERE 1=1 AND wp_posts.post_type = 'post' AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private') ORDER BY wp_posts.post_date DESC LIMIT 0, 10
La richiesta senza SQL_CALC_FOUND_ROWSsarà più veloce.
Osservazioni su query_posts
Suggerimento: all'inizio nel 2004 ce n'era solo global $wp_query. A partire dalla versione WordPress 2.1 è $wp_the_queryarrivata. Suggerimento: $GLOBALS['wp_query']e $GLOBALS['wp_the_query']sono oggetti separati.
query_posts()è WP_Querywrapper. Restituisce il riferimento WP_Queryall'oggetto principale e allo stesso tempo imposta il global $wp_query.
File: /wp-includes/query.php
function query_posts($args) {
$GLOBALS['wp_query'] = new WP_Query();
return $GLOBALS['wp_query']->query($args);
}
In PHP4 tutto, compresi gli oggetti, veniva passato per valore. query_postsera così:
File: /wp-includes/query.php (WordPress 3.1)
function &query_posts($args) {
unset($GLOBALS['wp_query']);
$GLOBALS['wp_query'] =& new WP_Query();
return $GLOBALS['wp_query']->query($args);
}
Si noti che nello scenario tipico con una query primaria e una secondaria abbiamo queste tre variabili:
$GLOBALS['wp_the_query']
$GLOBALS['wp_query'] // should be the copy of first one
$custom_query // secondary
Diciamo che ciascuno di questi tre richiede 1 milione di memoria. Il totale sarebbe 3M di memoria. Se lo utilizziamo query_posts, $GLOBALS['wp_query']verrà disattivato e creato nuovamente.
PHP5 + dovrebbe essere intelligente per svuotare l' $GLOBALS['wp_query']oggetto, proprio come in PHP4 l'abbiamo fatto conunset($GLOBALS['wp_query']);
function query_posts($args) {
$GLOBALS['wp_query'] = new WP_Query();
return $GLOBALS['wp_query']->query($args);
}
Di conseguenza query_postsconsuma 2 M di memoria in totale, mentre get_postsconsuma 3 M di memoria.
Nota in query_postsnon stiamo restituendo l'oggetto reale, ma un riferimento all'oggetto.
Da php.net : un riferimento PHP è un alias, che consente a due diverse variabili di scrivere sullo stesso valore. A partire da PHP 5, una variabile oggetto non contiene più l'oggetto stesso come valore. Contiene solo un identificatore di oggetto che consente agli acceditori di oggetti di trovare l'oggetto reale. Quando un oggetto viene inviato per argomento, restituito o assegnato a un'altra variabile, le diverse variabili non sono alias: contengono una copia dell'identificatore, che punta allo stesso oggetto.
Anche in PHP5 + l'operatore assegnato (=) è intelligente. Userà superficiale copia e la copia oggetto non è difficile. Quando scriviamo in questo $GLOBALS['wp_query'] = $GLOBALS['wp_the_query'];modo verranno copiati solo i dati, non l'intero oggetto poiché condividono lo stesso tipo di oggetto.
Ecco un esempio
print( md5(serialize($GLOBALS['wp_the_query']) ) );
print( md5(serialize($GLOBALS['wp_query'] ) ) );
query_posts( '' );
print( md5(serialize($GLOBALS['wp_the_query']) ) );
print( md5(serialize($GLOBALS['wp_query'] ) ) );
Risulterà:
f14153cab65abf1ea23224a1068563ef
f14153cab65abf1ea23224a1068563ef
f14153cab65abf1ea23224a1068563ef
d6db1c6bfddac328442e91b6059210b5
Prova a reimpostare la query:
print( md5(serialize($GLOBALS['wp_the_query'] ) ) );
print( md5(serialize($GLOBALS['wp_query'] ) ) );
query_posts( '' );
wp_reset_query();
print( md5(serialize($GLOBALS['wp_the_query'] ) ) );
print( md5(serialize($GLOBALS['wp_query'] ) ) );
Risulterà:
f14153cab65abf1ea23224a1068563ef
f14153cab65abf1ea23224a1068563ef
f14153cab65abf1ea23224a1068563ef
f14153cab65abf1ea23224a1068563ef
Puoi creare problemi anche se lo usi WP_Query
print( md5(serialize($GLOBALS['wp_the_query'] ) ) );
print( md5(serialize($GLOBALS['wp_query'] ) ) );
global $wp_query;
$wp_query = new WP_Query( array( 'post_type' => 'post' ) );
print( md5(serialize($GLOBALS['wp_the_query'] ) ) );
print( md5(serialize($GLOBALS['wp_query'] ) ) );
Naturalmente, la soluzione sarebbe quella di utilizzare wp_reset_querynuovamente la funzione.
print( md5(serialize($GLOBALS['wp_the_query'] ) ) );
print( md5(serialize($GLOBALS['wp_query'] ) ) );
global $wp_query;
$wp_query = new WP_Query( array( 'post_type' => 'post' ) );
wp_reset_query();
print( md5(serialize($GLOBALS['wp_the_query'] ) ) );
print( md5(serialize($GLOBALS['wp_query'] ) ) );
Questo è il motivo per cui penso che query_postspotrebbe essere migliore dal punto di vista della memoria. Ma dovresti sempre fare wp_reset_queryscherzi.