WP_query () ne zaman kullanılır, query_posts () ve pre_get_posts


159

@ Nacin's 'in dün Query'yi bilmediğini okudum ve sorgulayıcı bir tavşan deliğinden bir parça aşağı gönderildi. Dünden önce, query_posts()tüm sorgu ihtiyaçları için (yanlış) kullanıyordum . Şimdi kullanma konusunda biraz daha zekiyim WP_Query(), ancak hala bazı gri alanlarım var.

Kesin olarak bildiğimi düşündüğüm şey:

Ben kazanıyorsam ek herhangi bir yere döngüler bir sayfa kenar çubuğunun, bir altbilgi, "ilişkili mesajların", her türlü vb-ı kullanıyor istiyorum WP_Query(). Bunu tek bir sayfada defalarca zarar vermeden kullanabilirim. (sağ?).

Neyi bilmiyorum ki

  1. Ne zaman kullanabilirim nacin en @ pre_get_posts vs. WP_Query()? pre_get_postsŞimdi her şey için kullanmalı mıyım ?
  2. Bir şablon sayfasındaki döngüyü değiştirmek istediğimde - bir taksonomi arşiv sayfasını değiştirmek istediğimi varsayalım - if have_posts : while have_posts : the_postparçayı çıkartıp kendim yazabilir WP_Query()miyim? Yoksa çıktıyı pre_get_postsfunction.php dosyamda kullanarak değiştirir miyim ?

tl; Dr.

Bu konuda çizmek istediğim tl; dr kuralları:

  1. Asla query_postsartık kullanma
  2. Tek bir sayfada birden fazla sorgu çalıştırırken, WP_Query()
  3. Bir döngü değiştirirken, bunu __________________ yapın.

Herhangi bir bilgelik için teşekkürler

havlu kumaş

ps: Gördüm ve okudum: Ne zaman WP_Query vs query_posts () vs get_posts () kullanmalısınız? Başka bir boyut ekler - get_posts. Ama hiç ilgilenmiyor pre_get_posts.



@ saltcod, şimdi farklı, WordPress gelişti, burada kabul edilen cevaba göre birkaç yorum ekledim .
Aralık'ta prosti

Yanıtlar:


145

Söylemeye hakkınız var:

Asla query_postsartık kullanma

pre_get_posts

pre_get_postsherhangi bir sorguyu değiştirmek için kullanılan bir filtredir . En sık yalnızca 'ana sorguyu' değiştirmek için kullanılır:

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

      if( $query->is_main_query() ){
        //Do something to main query
      }
}

(Ayrıca hatalıis_admin() çıkıp dönmediğini de kontrol ederim - bu gereksiz olabilir.). Ana sorgu, şablonlarınızda şöyle görünür:

if( have_posts() ):
    while( have_posts() ): the_post();
       //The loop
    endwhile;
endif;

Eğer bu döngüyü düzenleme ihtiyacı duyuyorsanız - kullanın pre_get_posts. Örneğin, kullanmak istekliyseniz query_posts()- kullanın pre_get_posts.

WP_Query

Ana sorgu, a'nın önemli bir örneğidir WP_Query object. WordPress, örneğin hangi şablonun kullanılacağına ve url'ye iletilen herhangi bir argümanın (örneğin sayfa numaralandırması) WP_Querynesnenin o örneğine yönlendirildiğine karar vermek için kullanır .

İkincil döngüler için (örneğin, kenar çubuklarında veya 'ilgili yazılar' listelerinde), WP_Querynesnenin kendi ayrı örneğini oluşturmak isteyeceksiniz . Örneğin

$my_secondary_loop = new WP_Query(...);
if( $my_secondary_loop->have_posts() ):
    while( $my_secondary_loop->have_posts() ): $my_secondary_loop->the_post();
       //The secondary loop
    endwhile;
endif;
wp_reset_postdata();

