Bootstrap

Vũ Thành Lâm

Content - Code - SEO - MMO
17/10/1979
Tây Mỗ - Nam Từ Liêm - Hà Nội
thanhlam19792003

Lamvt – Vũ Thành Lâm – bắt đầu Code 2005 Freelancer từ 2006 với hàng ngàn dự án lớn nhỏ cho nước ngoài và hàng trăm dự án web cho Việt Nam.

SEO thành công rất nhiều dự án lớn, độ khó cao.
MOD (Moderator) và Admin (Administraror) của nhiều diễn đàn về SEO và CODE web MMO tại Việt Nam
Dạy Lập trình Thiết kế Web và SEO Miễn phí 15++ Năm (Từ 2006 đến Nay)

Phân trang cho các vòng lặp tùy chỉnh WordPress custom loop

3.7/5 - (3 bình chọn)

Câu hỏi

Tôi có thêm một truy vấn tùy chỉnh/ truy vấn phụ vào mẫu file tùy chỉnh. Làm cách nào để WordPress dùng truy vấn tùy chỉnh của tôi để đánh trang, thay vì sử dụng phân trang của vòng lặp truy vấn chính (main query loop).

Phụ lục

Tôi đã sửa truy vấn vòng lặp chính (main loop query) bằng query_posts(). Nhưng tại sao phân trang vẫn không hoạt động, tôi phải sửa nó thế nào?

Chip Bennett

Câu trả lời chính xác nhất

Vấn đề

Được mặc định sẵn, WordPress dùng truy vấn chính để xác định phân trang. Đ.ối tượng truy vấn chính được lưu trữ trong global $wp_query. Nó cũng được dùng để xuất vòng lặp truy vấn chính:

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

Khi bạn dùng truy vấn tùy chỉnh (custom query), bạn tạo ra một đối tượng truy vấn hoàn toàn riêng biệt:

$custom_query = new WP_Query( $custom_query_args );
Và truy vấn đó được xuất ra bởi một vòng lặp hoàn toàn riêng biệt.
if ( $custom_query->have_posts() ) :
while ( $custom_query->have_posts() ) :
$custom_query->the_post();
Nhưng thẻ phân trang mẫu (pagination template tag), bao gồm previous_posts_link(), next_posts_link(), posts_nav_link(), và paginate_links(), output của chúng đều dựa vào đối tượng truy vấn chính, $wp_query. Truy vấn này có thể hoặc không thể phân trang được. Ví dụ, nếu current context là một mẫu trang tùy chỉnh, đối tượng $wp_query chính sẽ chỉ bao gồm một post đơn lẻ. Và ID của trang đó sẽ là ID mà mẫu trang tùy chỉnh được chỉ định.
Còn nếu current context là một chỉ số lưu trữ (archive index) thuộc loại nào đấy, $wp_query chính có thể có đủ trang để thực hiện phân trang. Và những vấn đề lại phát sinh: Đối với đối tượng $wp_query chính, WordPress sẽ chuyển một tham số phân trang đến truy vấn, dựa vào biến truy vấn URL phân trang. Khi truy vấn được nạp, tham số phân trang (paged parameter) sẽ được dùng để xác định tập hợp bài đăng được phân trang trả về. Nếu click vào link phân trang được hiện thị, trang tiếp theo được tải lên, truy vấn tùy chỉnh của bạn sẽ không thể biết được phân trang đã thay đổi.

Giải pháp

Chuyển tham số phân trang chính xác tới truy vấn tùy chỉnh

Giả sử truy vấn tùy chỉnh sử dụng mảng args:

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

Bạn phải chuyển tham số phân trang đúng tới mảng (array). Có thể thực hiện bằng cách nạp biến truy vấn URL, biến này được sử dụng để xác định trang hiện tại, thông qua thông qua get_query_var ():

get_query_var( ‘paged’ );

Sau đó bạn có thể nối tham số đó vào mảng truy vấn tùy chỉnh args của bạn:

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

