Hướng dẫn phân trang trong WordPress

24 Tháng sáu, 2024
(1 đánh giá)

Khi ở trang lưu trữ, chắc hẳn các bạn gặp không ít khó khăn trong việc phân trang hoặc cố gắng loay hoay nhưng không được. Bài viết này mình sẽ hướng dẫn đầy đủ nhất các trường hợp phân trang ở các page hay archive, single,.. Còn về phân trang bằng Load Ajax mình sẽ viết ở bài sau.

Phân trang ở trang lưu trữ

Vậy thế nào là trang lưu trữ? Trang lưu trữ là các trang phân loại bài viết như category, tag, custom taxonomy,…

  • archive.php : Định dạng hiển thị cho toàn bộ trang lưu trữ trên website như lưu trữ theo ngày tháng, category, tag, custom taxonomy,..
  • category.php – Định dạng hiển thị cho toàn bộ category của website.
  • category-tin-tuc.php – Định dạng hiển thị trang category có slug là tin-tuc.
  • category-123.php – Định dạng hiển thị cho category mang ID 123.
  • tag.php – Định dạng hiển thị toàn bộ tag của website.
  • tag-tin-tuc.php – Định dạng hiển thị toàn bộ tag có slug là tin-tuc.
  • tag-123.php – Định dạng hiển thị toàn bộ tag có ID là 123.
  • author.php – Định dạng hiển thị cho trang toàn bộ các tác giả trong website.
  • author-tilu.php – Định dạng trang hiển thị tác giả tên tilu.
  • author-123.php – Định dạng trang hiển thị tác giả có ID là 123.
  • archive-product.php – Định dạng trang hiển thị danh sách các bài viết thuộc post type tên product.
  • taxonomy-product-category.php – Định dạng trang hiển thị danh sách các bài viết thuộc custom taxonomy tên product-category.

Phân trang ở trang lưu trữ thường rất đơn giản, bạn có thể xem qua một cấu trúc template lưu trữ bình thường:

<?php
/**
 * The template for displaying archive pages
 *
 * @link https://developer.wordpress.org/themes/basics/template-hierarchy/
 *
 * @package ws247
 */
get_header();
?>
	<div id="primary" class="content-area">
		<main id="main" class="site-main">
		<?php if ( have_posts() ) : ?>
			<header class="page-header">
				<?php
				the_archive_title( '<h1 class="page-title">', '</h1>' );
				the_archive_description( '<div class="archive-description">', '</div>' );
				?>
			</header><!-- .page-header -->
			<?php
			/* Start the Loop */
			while ( have_posts() ) :
				the_post();
				/*
				 * Include the Post-Type-specific template for the content.
				 * If you want to override this in a child theme, then include a file
				 * called content-___.php (where ___ is the Post Type name) and that will be used instead.
				 */
				get_template_part( 'template-parts/content', get_post_type() );
			endwhile;
			the_posts_navigation();
		else :
			get_template_part( 'template-parts/content', 'none' );
		endif;
		?>
		</main><!-- #main -->
	</div><!-- #primary -->
<?php
get_footer();

Sau khi kết thúc vòng lặp while, ta có thể đẩy ngay the_posts_navigation() vào để phân trang, đây là hàm WordPress hỗ trợ sẵn và khá tiện dụng, chỉ việc chỉnh css tí là sẽ dùng được. Để hiểu sâu hơn về the_posts_navigation(), bạn có thể xem đoạn function sau đây:

function get_the_posts_navigation( $args = array() ) {
    $navigation = '';
 
    // Don't print empty markup if there's only one page.
    if ( $GLOBALS['wp_query']->max_num_pages > 1 ) {
        $args = wp_parse_args(
            $args,
            array(
                'prev_text'          => __( 'Older posts' ),
                'next_text'          => __( 'Newer posts' ),
                'screen_reader_text' => __( 'Posts navigation' ),
            )
        );
 
        $next_link = get_previous_posts_link( $args['next_text'] );
        $prev_link = get_next_posts_link( $args['prev_text'] );
 
        if ( $prev_link ) {
            $navigation .= '<div class="nav-previous">' . $prev_link . '</div>';
        }
 
        if ( $next_link ) {
            $navigation .= '<div class="nav-next">' . $next_link . '</div>';
        }
 
        $navigation = _navigation_markup( $navigation, 'posts-navigation', $args['screen_reader_text'] );
    }
 
    return $navigation;
}