Dikkat wp_reset_postdata();- bunun nedeni ikincil döngünün $post'geçerli yayını' tanımlayan genel değişkeni geçersiz kılmasıdır . Bu aslında $postbiz olduğumuzu sıfırlar .

get_posts ()

Bu aslında bir WP_Querynesnenin ayrı bir örneği için bir sarmalayıcıdır . Bu, bir dizi post nesnesi döndürür. Yukarıdaki döngüde kullanılan yöntemler artık kullanımınıza sunulmamaktadır. Bu bir 'Döngü' değil, sadece bir post nesnesi dizisidir.

<ul>
<?php
global $post;
$args = array( 'numberposts' => 5, 'offset'=> 1, 'category' => 1 );
$myposts = get_posts( $args );
foreach( $myposts as $post ) :  setup_postdata($post); ?>
    <li><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></li>
<?php endforeach; wp_reset_postdata(); ?>
</ul>

Sorularınıza cevap olarak

  1. Kullanım pre_get_postsana sorgu değiştirmek için. WP_QueryŞablon sayfalarındaki ikincil döngüler için ayrı bir nesne (yöntem 2) kullanın .
  2. Ana döngünün sorgusunu değiştirmek istiyorsanız, kullanın pre_get_posts.

Öyleyse, WP_Query'den ziyade doğruca get_posts () 'a gideceğiniz bir senaryo var mı?
urok93

@ drtanz - evet. Örneğin, sayfa numaralandırmaya ihtiyacınız olmadığını veya en üstteki yapışkan direklere ihtiyacınız olmadığını söyleyin - bu durumlarda get_posts()daha verimlidir.
Stephen Harris

Ancak bu, ana sorguyu değiştirmek için pre_get_posts komutunu değiştirebileceğimiz fazladan bir sorgu eklemek olmaz mıydı?
urok93

@drtanz - get_posts()ana sorgu için kullanmazsınız - ikincil sorgular için.
Stephen Harris

1
@StephenHarris Right =) Eğer the_post kullanmak yerine nesne üzerinde next_post () kullanırsanız, genel sorguya adım atmazsınız ve daha sonra wp_reset_postdata'yı kullanmayı hatırlamanız gerekmez.
Özel

55

Döngüler için iki farklı bağlam vardır:

  • URL isteğine göre gerçekleşen ve şablonlar yüklenmeden önce işlenen ana döngü
  • başka bir şekilde gerçekleşen ikincil döngüler, şablon dosyalarından çağrılır veya başka türlü

Sorun query_posts()şu ki, ana olmaya çalışan ve perişan olan ikincil döngüdür. Böylece var olduğunu unut.

Ana döngüyü değiştirmek için

  • kullanma query_posts()
  • çek pre_get_postsile filtre kullanın$query->is_main_query()
  • dönüşümlü olarak requestfiltre kullanın (biraz daha fazla kaba olduğundan daha iyi)

İkincil döngü çalıştırmak için

Kullanımı new WP_Queryveya get_posts()hemen hemen değiştirilebilir olan (ikincisi için eski ince sarıcı).

Temizlemek

Kullanın wp_reset_query()Eğer kullanılırsa query_posts()veya global ile haberci $wp_queryyani neredeyse hiç gerek kalmayacaktır - doğrudan.

Kullanın wp_reset_postdata()Eğer kullanılırsa the_post()veya setup_postdata()veya global ile haberci $postve sonrası ile ilgili şeylerin başlangıç durumunu geri yüklemek gerekir.


3
Rarst demekwp_reset_postdata()
Gregory

23

query_posts($query)Örneğin, yasal senaryolar kullanmak için:

  1. Bir sayfada yayınların listesini veya özel yazı sonrası yayınları görüntülemek istiyorsunuz (sayfa şablonu kullanarak).

  2. Bu yayınların sayfalandırılmasını çalışır hale getirmek istiyorsunuz

