Domanda essenziale
Scavo di Let in trio: ::query_posts
, ::get_posts
e class WP_Query
per capire ::query_posts
meglio.
La pietra angolare per ottenere i dati in WordPress è la WP_Query
classe. Entrambi i metodi ::query_posts
e ::get_posts
usano quella classe.
Nota che la classe WP_Query
contiene anche i metodi con lo stesso nome: WP_Query::query_posts
e 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_Query
struttura:
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_posts
gancio
- 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_Query
oggetto 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 can
sviluppatori 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_cache
e update_post_term_cache
ai false
durante l'impostazione degli WP_Query
argomenti. 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_Query
campi 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_Query
ha la sostanza che puoi ripetere. Ci sono anche i metodi di supporto. Hai appena impostato il while
ciclo.
Nota. for
e i while
loop 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_Rewrite
classe 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_query
o $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_Query
ha il pratico pre_get_posts
gancio.
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_Query
oggetti. Se hai avuto una query primaria e una secondaria, pre_get_posts
non 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' request
hook.
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_postdata
nell'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_Query
ha wp_reset_query
funzione
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_query
fare:
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_Query
che restituisce i messaggi oggetto query.
L' ignore_sticky_posts
impostazione 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_rows
impostato su true indica che l'API del database WordPress non verrà utilizzata SQL_CALC_FOUND_ROWS
per 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_ROWS
esiste.
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_ROWS
sarà 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_query
arrivata. Suggerimento: $GLOBALS['wp_query']
e $GLOBALS['wp_the_query']
sono oggetti separati.
query_posts()
è WP_Query
wrapper. Restituisce il riferimento WP_Query
all'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_posts
era 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_posts
consuma 2 M di memoria in totale, mentre get_posts
consuma 3 M di memoria.
Nota in query_posts
non 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_query
nuovamente 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_posts
potrebbe essere migliore dal punto di vista della memoria. Ma dovresti sempre fare wp_reset_query
scherzi.