Làm cách nào tôi có thể tạo một trang đích danh mục theo sau là các trang của bài đăng?


9

Tôi đang cố gắng tạo một mẫu danh mục trong chủ đề của mình sẽ hiển thị nội dung tĩnh nếu người dùng ở trang đầu tiên của kho lưu trữ, sau đó hiển thị các bài đăng trong danh mục trên các trang sau. Về cơ bản, tôi đang cố gắng sao chép hành vi danh mục trên Wired.com trong đó http://www.wired.com/carget/design là trang đích trong khi / category / design / page / 1 hiển thị danh sách theo thời gian đảo ngược của các bài đăng như bạn mong đợi vào một kho lưu trữ thể loại.

Chìa khóa ở đây là tôi không hiển thị bất kỳ bài đăng nào từ kho lưu trữ danh mục trên trang đầu tiên, vì vậy tôi cần trang tiếp theo để bắt đầu với bài đăng đầu tiên. Trước tiên tôi đã thử làm điều này bằng cách sử dụng offset và phân trang thủ công bằng cách đặt offset của truy vấn thành 0 nếu var truy vấn 'paged' là 2. Nhưng offset được bỏ qua khi nó được đặt thành 0, vì vậy cách tốt nhất tôi có thể làm là đặt offset thành 1 và bắt đầu với bài thứ hai trong danh mục.

Đây là những gì tôi đã thêm vào hàm.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 );
  }
}

Điều gì sẽ tốt hơn và những gì nó xuất hiện Wired , là sử dụng phân trang mặc định để các bài đăng bắt đầu trên trang 1, nhưng chèn một trang 0 cho nội dung tĩnh. Về mặt giả thuyết, điều này có vẻ như có thể xảy ra bằng cách hiển thị nội dung tĩnh nếu 'paged' là 0 và hiển thị trang đầu tiên của bài đăng nếu 'paged' là 1. Vấn đề là 'paged' không bao giờ là 1 vì Wordpress đặt 'paged 'đến 0 khi người dùng yêu cầu trang đầu tiên. Điều đó có nghĩa là 'phân trang' là 0 cho cả / danh mục / tin tức / trang / 1 và / danh mục / tin tức.

Có cách nào để kiểm tra xem người dùng yêu cầu / danh mục / tin tức / trang / 1 trái ngược với / danh mục / tin tức không? Không, có cách nào để hiển thị tất cả các bài viết trong danh mục bắt đầu trên trang 2 không?

Câu trả lời:


7

Đây là một câu hỏi khá thú vị ( mà tôi đã nêu lên, đặc biệt cho cách tiếp cận và nghiên cứu của bạn ). Đường cong lớn ở đây là trang đầu tiên của truy vấn:

  • Bạn không thể đặt truy vấn để trả lại 0bài viết trên trang đầu tiên

  • Bằng cách di chuyển nội dung trang của mỗi trang lên một trang, bạn sẽ mất trang cuối cùng vì truy vấn sẽ vẫn chỉ có cùng số lượng bài đăng nên $max_num_pagestài sản sẽ vẫn giữ nguyên

Chúng ta sẽ cần phải "lừa" WP_Querylớp để trả lại bài đăng của mình một cách chính xác với phần bù của một trang và cũng có được số trang chính xác để không làm mất trang cuối cùng trong truy vấn

Hãy xem xét ý tưởng sau đây và cố gắng đưa mọi thứ vào mã. Trước khi chúng tôi làm, tôi muốn nêu ra một vài lưu ý ở đây

LƯU Ý QUAN TRỌNG:

  • Tất cả mọi thứ chưa được kiểm tra, vì vậy nó có thể là lỗi. Hãy chắc chắn để kiểm tra điều này cục bộ với gỡ lỗi được bật

  • Mã yêu cầu ít nhất PHP 5.3, bất kỳ phiên bản nào dưới 5.3 sẽ gây ra lỗi nghiêm trọng. Lưu ý, nếu vẫn đang sử dụng bất kỳ phiên bản nào dưới PHP 5.5, bạn đã nâng cấp từ lâu rồi

  • Sửa đổi và lạm dụng mã khi bạn thấy phù hợp với nhu cầu chính xác của bạn

Ý TƯỞNG ÁNH SÁNG:

Chúng ta sẽ cần gì