Lưu ý: Nếu trang của bạn là trang tĩnh, hãy dùng page thay vì paged bởi vì trang tĩnh dùng page chứ không phải paged. Đối với trang tĩnh, bạn làm như sau:

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

Giờ thì khi truy vấn tùy chỉnh được nạp, tập hợp đúng của các bài đăng được phân trang sẽ được trả về.

Sử dụng đối tượng truy vấn tùy chỉnh cho các hàm phân trang

Để các hàm phân trang cho ra output chính xác – ví dụ liên kết trước/ tiếp theo/ trang liên quan đến truy vấn tùy chỉnh – WordPress bắt buộc phải nhận diện được truy vấn tùy chỉnh. Điều này đòi hỏi một chút “hack”: thay thế đối tượng $ wp_query chính bằng đối tượng truy vấn tùy chỉnh, $ custom_query:

Hack đối tượng truy vấn chính
  1. Sao lưu đối tượng truy vấn chính: $temp_query = $wp_query
  2. Thực hiện null đối tượng truy vấn chính: $wp_query = NULL;
  3. Hoán đổi truy vấn tùy chỉnh vào đối tượng truy vấn chính: $wp_query = $custom_query;

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

“hack” phải được thực hiện trước khi gọi các hàm phân trang.

Reset đối tượng truy vấn chính

Khi hàm phân trang đã được xuất ra, tiến hành reset đối tượng truy vấn chính:

$wp_query = NULL;
$wp_query = $temp_query;

Sửa hàm phân trang

Hàm previous_posts_link() sẽ hoạt động bình thường, không bị ảnh hưởng bởi phân trang. Nó chỉ xác định trang hiện tại (current page), sau đó xuất link cho page – 1. Tuy nhiên, cần sửa next_posts_link() để xuất một cách chính xác, bởi vì next_posts_link() dùng tham số max_num_pages:

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

Như đối với các tham số truy vấn khác, hàm được mặc định sẽ dùng max_num_pages cho đối tượng $ wp_query chính. Để buộc next_posts_link () tính đến đối tượng $ custom_query, bạn cần phải chuyển max_num_pages vào hàm. Bạn có thể nạp giá trị này từ đối tượng $ custom_query: $custom_query->max_num_pages:

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

Tập hợp chúng lại với nhau

Dưới đây là cấu trúc cơ bản của một vòng lặp truy vấn tùy chỉnh (custom query loop) với các hàm phân trang thích hợp:

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

Phụ lục: Còn với query_posts()?

query_posts() cho các vòng lặp phụ

Nếu bạn đang dùng query_posts() để xuất vòng lặp tùy chỉnh, thay vì sau đó khởi tạo một đối tượng riêng biệt cho truy vấn tùy chỉnh qua WP_Query (), thì bạn lại dùng _doing_it_wrong (). Và rồi bạn sẽ gặp phải nhiều vấn đề (ít nhất bạn sẽ gặp phải vấn đề về phân trang). Bước đầu tiên để giải quyết những vấn đề này là chuyển từ việc sử dụng query_posts() sang WP_Query ().

Sử dụng query_posts() để chỉnh sửa vòng lặp chính

Nếu bạn chỉ muốn chỉnh sửa các tham số cho truy vấn vòng lặp chính (main loop query) – ví dụ như thay đổi các bài trên một trang, hoặc bỏ đi một danh mục – bạn có thể muốn sử dụng query_posts(). Nhưng vẫn không nên làm như vậy. Khi bạn sử dụng query_posts (), bạn buộc WordPress thay thế đối tượng truy vấn chính. (Chính xác thì WordPress sẽ tạo một truy vấn thứ hai và ghi đè lên $ wp_query). Vấn đề ở đây là nó thực hiện việc thay thế quá muộn và phân trang sẽ không được cập nhật.