Một cách thức khá đơn giản và tiện dụng phải không nào? Nhưng để phát triển hơn nữa thì mình có hay dùng một đoạn function như sau:

function giniit_pagination() {
    if( is_singular() )
        return;
    global $wp_query;
    /** Stop execution if there's only 1 page */
    if( $wp_query->max_num_pages <= 1 )
        return;
    $paged = get_query_var( 'paged' ) ? absint( get_query_var( 'paged' ) ) : 1;
    $max   = intval( $wp_query->max_num_pages );
    /** Add current page to the array */
    if ( $paged >= 1 )
        $links[] = $paged;
    /** Add the pages around the current page to the array */
    if ( $paged >= 3 ) {
        $links[] = $paged - 1;
        $links[] = $paged - 2;
    }
    if ( ( $paged + 2 ) <= $max ) {
        $links[] = $paged + 2;
        $links[] = $paged + 1;
    }
    echo '<div class="pagination"><ul class="list-unstyled">' . "\n";
    /** Previous Post Link */
    if ( get_previous_posts_link() )
      printf( '<li>%s</li>' . "\n", get_previous_posts_link( __( '<i class="fa fa-chevron-left" aria-hidden="true"></i>', 'giniit' ) ) );
    /** Link to first page, plus ellipses if necessary */
    if ( ! in_array( 1, $links ) ) {
        $class = 1 == $paged ? ' class="active"' : '';
        printf( '<li%s><a href="%s">%s</a></li>' . "\n", $class, esc_url( get_pagenum_link( 1 ) ), '1' );
        if ( ! in_array( 2, $links ) )
            echo '<li>…</li>';
    }
    /** Link to current page, plus 2 pages in either direction if necessary */
    sort( $links );
    foreach ( (array) $links as $link ) {
        $class = $paged == $link ? ' class="active"' : '';
        printf( '<li%s><a href="%s">%s</a></li>' . "\n", $class, esc_url( get_pagenum_link( $link ) ), $link );
    }
    /** Link to last page, plus ellipses if necessary */
    if ( ! in_array( $max, $links ) ) {
        if ( ! in_array( $max - 1, $links ) )
            echo '<li>…</li>' . "\n";
        $class = $paged == $max ? ' class="active"' : '';
        printf( '<li%s><a href="%s">%s</a></li>' . "\n", $class, esc_url( get_pagenum_link( $max ) ), $max );
    }
    /** Next Post Link */
    if ( get_next_posts_link() )
        printf( '<li>%s</li>' . "\n", get_next_posts_link( __( '<i class="fa fa-chevron-right" aria-hidden="true"></i>', 'giniit' ) ) );
    echo '</ul></div>' . "\n";
}

Copy đoạn sau vào file style.css:

.pagination {
	text-align: center;
	padding: 15px 0 45px;
}
.list-unstyled {
	padding-left: 0;
	list-style: none;
}
.pagination ul li {
	display: inline-block;
}
.pagination ul li:not(:last-child){
	margin-right: 5px;
}
.pagination ul li a {
	background: #f8f8f8;
	display: block;
	color: #555;
	cursor: pointer;
	font-size: 15px;
	width: 40px;
	height: 40px;
	line-height: 40px;
	-webkit-border-radius: 50%;
	border-radius: 50%;
}
.pagination ul li.active a,.pagination ul li:hover a {
	background: #EB2B2D;
	color: #FEFEFE!important;
}

Để phân trang được, các bạn chỉ cần thêm đoạn sau vào chỗ muốn hiển thị phân trang trong template lưu trữ là được:

<?php giniit_pagination() ?>

Và đây là kết quả, các bạn có thể xem ở đây:

Phân trang sau khi thêm CSS
Phân trang sau khi thêm CSS