Để làm cho mọi thứ hoạt động, chúng tôi sẽ cần những điều sau đây:

  • Số trang hiện tại đang được xem

  • Các posts_per_pagetùy chọn thiết lập trong cài đặt đọc

  • Tập quán offset

  • Sửa đổi thuộc $found_poststính của truy vấn để sửa thuộc $max_num_pagestính

Phân trang được WP_Queryđưa ra một vài dòng mã rất đơn giản

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

Về cơ bản điều gì xảy ra, một khi phần bù được đặt rõ ràng, pagedtham số sẽ bị bỏ qua. Tham số đầu tiên của LIMITmệnh đề SQL được tính toán lại từ phần bù và sẽ là số lượng bài đăng được bỏ qua trong truy vấn SQL được tạo.

Từ câu hỏi của bạn, rõ ràng khi đặt offsetthành 0, truy vấn bù không thành công, điều này thật lạ, vì kiểm tra sau sẽ trả về đúng

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

0là một số hợp lệ và sẽ trả về đúng. Nếu điều này không có trong cài đặt của bạn, bạn nên gỡ lỗi sự cố

Để quay trở lại vấn đề trong tay, chúng tôi sẽ sử dụng cùng loại logic để tính toán và đặt phần bù của chúng tôi để có được bài 1 trên trang 2 và từ đó phân trang truy vấn. Đối với trang đầu tiên, chúng tôi sẽ không thay đổi bất cứ điều gì, vì vậy các bài đăng được cho là ở trang 1 sẽ vẫn ở trang như bình thường, chúng tôi sẽ chỉ cần "ẩn" chúng sau để chúng tôi không hiển thị chúng trên trang 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 );
        }
    }
});

Bạn sẽ thấy các bài đăng tương tự từ trang 1 trên trang 2. Như tôi đã nói trước đây, nếu điều này không xảy ra, thì nó sẽis_numeric( 0 ) trả về sai ( không nên ) hoặc bạn có một pre_get_postshành động khác cũng đang cố gắng đặt bù hoặc bạn đang sử dụng việc sử dụng các posts_*bộ lọc mệnh đề ( cụ thể hơn là post_limitsbộ lọc ). Đây sẽ là một cái gì đó bạn sẽ cần phải tự gỡ lỗi.

Vấn đề tiếp theo là sửa lỗi phân trang, tạm dừng như tôi đã nói trước đây, bạn sẽ là một trang ngắn. Đối với điều này, chúng tôi sẽ cần thêm giá trị của get_option( 'posts_per_page' )số lượng bài đăng được tìm thấy trong truy vấn vì chúng tôi đang bù đắp truy vấn theo số tiền đó. bằng cách này, chúng tôi đang thêm 1vào $max_num_pagestài sản một cách hiệu quả .

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

Điều này sẽ sắp xếp mọi thứ, ngoại trừ trang đầu tiên.

TẤT CẢ MỌI THỨ NGAY BÂY GIỜ ( và đặc biệt dành cho @ialocin - Tàu ngầm vàng )

Tất cả điều này nên đi vào 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 );

LỰA CHỌN TRANG ĐẦU TIÊN

Có một vài lựa chọn ở đây:

LỰA CHỌN 1

Tôi rất có thể sẽ đi cho tùy chọn này. Những gì bạn muốn làm ở đây là tạo ra một category-news.php( nếu bạn chưa làm điều này ). Đây sẽ là mẫu sẽ được sử dụng bất cứ khi nào newsthể loại được xem. Mẫu này sẽ rất đơn giản

Thí dụ

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

Như bạn có thể thấy, tôi đã bao gồm hai phần mẫu news-special.phpnews-loop.php. Bây giờ, những điều cơ bản của hai mẫu tùy chỉnh là:

  • news-special.php-> Phần mẫu này sẽ là bất cứ điều gì bạn muốn hiển thị trên trang đầu tiên. Thêm tất cả thông tin tĩnh tùy chỉnh của bạn ở đây. Hãy cẩn thận đừng gọi vòng lặp trong mẫu này vì điều này sẽ hiển thị các bài đăng của trang đầu tiên.

  • news-loop.php-> Đây là mẫu mà chúng ta sẽ gọi vòng lặp. Phần này sẽ trông giống như thế này:

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

LỰA CHỌN 2

