Home WordpressWordPress cơ bản Hướng dẫn tạo phân trang wordpress

Hướng dẫn tạo phân trang wordpress

by admincp

Phân trang trong wordpress là một tính năng giúp rút gọn thanh cuộn khi blog của bạn có từ 50-100 posts hoặc lên đến 1000 bài viết.
pagination wordpress

Phân trang xuất hiện ở trang category, home, archive. Thiết lập số lượng bài viết được show ra ở mỗi phân trang, bạn vào Settings ->Reading.
Thay đổi giá trị dòng Blog pages show at most, chỉ định lượng bài viết hiển thị/page. Nhấn Save changes để lưu lại option. Giá trị này được lấy bởi option:

echo get_option("posts_per_page");

Lấy thông tin số trang hiện tại xác định trên tham số URL.

$paged = 1;	//hoặc 0
if(get_query_var('paged')) {
  $paged = get_query_var('paged');
} elseif(get_query_var('page')) {
  $paged = get_query_var('page');
}

– Lấy dữ liệu trên phân trang hiện tại.

//sử dụng WP_Query
$posts_per_page=get_option("posts_per_page");  //posts per page
$big = 999999999;
$data=new WP_Query(
	array(
                ....
		'numberposts'=>-1,
		'posts_per_page'=>$posts_per_page,		
		'paged'=>$paged
                ....
	)
);
while($data->have_posts()):
$data->the_post();
...
endwhile;

– Hiển thị liên kết phân trang.

$big = 999999999;
echo paginate_links( array(
	'base' => str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) ),	
	
	'format' => '?paged=%#%',
	'current' => min($paged,1),	
	'total' =>$data->max_num_pages,
	'prev_text'=>'<<',
	'next_text'=>'>>',
	//thêm tham số vào liên kết phân trang.
	'add_args'=>array('abc'=>1)		//result: /page/2/?s=xx&abc=1
) );

Giải thích:

  • current: chỉ số trang hiện tại, luôn bắt đầu từ 1
  • total: tổng số trang được tìm thấy.
  • add_args: mảng tham số URL được thêm vào url phân trang.

Ngoài ra, có một số thông tin khác bạn cần biết như tổng số bài viết trong kết quả Query là $data->found_posts
Nếu sử dụng global $wp_query, thì biến instance của WP_Query chính là biến toàn cục $wp_query. Tương tự trả về số lượng bài viết được tìm thấy:

$wp_query->found_posts;

Với các template như category, home thì sẽ không sử dụng WP_Query, để can thiệp phân trang thì bạn dùng query_posts. Ví dụ:

global $wp_query, $querystring;

query_posts($querystring."&posts_per_page=10");

Có thể không cần chỉ định số trang vì mặc định có ‘posts_per_page’ trong main query. Và cần show liên kết phân trang như ở trên.

echo paginate_links( array(
	'base' => str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) ),	
	
	'format' => '?paged=%#%',
	'current' => min($paged,1),	
	'total' =>$wp_query->max_num_pages,
	'prev_text'=>'<<',
	'next_text'=>'>>',
	//thêm tham số vào liên kết phân trang.
	'add_args'=>array('abc'=>1)		//result: /page/2/?s=xx&abc=1
) );

WordPress có biến global của WP_Query là $wp_query, dùng biến này để biết tổng số trang được tìm thấy. Viết lại cấu trúc đường dẫn phân trang vào thuộc tính ‘base’ và ‘format’. Bạn có thể sử dụng định dạng này.

echo paginate_links( array(
     'base' => get_pagenum_link(1) . '%_%',  
     'format' => 'page/%#%/',
    ...
));

Nếu bạn muốn tạo danh sách authors có phân trang, thì với hàm get_users cũng có thể giúp bạn làm được điều đó nhưng sử dụng tham số ‘offset‘ thay vì ‘posts_per_page‘. Ngoài class WP_Query đây là một giải pháp được tích hợp sẵn, xem thêm tại đây.

Phân trang với $wpdb

Nếu website wordpress của bạn tạo thêm bảng và muốn phân trang cho dữ liệu được liệt kê trong bảng thì làm thế nào?
Bạn chỉ băn khoăn tìm công thức tính tổng số trang bạn muốn hiện thị phù hợp với kết quả trích xuất từ bảng đó.

Thật đơn giản sử dụng công thức sau:

//$total: tổng số bài viết (dòng) được tìm thấy
//$posts_per_page: số bài viết (dòng) /1 page
ceil($total / $posts_per_page);

Tham khảo ví dụ sau đây:

