問題描述

我正在嘗試在我的主題中建立一個類別模板,如果使用者位於存檔的第一頁,則會顯示靜態內容,然後在以下頁面上顯示類別中的帖子。我基本上是嘗試複製 Wired.com 上的類別行為,其中 http://www.wired.com/category/design 是一個著陸頁,而/category /design /page /1 顯示了類似於期望在類別歸檔中的反向按時間順序排列的列表。

這裡的關鍵是,我沒有在第一頁上顯示類別歸檔中的任何帖子,所以我需要下一頁從第一個帖子開始。如果’paged’ 查詢 var 為 2,我首先嚐試使用 offset and manual pagination 來設定查詢的偏移量為 0 。但是當設定為零時,偏移量被忽略,所以我可以做的最好是將偏移量設定為 1,並從該類別中的第二個職位。

這是我新增到 functions.php 中的:

add_action('pre_get_posts', 'category_query_offset', 1 );
function category_query_offset(&$query) {
  // Before anything else, make sure this is the right query
  if (!$query->is_category('news')) {
    return;
  }

  // Next, determine how many posts per page
  $ppp = get_option('posts_per_page');

  //Next, detect and handle pagination
  if ($query->is_paged) {
    // Manually determine page query offset
    $page_offset = (($query->query_vars['paged']-1) * $ppp) - $ppp;
    // Apply adjust page offset
    $query->set('offset', $page_offset );
  }
}

什麼會更好,以及它顯示的是使用預設分頁,以便帖子從第 1 頁開始,但為靜態內容插入頁面 0 。假設’paged’ 為 1,那麼’paged’ 為 0,並顯示第一頁帖子,這樣就可以顯示靜態內容。問題是’paged’ 從不是 1,因為 WordPress 將’paged’ 設定為零,當使用者請求第一頁。這意味著’paged’ 對於/category /news /page /1 和/category /news 都是 0 。

有沒有辦法檢查使用者是否要求/category /news /page /1 而不是/category /news?沒有,是否有一種方法來顯示從第 2 頁開始的類別中的所有帖子?

最佳解決方案

這是一個非常有趣的問題 (我特別為您的方法和研究而升級了) 。這裡的大麴線球是查詢的第一頁:

  • 您無法設定查詢以返回第一頁上的 0 帖子

  • 透過將每頁的頁面內容向上移動一頁,您將會丟失最後一頁,因為查詢仍將只具有相同的帖子數量,因此 $max_num_pages 屬性仍然保持不變

我們將需要以某種方式”trick” WP_Query 類返回我們的帖子 corectly 與一個頁面的偏移,並且還得到正確的頁數,以便不鬆動查詢中的最後一頁

讓我們來看看下面的想法,並嘗試將所有內容都放在程式碼中。在我們做之前,我想在這裡提幾點

重要筆記:

  • 一切都是未經測試的,所以它可能是錯誤的。確保在本地進行測試,並開啟除錯開關

  • 該程式碼至少需要 PHP 5.3,5.3 以下版本會導致致命錯誤。請注意,如果仍然使用下面的 PHP 5.5 版本,您應該已經很久以前升級了

  • 修改和濫用您認為適合您的確切需求的程式碼

光線:

我們需要什麼

為了使一切正常,我們將需要以下內容:

  • 正在檢視的當前頁碼

  • posts_per_page 選項在閱讀設定中設定

  • 定製 offset

  • 修改查詢的 $found_posts 屬性以更正 $max_num_pages 屬性

分頁是 WP_Query 下來一個非常簡單的幾行程式碼

if ( empty($q['nopaging']) && !$this->is_singular ) {
    $page = absint($q['paged']);
    if ( !$page )
        $page = 1;
    // If 'offset' is provided, it takes precedence over 'paged'.
    if ( isset( $q['offset'] ) && is_numeric( $q['offset'] ) ) {
        $q['offset'] = absint( $q['offset'] );
        $pgstrt = $q['offset'] . ', ';
    } else {
        $pgstrt = absint( ( $page - 1 ) * $q['posts_per_page'] ) . ', ';
    }
    $limits = 'LIMIT ' . $pgstrt . $q['posts_per_page'];
}

基本上發生了什麼,一旦偏移被明確設定,paged 引數被忽略。 SQL LIMIT 子句的第一個引數從偏移量重新計算,並將是生成的 SQL 查詢中要跳過的帖子數。

從您的問題,顯然是將 offset 設定為 0 時,偏移查詢失敗,這是奇怪的,因為以下檢查應該返回 true

if ( isset( $q['offset'] ) && is_numeric( $q['offset'] ) )

0 是一個有效的數字,應該返回 true 。如果您的安裝沒有,您應該除錯問題

為了回到手頭的問題,我們將使用相同的邏輯來計算和設定我們的偏移量,以獲得第 2 頁的帖子 1,並從中分頁查詢。對於第一頁,我們不會更改任何內容,因此假設在第 1 頁上的帖子仍然正常,我們稍後將需要”hide”,以便我們不在第 1 頁顯示它們

