Özel döngüler için sayfalandırma nasıl düzeltilir?


122

Bir şablon dosyasına / özel sayfa şablonuna özel / ikincil bir sorgu ekledim; WordPress'in ana sorgu döngüsünün sayfalandırmasını kullanmak yerine sayfalandırma için özel sorgumu kullanmasını nasıl sağlayabilirim?

ek

Ana döngü sorgusu ile değiştirdim query_posts(). Sayfalama neden çalışmıyor ve nasıl düzeltebilirim?

Yanıtlar:


215

Sorun

Varsayılan olarak, herhangi bir bağlamda, WordPress sayfalamayı belirlemek için ana sorguyu kullanır. Ana sorgu nesnesi, $wp_queryana sorgu döngüsünün çıktısını almak için de kullanılan globalde saklanır :

if ( have_posts() ) : while ( have_posts() ) : the_post();

Ne zaman özel bir sorgu kullanmak , sen tamamen ayrı bir sorgu nesnesi oluşturmak:

$custom_query = new WP_Query( $custom_query_args );

Ve bu sorgu tamamen ayrı bir döngü aracılığıyla elde edilir:

if ( $custom_query->have_posts() ) : 
    while ( $custom_query->have_posts() ) : 
        $custom_query->the_post();

Ama dahil sayfalandırma şablon etiketleri previous_posts_link(), next_posts_link(), posts_nav_link(), ve paginate_links(), kendi çıkışını dayandırmak ana sorgu nesnesi , $wp_query. Bu ana sorgu sayfalandırılmış olabilir veya olmayabilir. Geçerli içeriğin bir özel sayfa şablonu ise, örneğin, ana $wp_queryamacı, sadece oluşacak tek bir yayın - özel sayfa şablonu atandığı sayfanın kimliğinin olduğu.

Geçerli içerik bir tür arşiv dizini ise, ana sayfa $wp_query, sorunun bir sonraki bölümüne yol açan sayfalandırmaya neden olacak kadar yayın içerebilir: ana $wp_querynesne için WordPress paged , sorguyu temel alan bir parametreyi iletir. pagedURL sorgu değişkeni. Sorgu getirildiğinde, bu pagedsayfalandırılmış hangi sayfaların döndürüleceğini belirlemek için kullanılır. Görüntülenen bir sayfalama bağlantısı tıklanır ve bir sonraki sayfa yüklenirse, özel sorgunuz sayfalamanın değiştiğini bilmenin bir yolunu bulamaz .

Çözüm

Özel Sorguya Doğru Sayfalı Parametreyi Geçmek

Özel sorgunun bir args dizisi kullandığını varsayarak:

$custom_query_args = array(
    // Custom query parameters go here
);

pagedDiziye doğru parametreyi iletmeniz gerekir. Bunu, şu anki sayfayı belirlemek için kullanılan URL sorgusu değişkenini aşağıdakiler yoluyla alarak yapabilirsiniz get_query_var():

get_query_var( 'paged' );

Daha sonra bu parametreyi özel sorgu args dizinize ekleyebilirsiniz:

$custom_query_args['paged'] = get_query_var( 'paged' ) 
    ? get_query_var( 'paged' ) 
    : 1;

Not: Sayfanız ise statik ön sayfa , kullandığınızdan emin olun pageyerine pagedstatik bir ön sayfa kullandığından pagedeğil paged. Statik bir ön sayfa için sahip olmanız gereken şey budur

$custom_query_args['paged'] = get_query_var( 'page' ) 
    ? get_query_var( 'page' ) 
    : 1;

Şimdi, özel sorgu alındığında, doğru bir şekilde sayfalanmış yayınlar kümesi döndürülecek.

Sayfalandırma İşlevleri İçin Özel Sorgu Nesnesi Kullanma

Sayfalandırma işlevlerinin doğru çıktı vermesi için - yani, özel sorguya göre önceki / sonraki / sayfa bağlantıları - WordPress'in özel sorguyu tanıması için zorlanması gerekir. Buna "kesmek" biraz gerektirir: Ana değiştirirken $wp_query, özel sorgu nesnesi ile nesneyi $custom_query:

Ana sorgu nesnesini kes

  1. Ana sorgu nesnesini yedekle: $temp_query = $wp_query
  2. Ana sorgu nesnesini boş bırakın: $wp_query = NULL;
  3. Özel sorguyu ana sorgu nesnesine yerleştirin: $wp_query = $custom_query;

    $temp_query = $wp_query;
    $wp_query   = NULL;
    $wp_query   = $custom_query;

Bu "kes" sayfalama işlevlerini çağırmadan önce yapılmalıdır

Ana sorgu nesnesini sıfırla

Sayfalandırma işlevleri çıktığında ana sorgu nesnesini sıfırlayın:

$wp_query = NULL;
$wp_query = $temp_query;

