問題描述

我已經將自定義/輔助查詢新增到模板檔案/自定義頁面模板中; 如何使 WordPress 使用我的自定義查詢進行分頁,而不是使用主查詢迴圈的分頁?

Addendum

我已經透過 query_posts()修改了主迴圈查詢。為什麼不分頁工作,怎麼解決?

最佳解決方案

問題

預設情況下,在任何給定的上下文中,WordPress 使用主查詢來確定分頁。主查詢物件儲存在 $wp_query 全域性中,也用於輸出主查詢迴圈:

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

當您使用 use a custom query 時,您將建立一個完全獨立的查詢物件:

$custom_query = new WP_Query( $custom_query_args );

該查詢透過一個完全獨立的迴圈輸出:

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

但分頁模板標籤,包括 previous_posts_link()next_posts_link()posts_nav_link()paginate_links(),它們的輸出基於主查詢物件 $wp_query 。該主要查詢可能是也可能不會被分頁。如果當前上下文是自定義頁面模板,例如,主 $wp_query 物件將僅包含單個帖子 – 分配了自定義頁面模板的頁面的 ID 。

如果當前上下文是某種歸檔索引,則主 $wp_query 可能包含足夠的帖子導致分頁,導致下一部分問題:對於主 $wp_query 物件,WordPress 會將 paged 引數傳遞給查詢,基於 paged URL 查詢變數。獲取查詢後,將使用該 paged 引數來確定要返回哪一組分頁的帖子。如果單擊顯示的分頁連結,並且下一頁載入,您的自定義查詢將無法知道分頁已更改。

解決方案

將正確的分頁引數傳遞給自定義查詢

假設自定義查詢使用 args 陣列:

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

您將需要將正確的 paged 引數傳遞給陣列。您可以透過獲取用於確定當前頁面的 URL 查詢變數,透過 get_query_var()

get_query_var( 'paged' );

然後,您可以將該引數附加到自定義查詢 args 陣列中:

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

注意:如果您的頁面是靜態首頁,請確保使用 page 代替 paged 作為靜態首頁使用 page 而不是 paged 。這是您應該擁有的靜態首頁

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

現在,當提取自定義查詢時,將返回正確的一組分頁帖子。

使用自定義查詢物件進行分頁功能

為了使分頁函式產生正確的輸出 – 即相對於自定義查詢的上一頁/下一頁/頁面連結 – 需要強制 WordPress 識別自定義查詢。這需要一點”hack”:使用自定義查詢物件 $custom_query 替換主 $wp_query 物件:

破解主查詢物件

  1. 備份主查詢物件:$temp_query = $wp_query
  2. 空的主查詢物件:$wp_query = NULL;
  3. 將自定義查詢交換到主查詢物件:$wp_query = $custom_query;

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

必須在呼叫任何分頁功能之前完成此”hack”

重置主查詢物件

分頁功能輸出後,重新設定主查詢物件:

$wp_query = NULL;
$wp_query = $temp_query;

分頁功能修復

無論分頁如何,previous_posts_link()功能都能正常工作。它只是確定當前頁面,然後輸出 page - 1 的連結。但是,需要修復 next_posts_link()才能正確輸出。這是因為 next_posts_link()使用 max_num_pages 引數:

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

與其他查詢引數一樣,預設情況下,該函式將使用 max_num_pages 作為主 $wp_query 物件。為了強制 next_posts_link()考慮 $custom_query 物件,您需要將 max_num_pages 傳遞給該功能。您可以從 $custom_query 物件獲取此值:$custom_query->max_num_pages

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

把它們放在一起

以下是具有正確功能的分頁功能的自定義查詢迴圈的基本構造:

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

附錄:query_posts()怎麼樣?

 query_posts()二級迴圈

如果您使用 query_posts()輸出自定義迴圈,而不是透過 WP_Query()例項化用於自定義查詢的單獨物件,那麼您將是_doing_it_wrong(),並且將遇到幾個問題 (其中最不重要的是分頁問題) 。解決這些問題的第一步將是將 query_posts()的不當使用轉換為適當的 WP_Query()呼叫。

使用 query_posts()修改主迴圈

如果您只想修改主迴圈查詢的引數 (例如更改每頁的帖子或排除類別),則可能會嘗試使用 query_posts()。但你還不應該。當您使用 query_posts()時,強制 WordPress 替換主查詢物件。 (WordPress 實際上是第二個查詢,並覆蓋 $wp_query) 。但問題是,在更新分頁的過程中,這個替換太晚了。

解決方案是透過 pre_get_posts 鉤子獲取帖子之前過濾主查詢。

而不是將其新增到類別模板檔案 (category.php) 中:

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

將以下內容新增到 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' );

而不是將其新增到部落格帖子索引模板檔案 (home.php) 中:

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

將以下內容新增到 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' );

這樣,當確定分頁時,WordPress 將使用 already-modified $wp_query 物件,不需要模板修改。

什麼時候使用什麼功能

研究 this question and answerthis question and answer,瞭解如何和何時使用 WP_Querypre_get_postsquery_posts()

次佳解決方案

我使用這個程式碼進行自定義迴圈與分頁:

<?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="http://<?php%20the_permalink();%20?>"><?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;
?>

資源:

參考文獻

注:本文內容整合自 Google/Baidu/Bing 輔助翻譯的英文資料結果。如果您對結果不滿意,可以加入我們改善翻譯效果:薇曉朵技術論壇。