Vậy số bài viết muốn phân trang thì chỉnh ở đâu? Các bạn có thể vào quản trị theo đường dẫn sau để thay đổi:

Cài đặt -> Đọc
Cài đặt -> Đọc
Số bài viết ở mỗi trang là 10
Số bài viết ở mỗi trang là 10

Phân trang ở các trang (page) hay bài viết (single)

Có thể bạn đã biết, khi ở trang archive, chúng ta chỉ việc dùng hàm if while để gọi được bài viết, nhưng lý do tại sao lại vậy thì bạn có thể hiểu nôm na rằng, tại trang lưu trữ đã có xuất hiện query_posts( array|string $query ). Do vậy, để có thể dùng if while trong trang trang (page) hay bài viết (single), chúng ta phải xét điều kiện gọi post-type, số lượng bài viết,… với WP_Query.

<?php
$paged = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;
$query = new WP_Query( array(
	'post_type' => 'post',
	'posts_per_page' => 6,
	'paged' => $paged
) );
if ( $query->have_posts() ) :
	while ( $query->have_posts() ) : $query->the_post(); 
		get_template_part( 'template-parts/content', get_post_type() ); 
	endwhile; 
	?>
	<div class="giniit-pagination">
		<ul class="pagination">
			<?php 
			echo paginate_links( array(
				'base'         => str_replace( 999999999, '%#%', esc_url( get_pagenum_link( 999999999 ) ) ),
				'total'        => $query->max_num_pages,
				'current'      => max( 1, get_query_var( 'paged' ) ),
				'format'       => '?paged=%#%',
				'show_all'     => false,
				'type'         => 'post',
				'end_size'     => 2,
				'mid_size'     => 1,
				'prev_next'    => true,
				'prev_text'    => sprintf( '<i></i> %1$s', __( '«', 'giniit' ) ),
				'next_text'    => sprintf( '%1$s <i></i>', __( '»', 'giniit' ) ),
				'add_args'     => false,
				'add_fragment' => '',
			) );
			?>
		</ul>
	</div> 
	<?php
endif;
?>

Copy đoạn sau vào style.css:

.giniit-pagination {
margin-top: 30px;
text-align: right; 
}
.giniit-pagination ul span,.giniit-pagination ul a{
display: inline-block; 
font-size: 14px;
color: #666666;
text-align: center;
border: 1px solid #ccc;
padding: 10px 10px;
transition: all .3s;
}
.giniit-pagination ul a:hover,.giniit-pagination ul span {
color: #fff;
background-color: #ae1c3f; 
}

Chúng ta sẽ có như sau:

Phân trang khi thêm CSS trên
Phân trang khi thêm CSS trên

Đây là hướng dẫn cơ bản về phân trang dạng paged, cả 2 cách trên khá đơn giản nhưng đối với mình khá là tiện lợi, theo một cách nào đó, mình không đánh giá cao ajax lắm. Ở bài viết tới, mình sẽ hướng dẫn bạn cách viết phân trang bằng ajax. Có vấn đề gì chưa hiểu, các bạn có thể comments bên dưới nhé

guest
0 Góp ý
Cũ nhất
Mới nhất Được bỏ phiếu nhiều nhất
Phản hồi nội tuyến
Xem tất cả bình luận
Tin tức liên quan
Custom Plus & Minus Quantity trong Woocommerce
Như bạn đã biết thì nút thay đổi số lượng của Woocommerce để default không mấy là đẹp mắt và khiến người dùng khó tương tác trong việc thay...
Hướng dẫn xóa san-pham , danh-muc-san-pham trong đường dẫn sản phẩm Woocommerce
Với mặc định của Woocommerce, chi tiết sản phẩm sẽ có dạng domain/san-pham/ten-san-pham và danh mục sản phẩm sẽ ở dạng domain/danh-muc-san-pham/ten-danh-muc. Một phần đường dẫn như vậy sẽ...
Hướng dẫn thêm Confirm Password trong Registration Page và Checkout Page
Tình trạng spam tài khoản, hay khách hàng không nghiêm túc trong việc tạo tài khoản để spam đơn hàng. Mình khuyến khích các bạn thêm một field nhập...