Sayfalandırma İşlev Düzeltmeleri

previous_posts_link()Fonksiyon ne olursa olsun bir şekilde sayfa numarası, normal şekilde çalışacaktır. Yalnızca geçerli sayfayı belirler ve sonra bağlantıyı çıkarır page - 1. Ancak, next_posts_link()düzgün bir şekilde çıktı almak için bir düzeltme gerekir. Bunun nedeni next_posts_link()kullandığı max_num_pagesparametre:

<?php next_posts_link( $label , $max_pages ); ?>

Diğer sorgu parametrelerinde olduğu gibi, işlev varsayılan max_num_pagesolarak ana $wp_querynesne için kullanır . Nesneyi next_posts_link()hesaba katmaya zorlamak için, işleve $custom_querygeçmeniz gerekir max_num_pages. Bu değeri $custom_querynesneden alabilirsiniz $custom_query->max_num_pages:

<?php next_posts_link( 'Older Posts' , $custom_query->max_num_pages ); ?>

Hepsini bir araya koy

Düzgün işleyen sayfalandırma işlevlerine sahip özel bir sorgu döngüsünün temel yapısı aşağıdadır:

// Define custom query parameters
$custom_query_args = array( /* Parameters go here */ );

// Get current page and append to custom query parameters array
$custom_query_args['paged'] = get_query_var( 'paged' ) ? get_query_var( 'paged' ) : 1;

// Instantiate custom query
$custom_query = new WP_Query( $custom_query_args );

// Pagination fix
$temp_query = $wp_query;
$wp_query   = NULL;
$wp_query   = $custom_query;

// Output custom query loop
if ( $custom_query->have_posts() ) :
    while ( $custom_query->have_posts() ) :
        $custom_query->the_post();
        // Loop output goes here
    endwhile;
endif;
// Reset postdata
wp_reset_postdata();

// Custom query loop pagination
previous_posts_link( 'Older Posts' );
next_posts_link( 'Newer Posts', $custom_query->max_num_pages );

// Reset main query object
$wp_query = NULL;
$wp_query = $temp_query;

Zeyilname: Ne hakkında query_posts()?

query_posts() İkincil döngüler için

query_posts()Özel bir döngü oluşturmak için kullanıyorsanız WP_Query(), o zaman özel sorgu için ayrı bir nesneyi kullanarak başlatmak , o zaman siz _doing_it_wrong()(ve en azından sayfalama sorunları olacak) birkaç soruna rastlayacaksınız. Bu sorunları çözmenin ilk adımı, yanlış kullanımı query_posts()uygun bir WP_Query()çağrıya dönüştürmek olacaktır .

query_posts()Ana Döngüyü Değiştirmek İçin Kullanma

Ana döngü sorgusu için parametreleri değiştirmek isterseniz - örneğin sayfa başına yazılanları değiştirmek veya bir kategori hariç bırakmak gibi - kullanmak isteyebilirsiniz query_posts(). Ama yine de yapmamalısın. Kullandığınızda query_posts(), WordPress'i ana sorgu nesnesini değiştirmeye zorlarsınız . (WordPress aslında ikinci bir sorgu yapar ve üzerine yazar $wp_query.) Sorun, yine de, sayfa değiştirme güncellemesi sürecinde bu değişikliği çok geç yapmasıdır.

Çözüm, gönderiler alınmadan öncepre_get_posts kanca aracılığıyla ana sorguyu filtrelemektir .

Bunu kategori şablonu dosyasına ( category.php) eklemek yerine :

query_posts( array(
    'posts_per_page' => 5
) );

Aşağıdakileri ekleyin functions.php:

function wpse120407_pre_get_posts( $query ) {
    // Test for category archive index
    // and ensure that the query is the main query
    // and not a secondary query (such as a nav menu
    // or recent posts widget output, etc.
    if ( is_category() && $query->is_main_query() ) {
        // Modify posts per page
        $query->set( 'posts_per_page', 5 ); 
    }
}
add_action( 'pre_get_posts', 'wpse120407_pre_get_posts' );

Bunu blog yazısı dizin şablon dosyasına ( home.php) eklemek yerine :

query_posts( array(
    'cat' => '-5'
) );

Aşağıdakileri ekleyin functions.php:

function wpse120407_pre_get_posts( $query ) {
    // Test for main blog posts index
    // and ensure that the query is the main query
    // and not a secondary query (such as a nav menu
    // or recent posts widget output, etc.
    if ( is_home() && $query->is_main_query() ) {
        // Exclude category ID 5
        $query->set( 'category__not_in', array( 5 ) ); 
    }
}
add_action( 'pre_get_posts', 'wpse120407_pre_get_posts' );

Bu şekilde, WordPress sayfa değişikliği $wp_querybelirlenirken önceden değiştirilmiş nesneyi kullanır, şablon değişikliği gerekmez.