$data=$wpdb->get_results("select * from wp_mytable");
$page = isset( $_GET['cpage'] ) ? abs( (int) $_GET['cpage'] ) : 1;
$posts_per_page=3;  //posts per page
$total=count($data);	//total 100 rows
echo paginate_links( array(
    'base' => add_query_arg( 'cpage', '%#%' ),
    'format' => '',
    'current' => $page,
    'total' =>ceil($total / $posts_per_page),
    'prev_text'=>__('<<'),
    'next_text'=>__('>>')
) );

Đôi khi class WP_Query không thực hiện được câu lệnh SQL phức tạp, bạn phải viết chuỗi SQL trực tiếp vào $wpdb. Chúng ta sẽ sử dụng biến SQL_CALC_FOUND_ROWS để lấy tổng số records được tìm thấy, kết hợp với lệnh LIMIT giới hạn kết quả records thỏa mãn chuỗi lệnh SELECT.
Chép đoạn code sau trong functions.php

function pagination_wpdb( ){
    global $wpdb, $paged, $max_num_pages, $current_date;

    $paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
    $post_per_page = intval(get_query_var('posts_per_page'));
    $offset = ($paged - 1)*$post_per_page;

    /* Custom sql here. I left out the important bits and deleted the body 
     as it will be specific when you have your own. */
    $sql = "
        SELECT SQL_CALC_FOUND_ROWS  {$wpdb->posts}.*
        FROM {$wpdb->posts}
        ....
        GROUP BY {$wpdb->posts}.ID 
        ORDER BY {$wpdb->posts}.post_date DESC
        LIMIT ".$offset.", ".$post_per_page."; ";   

    $sql_result = $wpdb->get_results( $sql, OBJECT);

    /* Determine the total of results found to calculate the max_num_pages
     for next_posts_link navigation */
    $sql_posts_total = $wpdb->get_var( "SELECT FOUND_ROWS();" );
    $max_num_pages = ceil($sql_posts_total / $post_per_page);

    return $sql_result;
}

Bạn nên kế thừa tham số phân trang ‘paged’ hoặc có thể lưu vào tham số khác. Nhưng việc sử dụng tham số ‘paged’ liên quan đến các hàm sử lý phân trang trong wordpress là điều tốt nhất. Truyền tổng số page $max_num_pages vào hàm hiển thị liên kết trang previous_posts_linknext_posts_link.

<?php 
    $pagination_sql = pagination_wpdb();
    /*followed by a standart loop to display your results */ 
    foreach($pagination_sql as $item){
	echo $item->post_title.'<br/>';
     }
 ?>
<div class="navigation">
    <div class="previous panel"><?php previous_posts_link('&laquo; previous',$max_num_pages) ?></div>
    <div class="next panel"><?php next_posts_link('next &raquo;',$max_num_pages) ?></div>
</div>

Kết quả giống như thế này:
pagination-wpdb

Bạn có thể liệt kê chỉ số trang bởi hàm paginate_links.

<?php
$big = 999999999;
echo paginate_links( array(
    'base' => str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) ),   
     
    'format' => '?paged=%#%',
    'current' => min($paged,1),  
    'total' =>$max_num_pages,
    'prev_text'=>'<<',
    'next_text'=>'>>',
) );
?>

Kết quả:
pagination-wpdb1

Phân trang trong trang tìm kiếm

Tạo phân trang trong trang tìm kiếm cũng giống như trên, có điều chú ý tới thuộc tính action của form.

<form method="get" action="<?php echo home_url('/')?>">

Thêm ký tự slash “/” sau url bởi hàm home_url('/') thì paginate_links mới hoạt động.

Chú ý:

Nếu số lượng bài viết cần lấy trong một phân trang nằm ngoài option “Blog pages show at most” trong phần Settings->reading hay chỉ định thuộc tính “posts_per_page”!=get_option(‘posts_per_page’) trong WP_Query, query_posts thì có hoạt động không?
Tất nhiên là hoạt động được, nhưng lưu ý giá trị posts_per_page >= (settings->reading->Blog pages show at most) không chênh nhau quá có thể chênh từ 1,2,3

Ví dụ: Giá tri trong settings->reading->Blog pages show at most đặt là 10 mà bạn muốn hiển thị 5 kết quả trong 1 phân trang thì phân trang sẽ không hoạt động.

Phân trang sử dụng Plugin

Cách đơn giản nhất và an toàn đối với những người không sành về code , là sử dụng plugin để làm việc phân trang này. Bạn có thể tải plugin “WP-PageNavi“.
Sau khi tải về giải nén vào thư mục plugins, rồi kích hoạt. Sau khi kích hoạt xong bạn cấu hình plugin để thay đổi một số hiển thị. Vào settings->PageNavi đừng quên nhấn Save Changes để lưu lại thay đổi.