Peki neden bir arşiv şablonu kullanmak yerine bir sayfada görüntülemek istiyorsunuz?

  1. Bir yönetici için daha sezgiseldir (müşteriniz?) - sayfayı 'Sayfalar'da görebilirler

  2. Menülere eklemek daha iyidir (sayfa olmadan doğrudan URL'yi eklemek zorunda kalırlar)

  3. Şablonda ek içerik (metin, küçük resim veya herhangi bir özel meta içerik) görüntülemek istiyorsanız, onu sayfadan kolayca elde edebilirsiniz (ve hepsi de müşteri için daha anlamlı olur). Bir arşiv şablonu kullandıysanız, ek içeriği kodlamanız veya örneğin tema / eklenti seçenekleri kullanmanız gerekebilir (bu, müşteri için daha az sezgiseldir)

İşte basitleştirilmiş bir örnek kod (sayfa şablonunuzda olurdu - örneğin sayfa-sayfanın-posts.php):

/**
 * Template Name: Page of Posts
 */

while(have_posts()) { // original main loop - page content
  the_post();
  the_title(); // title of the page
  the_content(); // content of the page
  // etc...
}

// now we display list of our custom-post-type posts

// first obtain pagination parametres
$paged = 1;
if(get_query_var('paged')) {
  $paged = get_query_var('paged');
} elseif(get_query_var('page')) {
  $paged = get_query_var('page');
}

// query posts and replace the main query (page) with this one (so the pagination works)
query_posts(array('post_type' => 'my_post_type', 'post_status' => 'publish', 'paged' => $paged));

// pagination
next_posts_link();
previous_posts_link();

// loop
while(have_posts()) {
  the_post();
  the_title(); // your custom-post-type post's title
  the_content(); // // your custom-post-type post's content
}

wp_reset_query(); // sets the main query (global $wp_query) to the original page query (it obtains it from global $wp_the_query variable) and resets the post data

// So, now we can display the page-related content again (if we wish so)
while(have_posts()) { // original main loop - page content
  the_post();
  the_title(); // title of the page
  the_content(); // content of the page
  // etc...
}

Şimdi, açıkça söylemek gerekirse, query_posts()burada da kullanmaktan kaçınabilir ve WP_Querybunun yerine kullanabiliriz - bunun gibi:

// ...

global $wp_query;
$wp_query = new WP_Query(array('your query vars here')); // sets the new custom query as a main query

// your custom-post-type loop here

wp_reset_query();

// ...

Ancak, neden böyle küçük bir fonksiyona sahip olduğumuzda bunu yapalım?


1
Brian, bunun için teşekkürler. Açıkladığınız senaryodaki SADECE bir sayfada çalışmak için pre_get_posts'ı almakta zorlanıyorum: müşterinin bir arşiv sayfasının ne olacağına özel alanlar / içerik eklemesi gerekiyor, bu nedenle bir "sayfanın" oluşturulması gerekiyor; müşterinin nav menüsüne eklemek için bir şeyler görmesi gerekir, çünkü özel bir bağlantı eklemek bunlardan kaçar; vb benden +1!
Lanni

2
Bu "pre_get_posts" kullanılarak da yapılabilir. Özel yazı tiplerimi özel bir sırayla ve özel bir filtre ile listeleyen bir "statik ön sayfa" olmasını sağladım. Bu sayfa aynı zamanda sayfalandırılmıştır. Nasıl çalıştığını görmek için bu soruya göz atın: wordpress.stackexchange.com/questions/30851/… Yani kısacası,
query_posts

1
Çünkü "Bunu, bir sayfadaki ana sorguyu değiştirmek için kullanmanın sayfa yükleme sürelerini artırabileceği, en kötü durumda ise gereken iş miktarını iki katından fazla arttırabileceği unutulmamalıdır. Kullanımı kolay olsa da, işlev karışıklığa da meyillidir. ve sonradan sorunlar. " Kaynak codex.wordpress.org/Function_Reference/query_posts
Claudiu Creanga

Bu cevap her türlü yanlış. WP'de Özel gönderi türüyle aynı URL ile bir "Sayfa" oluşturabilirsiniz. EG, eğer CPT’niz Muz ise aynı URL’ye sahip olan Muz adında bir sayfa alabilirsiniz. Öyleyse siteurl.com/bananas ile bitirdin. Tema klasörünüzde archive-bananas.php olduğu sürece, şablonu kullanır ve bunun yerine bu sayfayı "geçersiz kılar". Diğer yorumlardan birinde belirtildiği gibi, bu "yöntem" i kullanmak WP için iki kat iş yükü yaratır, bu nedenle asla kullanılmamalıdır.
Hybrid Web Dev,

8

WordPress sorgusunu functions.php'den değiştiriyorum:

//unfortunately, "IS_PAGE" condition doesn't work in pre_get_posts (it's WORDPRESS behaviour)
//so you can use `add_filter('posts_where', ....);`    OR   modify  "PAGE" query directly into template file

add_action( 'pre_get_posts', 'myFunction' );
function myFunction($query) {
    if ( ! is_admin() && $query->is_main_query() )  {
        if (  $query->is_category ) {
            $query->set( 'post_type', array( 'post', 'page', 'my_postType' ) );
            add_filter( 'posts_where' , 'MyFilterFunction_1' ) && $GLOBALS['call_ok']=1; 
        }
    }
}
function MyFilterFunction_1($where) {
   return (empty($GLOBALS['call_ok']) || !($GLOBALS['call_ok']=false)  ? $where :  $where . " AND ({$GLOBALS['wpdb']->posts}.post_name NOT LIKE 'Journal%')"; 
}

bu örneği görmek isterdim ama yan tümce özel metada.
Andrew Welch

6

Yalnızca, WordPress zaman içinde geliştiğinden ve şimdi bazı şeylerin farklı olduğundan (beş yıl sonra) bazı kabul edilen cevaplarda bazı iyileştirmeler yapmak:

pre_get_postsherhangi bir sorguyu değiştirmek için kullanılan bir filtredir. En sık yalnızca 'ana sorguyu' değiştirmek için kullanılır:

Aslında bir eylem kancası. Filtre değil ve herhangi bir sorguyu etkileyecektir.

Ana sorgu, şablonlarınızda şöyle görünür:

if( have_posts() ):
    while( have_posts() ): the_post();
       //The loop
    endwhile;
endif;

Aslında bu da doğru değil. İşlev , yalnızca ana sorgu ile ilgili olmayan nesneyi have_postsyineler . ikincil sorgularla da değiştirilebilir.global $wp_queryglobal $wp_query;

function have_posts() {
    global $wp_query;
    return $wp_query->have_posts();
}

get_posts ()

Bu aslında bir WP_Query nesnesinin ayrı bir örneği için bir sarıcıdır.

Aslında, bugünlerde WP_Querybir sınıf var, bu yüzden bir sınıf örneğimiz var.


Sonuç olarak: @StephenHarris zamanında tüm bunların doğru olduğunu yazdı, ancak zaman içinde WordPress'teki şeyler değişti.


Teknik olarak, tüm başlık altında filtreler, eylemler sadece basit bir filtredir. Ancak burada haklısınız, bu, referansla bir argüman ileten bir eylemdir; bu, daha basit eylemlerden nasıl farklılaştığını gösterir.
Milo

get_postsbir WP_Querynesne değil post nesneler dizisi döndürür , böylece gerçekte hala doğru olur. ve WP_Queryher zaman bir sınıf olmuştur, bir sınıf örneği = nesne.
Milo

Teşekkürler @ Melo, bazı sebeplerden dolayı doğrusu kafamda basitleştirilmiş bir model vardı.
prosti
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.