Hangi işlevi ne zaman kullanmalı

Araştırma bu soruyu ve cevabı ve bu soru cevap nasıl ve ne zaman kullanmak anlamak için WP_Query, pre_get_postsve query_posts().


31
Kodeksin içindeki dilek sayfaları çok eksiksiz olabilir.
Pieter Goosen

Chip, günümü sen yaptın!
tepkenvannkorn

1
Chip, her zaman çok zaman kazanıyorsun! Eğer sadece google rütbeli olsaydı çılgın arama yapmadan önce size daha yüksek cevaplar (googlers için belirtme çizgisi);) teşekkürler.
Sagive SEO

Örneğinizi kullanarak , bu sayfada aşağıdan (?: Koşullu yerine) bulunan if-else bloğunu kullanana kadar disk belleği çalışamadı: themeforest.net/forums/thread/… , çok garip. Aksi halde bu cevap bana çok şey öğretti.
Adım

2
Harika bir cevap - 1 şey, bir sonraki / önceki post link işlevini bir ajax çağrısında çalıştırmakta sorun yaşıyordum - kısa sürede cevap vermeyecekti - etrafta kısa bir süre sonra pagedgenelin güncellenmediğini öğrendim (yönetici ile ilgisi olan bir şey yapma) ajax.php ortamı) bu yüzden şunu ekledim: global $paged; $paged = $custom_query_args['paged']; ve işe yaradı :)
acSlater

21

Bu kodu sayfalandırma ile özel döngü için kullanıyorum:

<?php
if ( get_query_var('paged') ) {
    $paged = get_query_var('paged');
} elseif ( get_query_var('page') ) { // 'page' is used instead of 'paged' on Static Front Page
    $paged = get_query_var('page');
} else {
    $paged = 1;
}

$custom_query_args = array(
    'post_type' => 'post', 
    'posts_per_page' => get_option('posts_per_page'),
    'paged' => $paged,
    'post_status' => 'publish',
    'ignore_sticky_posts' => true,
    //'category_name' => 'custom-cat',
    'order' => 'DESC', // 'ASC'
    'orderby' => 'date' // modified | title | name | ID | rand
);
$custom_query = new WP_Query( $custom_query_args );

if ( $custom_query->have_posts() ) :
    while( $custom_query->have_posts() ) : $custom_query->the_post(); ?>

        <article <?php post_class(); ?>>
            <h3><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h3>
            <small><?php the_time('F jS, Y') ?> by <?php the_author_posts_link() ?></small>
            <div><?php the_excerpt(); ?></div>
        </article>

    <?php
    endwhile;
    ?>

    <?php if ($custom_query->max_num_pages > 1) : // custom pagination  ?>
        <?php
        $orig_query = $wp_query; // fix for pagination to work
        $wp_query = $custom_query;
        ?>
        <nav class="prev-next-posts">
            <div class="prev-posts-link">
                <?php echo get_next_posts_link( 'Older Entries', $custom_query->max_num_pages ); ?>
            </div>
            <div class="next-posts-link">
                <?php echo get_previous_posts_link( 'Newer Entries' ); ?>
            </div>
        </nav>
        <?php
        $wp_query = $orig_query; // fix for pagination to work
        ?>
    <?php endif; ?>

<?php
    wp_reset_postdata(); // reset the query 
else:
    echo '<p>'.__('Sorry, no posts matched your criteria.').'</p>';
endif;
?>

Kaynak:


1
Bu cevabın bir türevi ile başka bir güzel ders: callmenick.com/post/custom-wordpress-loop-with-pagination
mrwweb

5

Her zamanki gibi harika. Buna ek olarak, bazı "intro metni" için bir Sayfa'ya eklenmiş bir küresel sayfa şablonu kullandığınız ve bunu sayfalandırmak istediğiniz bir alt sorgu tarafından kullandığınız durumu göz önünde bulundurun.

Yukarıda belirttiğimiz gibi paginate_links () işlevini kullanmak , çoğunlukla varsayılan ayarlarla (ve güzel kalıcı bağlantıların açık olduğunu varsayarsak), sayfalandırma bağlantılarınız varsayılan olarak güzeldir mysite.ca/page-slug/page/#, ancak 404hatalar verecektir, çünkü WordPress bu belirli URL yapısını bilmez ve "page-slug" un çocuğu olan "page" alt sayfasına bakın.

Buradaki hile, /page/#/yapıyı kabul eden ve onu WordPress'in anlayabileceği bir sorgu dizgisine yeniden yazan , yalnızca söz konusu "sözde arşiv sayfası" sayfa fişine uygulanan şık bir yeniden yazma kuralı eklemektir mysite.ca/?pagename=page-slug&paged=#. Not pagenameve pageddeğil nameve page(bu kelimenin tam anlamıyla Keder HOURS, bu cevap burada motive!).