add_action( 'pre_get_posts', function ( $q )
{
    if (    !is_admin() // Only target the front end, VERY VERY IMPORTANT
         && $q->is_main_query() // Only target the main query, VERY VERY IMPORTANT
         && $q->is_cateory( 'news' ) // Only target the news category
    ) {
        $current_page = $q->get( 'paged' ); // Get the current page number
        // We will only need to run this from page 2 onwards
        if ( $current_page != 0 ) { // You can also use if ( is_paged() ) {
            // Get the amount of posts per page
            $posts_per_page = get_option( 'posts_per_page' );
            // Recalculate our offset
            $offset = ( ( $current_page - 1) * $posts_per_page ) - $posts_per_page; // This should work on page 2 where it returns 0

            // Set our offset
            $q->set( 'offset', $offset );
        }
    }
});

您應該看到第 2 頁的第 1 頁上的相同帖子。如前所述,如果沒有發生這種情況,is_numeric( 0 )將返回 false(不應該),或者還有另一個 pre_get_posts 操作,也試圖設定一個偏移量或者您正在使用 posts_*子句過濾器 (更具體地說是 post_limits 過濾器) 。這將是你需要自己除錯的東西。

下一個問題是糾正分頁,如前所述,你將是一個簡短的頁面。為此,我們將需要將 get_option( 'posts_per_page' )的值新增到查詢中發現的帖子數量,因為我們將查詢量抵消該量。透過這樣做,我們有效地將 1 新增到 $max_num_pages 屬性。

add_action( 'found_posts', function ( $found_posts, $q )
{
    if (    !is_admin() // Only target the front end, VERY VERY IMPORTANT
         && $q->is_main_query() // Only target the main query, VERY VERY IMPORTANT
         && $q->is_cateory( 'news' ) // Only target the news category
    ) {
        $found_posts = $found_posts + get_option( 'posts_per_page');
    }
}, 10, 2 );

這應該排序所有,除了第一頁。

現在全部 (特別為 @ialocin – Yellow Submarine)

這一切都應該進入 functions.php

add_action( 'pre_get_posts', function ( $q )
{
    if (    !is_admin() // Only target the front end, VERY VERY IMPORTANT
         && $q->is_main_query() // Only target the main query, VERY VERY IMPORTANT
         && $q->is_cateory( 'news' ) // Only target the news category
    ) {
        $current_page = $q->get( 'paged' ); // Get the current page number
        // We will only need to run this from page 2 onwards
        if ( $current_page != 0 ) { // You can also use if ( is_paged() ) {
            // Get the amount of posts per page
            $posts_per_page = get_option( 'posts_per_page' );
            // Recalculate our offset
            $offset = ( ( $current_page - 1) * $posts_per_page ) - $posts_per_page; // This should work on page 2 where it returns 0

            // Set our offset
            $q->set( 'offset', $offset );
        }
    }
});

add_filter( 'found_posts', function ( $found_posts, $q )
{
    if (    !is_admin() // Only target the front end, VERY VERY IMPORTANT
         && $q->is_main_query() // Only target the main query, VERY VERY IMPORTANT
         && $q->is_cateory( 'news' ) // Only target the news category
    ) {
        $found_posts = $found_posts + get_option( 'posts_per_page');
    }
    return $found_posts;
}, 10, 2 );

第一頁選項

這裡有幾個選項:

選項 1

我可能會選擇這個選項。你想要做的是建立一個 category-news.php(如果還沒有這樣做) 。這將是每當檢視 news 類別時將使用的模板。這個模板很簡單

<?php
get_header()

if ( !is_paged() ) { // This is the first page
    get_template_part( 'news', 'special' );
} else { // This is not the first page
    get_template_part( 'news', 'loop' );
}

get_sidebar();
get_footer();

如您所見,我已經包括兩個模板部分,news-special.phpnews-loop.php 。現在,兩個自定義模板的基礎是:

  • news-special.php – > 這個模板部分將是您想要顯示在第一頁上的任何內容。在這裡新增所有您的自定義靜態資訊。要小心,不要在此模板中呼叫迴圈,因為這將顯示第一頁的帖子。

  • news-loop.php – > 這是我們呼叫迴圈的模板。本節將如下所示:

    global $wp_query;
    while ( have_posts() ) {
    the_post();
    
        // Your template tags and markup
    
    }
    

選項 2

使用靜態內容建立一個單獨的模板,當我們檢視 news 類別的第一頁時,只需使用 category_template 篩選器即可使用此模板。另外,請確保不要呼叫此模板中的預設迴圈。另外,請確保這裡的命名約定不會與模板層次結構中的模板名稱相沖突

我希望這是有用的。隨心所欲地發表評論

EDIT

感謝 OP,WP_Query 類有一個明確的錯誤,檢查 trac ticket #34060 。我釋出的程式碼來自 Wordpress v4.4,該版本中修復了錯誤。

我回到 v4.3 的原始碼,那裡的 bug 是,當我設定為 offset 的值時,我可以確認 0 被忽略,因為程式碼只是檢查 offset 引數是 empty 。 PHP 中的 0 為空。我不知道這個行為 (錯誤) 是否僅在 v4.3 或所有以前的版本中發現 (根據機票,該錯誤在 v4.3 中),但是有一個補丁可以檢查這個錯誤在 trac 門票裡。就像我說的,這個 bug 在 v4.4 中一定是固定的

參考文獻

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