Perché query_posts () non è contrassegnato come obsoleto?


15

Ci sono due query_posts()funzioni tecnicamente parlando. Uno query_posts()è in realtà WP_Query::query_posts()e l'altro è nello spazio globale.

Chiedere dal buonsenso:

Se globale query_posts()è quel "male" perché non è deprecato?

O perché non è contrassegnato come _doing_it_wong.


2
Questa è un'ottima domanda! Per gli altri che si imbattono in questo che non sanno perché non dovresti usare query_posts (), qui e qui ci sono alcune buone domande e risposte sul primer.
Tim Malone,

Risposte:


11

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.

inserisci qui la descrizione dell'immagine

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.

inserisci qui la descrizione dell'immagine

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.


10

Ho appena creato un nuovo biglietto trac, il biglietto # 36874 , per proporre l' ammortamento di query_posts(). Se sarà accettato o meno rimane una buona domanda.

Il vero grosso problema query_posts()è che è ancora ampiamente utilizzato da plugin e temi, anche se ci sono stati davvero buoni scritti sull'argomento del perché dovresti MAI MAI MAI usarlo. Penso che il post più epico qui su WPSE sia il seguente:

deprecation! == rimozione , quindi il deprezzamento query_posts()non ne fermerà l'utilizzo da parte di sviluppatori di bassa qualità e persone in generale che non conoscono WordPress e che usano tutorial di scarsa qualità come linee guida. Proprio come una prova, quante domande abbiamo ancora qui dove le persone usanocaller_get_posts in WP_Query? È stato deprecato per molti anni ormai.

Le funzioni e gli argomenti obsoleti possono tuttavia essere rimossi in qualsiasi momento gli sviluppatori principali ritengono opportuno, ma molto probabilmente questo non accadrà mai con query_posts() poiché ciò spezzerà milioni di siti. Quindi sì, probabilmente non vedremo mai la rimozione totale di query_posts()- il che potrebbe portare al fatto che molto probabilmente non sarà mai deprecato.

Questo è un punto di partenza, ma bisogna ricordare che deprecare qualcosa in WordPress non ne ferma l'uso.

AGGIORNAMENTO 19 maggio 2016

Il biglietto che ho raccolto è ora chiuso e contrassegnato come duplicato di un biglietto di 4 anni , che è stato chiuso come riparato ed è stato riaperto e rimane ancora aperto e non risolto.

Sembra che gli sviluppatori principali stiano aggrappandosi a questo vecchio piccolo fedele fedele. Tutti gli interessati, ecco il biglietto duplicato di 4 anni


Perché hanno chiuso il ticket core.trac.wordpress.org/ticket/36874 ? Per favore, @PieterGoosen, puoi includere il link a questa discussione nel tuo ticket core.trac.wordpress.org/ticket/36874 poiché questa domanda si riferisce al biglietto 1: 1
prosti

@prosti Sembra che sia stato contrassegnato come duplicato in quanto questo problema è già stato sollevato ... 4 anni fa trovato qui .
Howdy_McGee

3

[piuttosto rant]

È la filosofia fondamentale permanente a questo punto che nulla è veramente deprecato. L'avviso di deprecazione, sebbene sia bello da avere, verrà semplicemente ignorato se la funzione non verrà effettivamente abbandonata ad un certo punto. Ci sono molte persone che non si sviluppano conWP_DEBUG on e non noteranno l'avviso se non ci sarà una rottura effettiva.

Mano OTOH, questa funzione è come gotoun'istruzione. Personalmente non l'ho mai usato (per una definizione più piccola di quella prevista)goto quanto mi ma posso capire gli argomenti che indicano una situazione in cui non è malvagia per impostazione predefinita. Lo stesso vale query_posts, è un modo semplice per impostare tutti i globi necessari per creare un semplice ciclo e può essere utile in un contesto Ajax o Rest-API. Non lo userei mai nemmeno in quei contesti, ma vedo che lì, si tratta più di una questione di stile di programmazione che di una funzione malvagia da sola.

Andando un po 'più in profondità, il problema principale è che i globi devono essere impostati affatto. Questo è il problema principale, non l'unica funzione che aiuta a impostarli.


E per il confronto, è davvero query_postspiù lento di una query secondaria (leggi: non la query principale).
prosti

@prosti, in quanto imposta ed esegue un wp_query, quanto può essere più lento? certo c'è un certo sovraccarico ma probabilmente stiamo parlando di millisecondi qui. Questo ovviamente presuppone che lo si usi in luoghi in cui WP non fornisce una query per impostazione predefinita. Nei luoghi in cui lo fa è male, non lo query_postsstesso ma la query inutile che è stata fatta durante il caricamento di WP
Mark Kaplun,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.