İşte yönlendirme kuralı:

add_rewrite_rule( "page-slug/page/([0-9]{1,})/?$", 'index.php?pagename=page-slug&paged=$matches[1]', "top" );

Her zaman olduğu gibi, yeniden yazma kurallarını değiştirirken , Yönetici arka ucunda Ayarlar> Kalıcı Bağlantılar'ı ziyaret ederek kalıcı bağlantılarınızı temizlemeyi unutmayın .

Bu şekilde davranacak birden fazla sayfanız varsa (örneğin, birden fazla özel yazı türüyle çalışırken), her sayfa grubu için yeni bir yeniden yazma kuralı oluşturmaktan kaçınmak isteyebilirsiniz. Tanımladığınız herhangi bir sayfa başlığı için işe yarayan daha genel bir düzenli ifade yazabiliriz.

Bir yaklaşım aşağıdadır:

function wpse_120407_pseudo_archive_rewrite(){
    // Add the slugs of the pages that are using a Global Template to simulate being an "archive" page
    $pseudo_archive_pages = array(
        "all-movies",
        "all-actors"
    );

    $slug_clause = implode( "|", $pseudo_archive_pages );
    add_rewrite_rule( "($slug_clause)/page/([0-9]{1,})/?$", 'index.php?pagename=$matches[1]&paged=$matches[2]', "top" );
}
add_action( 'init', 'wpse_120407_pseudo_archive_rewrite' );

Dezavantajları / Uyarılar

Ağzımda biraz kusmama neden olan bu yaklaşımın bir dezavantajı, Sayfa sümüklü böceklerin zor kodlamasıdır. Bir yönetici sözde arşiv sayfasının sayfasını tamamen değiştirirse, kızarırsınız - yeniden yazma kuralı artık eşleşmeyecek ve korkunç 404'ü alacaksınız.

Bu yöntem için bir geçici çözüm düşünebileceğimden emin değilim, ancak yeniden yazma kuralını bir şekilde tetikleyen genel sayfa şablonu olsaydı iyi olurdu. Bir gün o cevabı başka kimse kırmazsa bu cevabı tekrar görebilirim.


1
Gönderiyi kaydedebilir, sayfanızın arşiv şablonunuzun meta anahtarın altında olup olmadığını kontrol edebilir _wp_page_template, ardından başka bir yeniden yazma ve temizleme kuralları ekleyebilirsiniz.
Milo

2

Ana döngü sorgusu ile değiştirdim query_posts(). Sayfalama neden çalışmıyor ve nasıl düzeltebilirim?

Müthiş cevap Çip yaratılanın bugün değiştirilmesi gerekiyor.
Bir süredir , ana sorgu çalıştırıldıktan hemen sonra global $wp_the_querydeğere eşit olması gereken değişkenimiz var $wp_query.

Bu yüzden Chip'in cevabındaki kısım:

Ana sorgu nesnesini kes

artık gerekli değil. Geçici değişkeni yaratarak bu kısmı unutabiliriz.

// Pagination fix
$temp_query = $wp_query;
$wp_query   = NULL;
$wp_query   = $custom_query;

Yani şimdi arayabiliriz:

$wp_query   = $wp_the_query;

veya daha da iyisi arayabiliriz:

wp_reset_query();

Çipte belirtilen diğer her şey kalır. Bu sorgu-reset-bölümünden sonra, f($wp_query)bunlar $wp_querygenel olana bağlı olan sayfalama işlevlerini çağırabilirsiniz .


Sayfalama mekaniğini daha da iyileştirmek ve query_postsfonksiyona daha fazla özgürlük vermek için bu olası gelişmeyi yarattım:

https://core.trac.wordpress.org/ticket/39483


1
global $wp_query;
        $paged = get_query_var('paged', 1);

    $args = array( 
        'post_type' => '{your_post_type_name}',
        'meta_query' => array('{add your meta query argument if need}'),  
        'orderby' => 'modified',
        'order' => 'DESC',
        'posts_per_page' => 20,
        'paged' => $paged 
    );
    $query = new WP_Query($args);

    if($query->have_posts()):
        while ($query->have_posts()) : $query->the_post();
            //add your code here
        endwhile;
        wp_reset_query();

        //manage pagination based on custom Query.
        $GLOBALS['wp_query']->max_num_pages = $query->max_num_pages;
        the_posts_pagination(array(
            'mid_size' => 1,
            'prev_text' => __('Previous page', 'patelextensions'),
            'next_text' => __('Next page', 'patelextensions'),
            'before_page_number' => '<span class="meta-nav screen-reader-text">' . __('Page', 'patelextensions') . ' </span>',
        ));
    else:
    ?>
        <div class="container text-center"><?php echo _d('Result not found','30'); ?></div>
    <?php
        endif;
    ?>
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.