Query_posts () neden kullanımdan kaldırıldı olarak işaretlenmiyor?


15

query_posts()Teknik olarak konuşan iki işlev vardır . Biri query_posts()aslında WP_Query::query_posts()diğeri küresel alanda.

Akıl sağlığından sormak:

Eğer küresel query_posts()"kötülük" ise neden itiraz edilmiyor?

Veya neden olarak işaretlenmiyor _doing_it_wong.


2
Bu harika bir soru! Buna rastlayan diğerleri için query_posts () kullanmamanız gerektiğini neden bilmeyenler için, burada ve burada üzerinde iyi bir Q & A astarı var.
Tim Malone

Yanıtlar:


11

Temel soru

Üçlü içine edelim kazı: ::query_posts, ::get_postsve class WP_Queryanlamak için ::query_postsdaha iyi.

WordPress'te veri almanın temel taşı WP_Querysınıftır. Yöntemler Hem ::query_postsve ::get_postssınıf kullanan.

Sınıfın WP_Queryaynı ada sahip yöntemleri de içerdiğini unutmayın : WP_Query::query_postsve WP_Query::get_postsancak aslında sadece global yöntemleri düşünüyoruz, bu yüzden kafa karıştırmayın.

resim açıklamasını buraya girin

Anlamak WP_Query

Çağrılan sınıf WP_Query2004 yılında yeniden tanıtıldı. 2004'te mevcut olan ☂ (şemsiye) işaretine sahip tüm alanlar. Daha sonra ek alanlar eklenmiştir.

İşte WP_Queryyapı:

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 İsviçre çakısıdır.

Hakkında bazı şeyler WP_Query:

  • geçtiğiniz argümanlar ile kontrol edebileceğiniz bir şey
  • varsayılan olarak açgözlü
  • döngü için maddeyi tutar
  • x2 global alanına kaydedilir
  • birincil veya ikincil olabilir
  • yardımcı sınıfları kullanır
  • kullanışlı bir pre_get_postskancası var
  • iç içe döngüler için bile desteği var
  • SQL sorgu dizesini tutar
  • sonuçların sayısını tutar
  • sonuçları tutar
  • olası tüm sorgu bağımsız değişkenlerinin listesini tutar
  • şablon bayraklarını tutar
  • ...

Tüm bunları açıklayamıyorum, ancak bunların bazıları zor, bu yüzden kısa ipuçları verelim.

WP_Query geçtiğiniz argümanlar ile kontrol edebileceğiniz bir şeydir

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

WordPress sürüm 4.7'deki bu liste gelecekte kesinlikle değişecektir.

Bu WP_Query, bağımsız değişkenlerden nesneyi oluşturan en az örnek olacaktır :

// 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 açgözlü

get all you canWordPress geliştiricileri , performans için iyi olduğu için mümkün olan tüm verileri erkenden almaya karar verdikleri fikri üzerine kuruldu . Bu nedenle, sorgu veritabanından 10 yazı aldığında varsayılan olarak, bu yazıların terimlerini ve meta verilerini ayrı sorgular yoluyla alır. Terimler ve meta veriler önbelleğe alınır (önceden getirilir).

Önbelleklemenin yalnızca tek bir istek ömrü için olduğunu unutmayın.

Eğer ayarlarsanız önbelleğe alma devre dışı bırakabilir update_post_meta_cacheve update_post_term_cachekarşı falseayarlarken WP_Queryargümanlar. Önbellek devre dışı bırakıldığında, veriler yalnızca istek üzerine veritabanından istenir.

WordPress bloglarının çoğunda önbellekleme iyi çalışır, ancak önbelleği devre dışı bırakabileceğiniz bazı durumlar vardır.

WP_Query yardımcı sınıfları kullanır

WP_QueryOrada alanları işaretlediyseniz , şu üç tanesine sahipsiniz:

public $tax_query;
public $meta_query;
public $date_query;

Gelecekte yeni eklemeyi hayal edebilirsiniz.

resim açıklamasını buraya girin

WP_Query Döngü maddesini tutar

Bu kodda:

$query = new WP_Query( $args )
if ( $query->have_posts() ) {
        while ( $query->have_posts() ) {
            $query->the_post();

WP_Queryyineleyebileceğiniz maddeye sahip olduğunu fark edebilirsiniz. Yardımcı yöntemler de var. Sadece whiledöngüyü ayarladýn .

Not. forve whiledöngüler semantik olarak eşdeğerdir.

WP_Query birincil ve ikincil

WordPress'te bir birincil ve sıfır veya daha fazla ikincil sorgunuz vardır.

Birincil sorguya sahip olmak mümkün değildir, ancak bu makalenin kapsamı dışındadır.

Ana sorgu veya normal sorgu olarak bilinen birincil sorgu . İkincil sorgu , özel sorgu olarak da adlandırılır .

WordPress WP_Rewrite, URL'ye dayalı sorgu bağımsız değişkenleri oluşturmak için sınıfı erken kullanır . Bu argümanlara dayanarak, küresel alanda iki özdeş nesneyi saklar. Bunların her ikisi de ana sorguyu tutacaktır.

global $wp_query   @since WordPress 1.5
global $wp_the_query @since WordPress 2.1

Biz derken ana sorgu biz bu değişkenlerden düşünüyorum. Diğer sorgular ikincil veya özel olarak adlandırılabilir.

Kullanımı ya tamamen yasaldır global $wp_queryya $GLOBALS['wp_query'], ama ikinci gösterimi kullanarak çok daha dikkate değer olduğunu ve işlevlerin kapsamı içine ek bir satır yazarak kaydeder.

$GLOBALS['wp_query']ve $GLOBALS['wp_the_query']ayrı nesnelerdir. $GLOBALS['wp_the_query']donmuş kalmalıdır.

WP_Querykullanışlı pre_get_postskanca var.

Bu eylem kancası. Herhangi bir WP_Query örnek için geçerli olacaktır . Buna şöyle diyorsunuz:

add_action( 'pre_get_posts', function($query){

 if ( is_category() && $query->is_main_query() ) {
    // set your improved arguments
    $query->set( ... );  
    ...  
 }

 return $query;  
});

Bu kanca harika ve herhangi bir sorgu bağımsız değişkenini değiştirebilir.

İşte okuyabileceğiniz şeyler :

Sorgu değişkeni nesnesi oluşturulduktan sonra, ancak gerçek sorgu çalıştırılmadan önce tetiklenir.

Yani bu kanca argüman yöneticisidir ancak yeni WP_Querynesneler oluşturamaz . Bir birincil ve bir ikincil sorgunuz varsa, pre_get_postsüçüncü sorguyu oluşturamazsınız. Veya sadece bir birinciliniz varsa, ikinciyi oluşturamaz.

Ana sorguyu değiştirmeniz gerektiğinde, sadece requestkanca kullanabilirsiniz .

WP_Query iç içe halkaları destekler

Eklenti kullanıyorsanız ve şablondan eklenti işlevlerini çağırırsanız bu senaryo oluşabilir.

WordPress'in iç içe döngüler için bile yardımcı işlevlere sahip olduğu vitrin örneği:

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;

Tema birimi test verilerini kurduğumdan çıktı şu şekilde olacak :

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!

Özel $ sorgusunda 5 mesaj istediğim halde, yapışkan yazı devam edeceği için bana altı dönecek. wp_reset_postdataÖnceki örnekte hayır varsa , çıkış $GLOBALS['post']geçersiz olacağından çıktı bu şekilde olacaktır.

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_Queryvardır wp_reset_queryişlevi

Bu bir sıfırlama düğmesi gibidir. $GLOBALS['wp_the_query']her zaman dondurulmalı ve eklentiler veya temalar asla değiştirilmemelidir.

İşte wp_reset_queryyapmanız gerekenler:

function wp_reset_query() {
    $GLOBALS['wp_query'] = $GLOBALS['wp_the_query'];
    wp_reset_postdata();
}

İle ilgili açıklamalar get_posts

get_posts benziyor

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

Satır numaraları gelecekte değişebilir.

Bu sadece bir olan sarıcı etrafında WP_Queryo iadeler sorgu nesnesi mesajlar.

ignore_sticky_postsGerçek araçlarına seti yapışkan mesajlar sadece doğal bir konumda gösterilmesine olabilir. Ön kısımda yapışkan yazı olmayacak. Diğer no_found_rowstrue olarak ayarlandığında, WordPress veritabanı API'sinin sayfa SQL_CALC_FOUND_ROWSnumaralandırma uygulamak için kullanılmayacağı, bulunan satırları yürütmek için veritabanındaki yükün azaltılacağı anlamına gelir sayısını .

Sayfalandırmaya ihtiyacınız olmadığında kullanışlıdır. Şimdi anlıyoruz ki bu sorgu ile bu fonksiyonu taklit edebiliriz:

$args = array ( 'ignore_sticky_posts' => true, 'no_found_rows' => true);
$query = new WP_Query( $args );
print( $query->request );

İlgili SQL isteği şöyledir:

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

Şu anda sahip olduklarımızı, önceki SQL isteğiyle karşılaştırın SQL_CALC_FOUND_ROWS.

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

Olmadan istek SQL_CALC_FOUND_ROWSdaha hızlı olacaktır.

İle ilgili açıklamalar query_posts

İpucu: İlk olarak 2004'te sadece vardı global $wp_query. WordPress 2.1 sürümünden itibaren $wp_the_querygeldi. İpucu: $GLOBALS['wp_query']ve $GLOBALS['wp_the_query']ayrı nesnelerdir.

query_posts()bir WP_Querysargı. Ana WP_Querynesneye başvuruyu döndürür ve aynı zamanda global $wp_query.

File: /wp-includes/query.php
function query_posts($args) {
    $GLOBALS['wp_query'] = new WP_Query();
    return $GLOBALS['wp_query']->query($args);
}

PHP4'te nesneler dahil her şey değere göre geçirildi. query_postsşöyleydi:

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

Bir birincil ve bir ikincil sorgu içeren tipik senaryoda şu üç değişkene sahip olduğumuzu lütfen unutmayın:

$GLOBALS['wp_the_query'] 
$GLOBALS['wp_query'] // should be the copy of first one
$custom_query // secondary

Diyelim ki bu üçünün her biri 1M bellek alıyor. Toplam 3M bellek olacaktır. Eğer kullanırsak query_posts, $GLOBALS['wp_query']ayarlanmayacak ve yeniden yaratılacaktır.

PHP5 + $GLOBALS['wp_query']nesneyi boşaltmak için akıllı olmalı , tıpkı PHP4'te olduğu gibiunset($GLOBALS['wp_query']);

function query_posts($args) {
    $GLOBALS['wp_query'] = new WP_Query();
    return $GLOBALS['wp_query']->query($args);
}

Sonuç olarak query_poststoplamda 2M bellek get_poststüketirken, 3M bellek tüketir.

query_postsGerçek nesneyi değil, nesneye bir referans döndürdüğümüzü unutmayın .

Gönderen php.net : bir PHP referans aynı değere yazma için iki farklı değişkenleri sağlayan bir diğer addır. PHP 5'ten itibaren, bir nesne değişkeni artık değer olarak nesnenin kendisini içermez. Yalnızca nesne erişimcilerinin gerçek nesneyi bulmasına izin veren bir nesne tanımlayıcı içerir. Bir nesne bağımsız değişkenle gönderildiğinde, döndürüldüğünde veya başka bir değişkene atandığında, farklı değişkenler takma ad değildir: tanımlayıcının aynı nesneyi işaret eden bir kopyasını tutarlar.

Ayrıca PHP5 + 'da assign (=) operatörü akıllıdır. Sert kopya değil, sığ kopya kullanır . Bu şekilde yazdığımızda $GLOBALS['wp_query'] = $GLOBALS['wp_the_query'];, veriler aynı nesne türünü paylaştığından tüm veriler değil, yalnızca veriler kopyalanacaktır.

İşte bir örnek

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'] ) ) );

Sonuçlanacak:

f14153cab65abf1ea23224a1068563ef
f14153cab65abf1ea23224a1068563ef
f14153cab65abf1ea23224a1068563ef
d6db1c6bfddac328442e91b6059210b5

Sorguyu sıfırlamayı deneyin:

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'] ) ) );

Sonuçlanacak:

f14153cab65abf1ea23224a1068563ef
f14153cab65abf1ea23224a1068563ef
f14153cab65abf1ea23224a1068563ef
f14153cab65abf1ea23224a1068563ef

Kullansanız bile sorun yaratabilirsiniz 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'] ) ) );

Tabii ki, çözüm wp_reset_queryişlevi tekrar kullanmak olacaktır .

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'] ) ) );

Bu yüzden query_postsbellek açısından daha iyi olabileceğini düşünüyorum . Ama her zaman wp_reset_queryhile yapmalısın .


10

Sadece yeni trac bilet oluşturduk bilet # 36874 arasında itirazın önerecek, query_posts(). Kabul edilip edilmeyeceği iyi bir soru olmaya devam etmektedir.

Asıl büyük sorun query_posts(), neden hiç kullanmamanız gerektiği konusunda gerçekten iyi yazılar olmasına rağmen, eklentiler ve temalar tarafından hala yaygın olarak kullanılmasıdır . Bence burada WPSE'deki en destansı yazı şudur:

kullanımdan kaldırma! == kaldırma , bu nedenle kullanımdan kaldırma , query_posts()kalitesiz geliştiriciler ve WordPress'i bilmeyen ve kalitesiz öğreticileri kural olarak kullanan kişiler tarafından kullanımını durdurmaz. İnsanlar kullandığınız yere Sadece bazı kanıtı olarak, biz hala burada kaç soru alabilirim caller_get_postsiçinde WP_Query? Uzun yıllardır kullanımdan kaldırıldı.

Ancak, kullanımdan kaldırılan işlevler ve bağımsız değişkenler, çekirdek geliştiricilerin uygun gördüğü her an kaldırılabilir, ancak bu muhtemelen hiçbir zaman gerçekleşmeyecektir, query_posts()çünkü bu milyonlarca siteyi kıracaktır. Yani evet, muhtemelen hiçbir zaman tamamen kaldırılmayacağını göreceğiz query_posts()- bu muhtemelen hiç bir zaman kullanımdan kaldırılmayacak.

Ancak bu bir başlangıç ​​noktasıdır, ancak hatırlamak gerekir, WordPress'teki bir şeyi reddetmek kullanımını durdurmaz.

GÜNCELLEME 19 Mayıs 2016

Kaldırdığım bilet şimdi kapatıldı ve alışılmadık olarak kapatılan ve yeniden açık kalan ve hala çözülmemiş olan 4 yaşındaki bir bilete kopya olarak işaretlendi .

Çekirdek geliştiriciler bu eski sadık küçük kötülüğe dayanıyor gibi görünüyor. Herkes ilgileniyor, burada yinelenen 4 yaşındaki bilet


Neden core.trac.wordpress.org/ticket/36874 biletini kapattılar ? Eğer bilet içinde bu konuya yönelik bir bağlantı bulunmasını can @PieterGoosen Lütfen core.trac.wordpress.org/ticket/36874 1: Bu soru bilet 1 ile ilgilidir beri
prosti

@prosti Görünüşe göre bu sorun zaten gündeme getirildiği için kopya olarak işaretlendi ... 4 yıl önce burada bulundu .
Howdy_McGee

3

[biraz rant]

Bu noktada ayakta duran temel felsefe hiçbir şeyin gerçekten itiraz edilmediğidir. Kullanımdan çıkarma bildirimi, sahip olmak güzel olsa da, işlev bir noktada gerçekten bırakılmayacaksa, göz ardı edilecektir. WP_DEBUGÜzerinde gelişmeyen ve gerçek bir kırılma olmazsa bildirimi fark etmeyecek birçok insan var.

OTOH eli, bu işlev gotoifade gibidir. Şahsen hiç kullanmadım (daha sonra daha küçük tanım için) gotoama varsayılan olarak kötülük olmadığı bazı durumlara işaret eden argümanları anlayabiliyorum. Aynı şey query_posts, basit bir döngü oluşturmak için gereken tüm globalleri kurmanın basit bir yoludur ve ajax veya rest-api bağlamında yararlı olabilir. Ben asla bu bağlamlarda kullanmazdım, ama orada görebiliyorum, daha çok kodlama tarzı bir sorun, sonra bir işlev kendi başına kötü oluyor.

Biraz daha derine inerken, asıl sorun küresellerin hiç ayarlanması gerektiğidir. Onları ayarlamaya yardımcı olan tek işlev değil ana sorun budur.


Ve karşılaştırma için, query_postsikincil bir sorgudan gerçekten daha yavaştır (okuma: ana sorgu değil).
prosti

@prosti, sadece bir wp_query kurar ve çalıştırır, ne kadar yavaş olabilir? Tabii bazı yükü var ama biz muhtemelen milisaniye burada konuşuyor. Bu elbette WP'nin varsayılan olarak bir sorgu sağlamadığı yerlerde kullandığınızı varsayar. Kötü olduğu yerlerde, query_postskendisi değil, WP yüklenirken yapılan işe yaramaz sorgu
Mark Kaplun
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.