*Cách Sử dụng:
Trong theme Twentyten bạn thấy có dòng phân trang:

<div class="nav-previous"><?php next_posts_link( __( '<span class="meta-nav">&larr;</span> Older posts', 'twentyten' ) ); ?></div>
<div class="nav-next"><?php previous_posts_link( __( 'Newer posts <span class="meta-nav">&rarr;</span>', 'twentyten' ) ); ?></div>

2 dòng trên có tác dụng next/prev bài viết. Với plugin WP-Pagenavi này giờ đây bạn chỉ thay bởi 1 dòng đơn giản sau:

<?php wp_pagenavi(); ?>

Tạo phân trang với custom queries.
Cách 1:

query_posts( array( 'tag' => 'foo', 'paged' => get_query_var('paged') ) );

while ( have_posts() ) : the_post();
	the_title();
	// more stuff here
endwhile;

wp_pagenavi();

wp_reset_query();	// avoid errors further down the page

Cách 2: sử dụng WP_Query, quản lý sẽ tốt hơn. Với cách này bạn cần khai báo đối tượng độc lập WP_Query vào hàm wp_reset_postdata

$my_query = new WP_Query( array( 'tag' => 'foo', 'paged' => get_query_var('paged') ) );

while ( $my_query->have_posts() ) : $my_query->the_post();
	the_title();
	// more stuff here
endwhile;

wp_pagenavi( array( 'query' => $my_query ) );

wp_reset_postdata();	// avoid errors further down the page

Xem chi tiết cách dùng: tại đây.

Tùy biến hiển thị nút phân trang

tùy biến hiển thị liên kết phân trang
Bạn có thể sử dụng hook để sửa lại mọi nội dung pagination tạo bởi wp_pagenavi. Ví dụ thêm đoạn code sau vào functions.php

//attach our function to the wp_pagenavi filter
add_filter( 'wp_pagenavi', 'ik_pagination', 10, 2 );
 
//customize the PageNavi HTML before it is output
function ik_pagination($html) {
	$out="";
 
	//wrap a's and span's in li's
	$out = str_replace("<a","<li><a",$html);	
	$out = str_replace("</a>","</a></li>",$out);
	$out = str_replace("<span","<li><span",$out);	
	$out = str_replace("</span>","</span></li>",$out);
 
	return '<div class="paging">
			<ul>'.$out.'</ul>
		</div>';
}

Lưu ý: sử dụng str_replace thay tên class của thẻ liên kết, và thêm thẻ HTML nếu muốn, nhưng tránh dùng từ “page” vì nó sẽ thay thế URL /page/ làm hỏng liên kết sang trang tới và lui.

Một số lỗi

Lỗi 404

Khi nhảy đến trang 2 có báo lỗi 404 không tìm thấy, nếu gặp lỗi này bạn nên kiểm tra lại hook pre_get_posts.

*Chỉnh lại prep_get_posts:

function my_post_queries( $query ) {
    // do not alter the query on wp-admin pages and only alter it if it's the main query
    if ($query->is_main_query()){

        // alter the query for the home and category pages
        if(is_home()){
            //$query->set('posts_per_page', 5);
            if(!$query->get('post_type')){
                $query->set('post_type',array(tutorial_posttype,'post'));
            }
            
        }
	}
}

– Ví dụ vì nguyên nhân nào đó không xác định post_type thì bạn thiết lập lại post_type.
* Có thể thay thế page vs paged:

function remove_page_from_query_string($query_string)
{
    if (isset($query_string['name']) && $query_string['name'] == 'page' && isset($query_string['page'])) {
        unset($query_string['name']);
        // 'page' in the query_string looks like '/2', so i'm spliting it out
        list($delim, $page_index) = split('/', $query_string['page']);
        $query_string['paged'] = $page_index;
    }
    return $query_string;
}
// I will kill you if you remove this. I died two days for this line
add_filter('request', 'remove_page_from_query_string');

Hoặc thêm dòng sau:

function bti_change_posts_per_page(){ return 1; }
if( preg_match("|/".get_option('tag_base')."/.+/page/[0-9]+$|i", $_SERVER['REQUEST_URI']) ){
    add_filter( 'pre_option_posts_per_page' , 'bti_change_posts_per_page');
}

Tác giả: HOANGWEB.COM

Để nhận được bài viết mới vui lòng đăng ký kênh kiến thức WordPress từ A-Z ở Form bên dưới. Bạn cũng có thể nhận được sự trợ giúp trên TwitterFacebook

Liên hệ

Công ty chuyên Thiết kế website uy tín nhất Miền Bắc: http://vinastar.net

Hotline tư vấn: 0989 48 3456

Nguồn: Sưu tầm trên internet

You may also like

Leave a Comment