Giải pháp cho vấn đề này là lọc truy vấn chính trước khi bài đăng được nạp vào. Bằng cách sử dụng hook pre_get_posts.

Thay vì thêm cái này vào tệp danh mục mẫu (category template file) (category.php):

query_posts( array(
‘posts_per_page’ => 5
) );

Hãy thêm phần sau vào 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’ );

Thay vì thêm cái này vào file mục lục mẫu của các bài đăng trên blog (blog posts index template file) (home.php):

query_posts( array(
‘cat’ => ‘-5’
) );

Thêm phần sau vào 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’ );

Với cách này, WordPress sẽ sử dụng đối tượng $wp_query đã được chỉnh sửa khi tiến hành xác định phân trang. Nó sẽ không yêu cầu sửa đổi mẫu.

Làm sao để biết lúc nào thì cần dùng hàm nào

Hãy tìm hiểu ở this question and answer và this question and answer để hiểu cách dùng và khi nào thì nên sử dụng  WP_Query, pre_get_posts, and query_posts().

Câu trả lời của Chip Bennett

Tin mới nhất

VR PLUS (https://vrplus.vn/ ) Là một trong những dự án do Lamvt thực hiện trong thời gian gần đây. Như...

Trong một năm qua, chúng tôi đã xuất bản khoảng 79 bài viết SEO trên blog Ahrefs. Các bài viết...

Khám phá kĩ thuật viết nội dung SEO Nếu không có SEO, nội dung của bạn có thể bị chìm...

Các website về lĩnh vực làm đẹp cần phải có một thiết kế (design) hấp dẫn và bắt mắt. Điều...

Core Web Vitals được đo lường như thế nào? Làm thế nào để bạn biết các bản sửa lỗi đã...

Tin được yêu thích

Như đã nói, phần mềm chỉnh sửa video đang ngày càng chứng tỏ được tầm quan trọng của mình, nhất...

Nhiều bạn thắc mắc là sau khi cài đặt Plugin cho Google AMP thì làm thế nào để kiểm tra,...

Các trang web giáo dục và các trang web của chính phủ có một lợi thế hơn trong bảng xếp...

Nội dung là một trong 3 tiêu chí quan trọng để google đánh giá thứ hạng tìm kiếm cho website...

Thẻ <span> </span> Thẻ <span> là thẻ khá đặc biệt trong HTML, theo mặc định thì thẻ <span> được thêm...

Khách đang xem

  1. Khi thực hiện kiểm toán SEO trên trang web, một trong những điều đầu tiên bạn cần kiểm tra đó...
    7 giây trước
  2. Câu hỏi: Menu bình thường của WordPress trông như thế này: Home | Blog | About us | Contact Nhưng...
    15 giây trước
  3. CSS Flexbox là một công cụ hữu ích cho việc bố cục trang web mà không sử dụng đến float...
    26 giây trước
  4. Bạn đang kinh doanh online? Bạn là một marketer? Hay đơn giản bạn là một Web Developers ? Và một ngày...
    9 giây trước
  5. Vị trí xếp hạng trên công cụ tìm kiếm đã mở ra một khái niệm cho ngành mới đó là...
    11 giây trước
  6. Một ngày đẹp trời, một nick lạ hoắc với tên là nữ, ảnh đại diện rất xinh inbox tới Lamvt...
    20 giây trước
  7. Để trang web của bạn có được vị trí tốt trên bảng xếp hạng, bạn nên tối ưu hoá các...
    23 giây trước
  8. Bạn đang muốn sở hữu cho riêng mình một  Private Blog Network. Nhưng điều bạn băn khoăn là để làm...
    3 giây trước
  9. Bạn chắc cũng đã từng sử dụng điện thoại thông minh hay máy tính bảng để truy cập vào các...
    14 giây trước
  10. Trong vài năm qua, các quy tắc xây dựng liên kết đã được thay đổi nhiều lần. Tuy nhiên, nguyên...
    30 giây trước