Tạo một mẫu riêng với nội dung tĩnh của bạn và chỉ cần sử dụng category_templatebộ lọc để sử dụng mẫu này khi chúng tôi xem trang đầu tiên của newsdanh mục. Ngoài ra, hãy chắc chắn không gọi vòng lặp mặc định trong mẫu này. Ngoài ra, hãy đảm bảo rằng quy ước đặt tên của bạn ở đây không va chạm với tên mẫu trong cấu trúc phân cấp mẫu

Tôi hy vọng điều này là hữu ích. Hãy thoải mái nhận xét ý kiến ​​với mối quan tâm

BIÊN TẬP

Nhờ OP, có một lỗi nhất định trong WP_Querylớp, hãy kiểm tra vé trac # 34060 . Mã tôi đã đăng là từ Wordpress v4.4 và lỗi được sửa trong phiên bản này.

Tôi đã quay lại mã nguồn của v4.3, nơi có lỗi và tôi có thể xác nhận rằng 0nó bị bỏ qua khi được đặt làm giá trị thành offsetmã chỉ đơn giản là kiểm tra xem offsettham số có phải không empty. 0được lấy làm trống trong PHP. Tôi không chắc chắn nếu hành vi này (lỗi) chỉ được tìm thấy trong phiên bản v4.3 hoặc trong tất cả các phiên bản trước đó (theo vé, lỗi này là trong phiên bản 4.3), nhưng có một bản vá cho lỗi này mà bạn có thể kiểm tra ra trong vé trac. Như tôi đã nói, lỗi này chắc chắn đã được sửa trong v4.4


2
Cảm ơn câu trả lời chi tiết của bạn. Đây thực sự là khá nhiều những gì tôi đã thực hiện trong nỗ lực đầu tiên của tôi. Vấn đề là cài đặt 'offset' thành 0 không hoạt động. Hóa ra đó thực sự là một lỗi trong WordPress Core core.trac.wordpress.org/ticket/34060 . Vá nó làm cho mọi thứ hoạt động. Điều duy nhất mà mã của bạn bị thiếu là return $found_posts;sau câu lệnh if trong hành động Found_posts. Cảm ơn!
willcwelch

Cảm ơn bạn đã phản hồi tích cực của bạn. Tôi đã quay lại mã nguồn phiên bản 4.3 query.php, và vâng, 0sẽ bị bỏ qua vì kiểm tra ở đây là trống và 0được coi là trống. Mã trong câu trả lời của tôi là mã cập nhật được gửi cùng với v4.4, vì vậy tôi có thể xác nhận rằng lỗi đã được sửa trong 4.4. Tôi sẽ cập nhật câu trả lời của tôi cho phù hợp. Về found_postsvấn đề, bắt tốt, nó thực sự là một bộ lọc và nên được trả lại. Thưởng thức
Pieter Goosen

haha, cảm ơn :) và vì tất cả những gì đang tự hỏi tại sao ... một, hai, ba, bốn, tôi có thể có thêm một chút ... liên kết thực sự với bài hát bây giờ không
Nicolai

@ialocin hahaha, tôi sẽ nhớ cái này ;-)
Pieter Goosen

1
nó khá hấp dẫn :) nhưng không có gì lạ, vì nó được viết khá nhiều như một bài hát thiếu nhi
Nicolai

0

Cập nhật:

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 paged
 $ppp = get_option('paged');
}
// Next, handle paged
if($ppp > 1){
    $query->set('paged', $ppp-1);
}

Hãy thử một vài thứ như

$paged = ( get_query_var('paged') ) ? get_query_var('paged')-1 : 1;
$args = array (
    'paged' => $paged,
);

Tôi đã sửa lời giải thích của mình về cách hoạt động của biến 'phân trang'. Có vẻ như những gì bạn đang cố gắng làm giảm mỗi số trang xuống 1, do đó, yêu cầu cho trang 2 cung cấp cho bạn trang 1. Vấn đề là khi trang 1 được truy vấn, 'paged' được đặt thành 0. Ngoài ra, get_query_var () nên được sử dụng thay vì get_option cho 'paged'. Với sửa lỗi đó, khi điều này chạy, mỗi lần thay đổi truy vấn, nó lặp lại cho đến khi 'paged' là 0 cho bất kỳ yêu cầu trang nào.
willcwelch
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.