Phân trang trong WordPress v3 – Tương thích mọi trang, nhẹ và đẹp

Phân trang là phần thiết yếu trong blog, trang danh sách hoặc archive trong WordPress. Mặc dù WordPress có sẵn hàm paginate_links(), nhưng đôi khi bạn cần nhiều quyền kiểm soát hơn về cấu trúc HTML, class CSS, icon, v.v…

Phân trang trong WordPress v3 – Tương thích mọi trang, nhẹ và đẹp

Dưới đây là một hàm phân trang nhẹ – đẹp – hoạt động tốt với mọi trang (bao gồm cả blog chính, category, custom query, custom post type archive…).

Mã nguồn hàm init_pagination()

Mình xuất phân trang của UIkit, bạn có thể tùy chỉnh lại cho phù hợp với dự án của mình nhé.

function init_pagination($query = null) {
    $paged = max(1, get_query_var('paged'));

    // Nếu không truyền gì → dùng global $wp_query
    if (is_null($query)) {
        global $wp_query;
        $query = $wp_query;
    }

    // Nếu truyền số nguyên thì tạo đối tượng giả
    if (is_numeric($query)) {
        $pages = (int) $query;
    } elseif ($query instanceof WP_Query) {
        $pages = $query->max_num_pages;
    } else {
        $pages = 1;
    }

    if ($pages <= 1) return;

    echo '<nav class="uk-margin-medium-top" aria-label="Pagination"><ul class="uk-pagination uk-flex-center">';

    // Nút "Trước"
    $prev_class = ($paged == 1) ? 'uk-disabled' : '';
    $prev_link = ($paged > 1) ? get_pagenum_link($paged - 1) : '#';
    echo '<li id="prev-link" class="'.$prev_class.'"><a href="'.$prev_link.'"><span class="uk-margin-small-right" uk-pagination-previous></span></a></li>';

    // Các số trang
    $range = 2;
    $show_ellipsis = false;

    for ($i = 1; $i <= $pages; $i++) {
        if ($i == 1 || $i == $pages || ($i >= $paged - $range && $i <= $paged + $range)) {
            $active = ($i == $paged) ? ' class="uk-active"' : '';
            echo '<li'.$active.'><a href="' . get_pagenum_link($i) . '">' . $i . '</a></li>';
            $show_ellipsis = true;
        } else {
            if ($show_ellipsis) {
                echo '<li class="uk-disabled"><span>…</span></li>';
                $show_ellipsis = false;
            }
        }
    }

    // Nút "Sau"
    $next_class = ($paged == $pages) ? 'uk-disabled' : '';
    $next_link = ($paged < $pages) ? get_pagenum_link($paged + 1) : '#';
    echo '<li id="next-link" class="'.$next_class.'"><a href="'.$next_link.'"><span class="uk-margin-small-left" uk-pagination-next></span></a></li>';

    echo '</ul></nav>';
}

Ưu điểm nổi bật

  • Tự động nhận paged và URL phân trang từ hệ thống WordPress.
  • Dùng được với mọi truy vấn: WP_Query, pre_get_posts, hoặc truy vấn archive mặc định.
  • Hiện dấu khi cần, giúp gọn gàng với số trang lớn.
  • Giao diện HTML dễ tùy chỉnh: có thể thay đổi thành Bootstrap, Tailwind, hoặc bất kỳ framework nào.
  • Không phụ thuộc plugin, siêu nhẹ và tối ưu.

Phiên bản hàm init_pagination() dùng paginate_links()

function init_pagination_links($query = null) {
    $paged = max(1, get_query_var('paged'));

    // Dùng global $wp_query nếu không truyền gì
    if (is_null($query)) {
        global $wp_query;
        $query = $wp_query;
    }

    // Lấy tổng số trang
    $total_pages = ($query instanceof WP_Query) ? $query->max_num_pages : (int) $query;

    if ($total_pages <= 1) return;

    $args = [
        'base'      => str_replace(999999999, '%#%', esc_url(get_pagenum_link(999999999))),
        'format'    => '?paged=%#%',
        'current'   => $paged,
        'total'     => $total_pages,
        'prev_text' => '<span class="uk-margin-small-right" uk-pagination-previous></span>',
        'next_text' => '<span class="uk-margin-small-left" uk-pagination-next></span>',
        'type'      => 'array'
    ];

    $links = paginate_links($args);

    if (!empty($links)) {
        echo '<nav class="uk-margin-medium-top" aria-label="Pagination"><ul class="uk-pagination uk-flex-center">';
        foreach ($links as $link) {
            $is_active = strpos($link, 'current') !== false ? ' class="uk-active"' : '';
            $is_disabled = strpos($link, 'next') !== false && $paged >= $total_pages || strpos($link, 'prev') !== false && $paged <= 1;
            $disabled_class = $is_disabled ? ' class="uk-disabled"' : '';

            // Gắn class chính xác theo UIKit
            echo '<li' . $is_active . $disabled_class . '>' . $link . '</li>';
        }
        echo '</ul></nav>';
    }
}

Ưu điểm của phiên bản này

  • Chuẩn WordPress: Dùng paginate_links() nên dễ dàng mở rộng, tương thích plugin SEO và caching.
  • Tùy biến dễ: Thêm format, base, prev_text, next_text để phù hợp mọi cấu trúc permalink.
  • Kết quả trả về dạng mảng (type => 'array') → dễ wrap trong HTML tuỳ thích.

Lưu ý

  • Nếu bạn dùng format => '?paged=%#%', đảm bảo Permalink dạng mặc định. Nếu bạn dùng permalink đẹp (/%postname%/), WordPress sẽ tự xử lý.
  • Hàm get_pagenum_link() đã tự tính toán base tốt rồi, nhưng vẫn nên dùng str_replace() như ví dụ để đảm bảo tính ổn định.

Cách sử dụng

Trong trang archive:

if (have_posts()) {
    while (have_posts()) {
        the_post();
        // hiển thị bài viết
    }

    // Phân trang
    init_pagination(); // dùng global $wp_query
}

Hoặc nếu bạn dùng WP_Query:

$args = [
    'post_type' => 'post',
    'paged' => get_query_var('paged') ?: 1,
    'posts_per_page' => 10,
];
$my_query = new WP_Query($args);

if ($my_query->have_posts()) {
    while ($my_query->have_posts()) {
        $my_query->the_post();
        // hiển thị
    }

    // Phân trang
    init_pagination($my_query);

    wp_reset_postdata();
}

Kết luận

Với init_pagination(), bạn có thể dễ dàng thêm phân trang đẹp, đúng chuẩn, và hiệu suất cao vào bất kỳ theme nào. Hàm này giúp bạn thoải mái kiểm soát giao diện, tránh việc phải phụ thuộc vào plugin hoặc code thừa của theme bên thứ ba.

Bình luận


  • Không có bình luận.

Init Toolbox

Nhấn Ctrl + \ trên máy tính, hoặc vuốt sang trái ở bất kỳ đâu trên mobile.

Đăng nhập





Đang tải...