<?php
function custom_pagination($wp_query = null, $range = 2) {
// Use global wp_query if none provided
if (!$wp_query) {
global $wp_query;
}
// Get total pages from query
$total_pages = $wp_query->max_num_pages;
// Return empty if only one page or no pages
if ($total_pages <= 1) {
return '';
}
// Get current page
$current_page = max(1, get_query_var('paged'));
if ($current_page == 0) {
$current_page = 1;
}
// Sanitize inputs
$current_page = max(1, intval($current_page));
$total_pages = max(1, intval($total_pages));
$range = max(1, intval($range));
// Ensure current page doesn't exceed total pages
$current_page = min($current_page, $total_pages);
// Auto-detect base URL
$base_url = '';
// Check if we're on a custom post type archive
if (is_post_type_archive()) {
$base_url = get_post_type_archive_link(get_post_type());
}
// Check if we're on a category page
elseif (is_category()) {
$base_url = get_category_link(get_queried_object_id());
}
// Check if we're on a tag page
elseif (is_tag()) {
$base_url = get_tag_link(get_queried_object_id());
}
// Check if we're on a taxonomy page
elseif (is_tax()) {
$base_url = get_term_link(get_queried_object());
}
// Check if we're on author page
elseif (is_author()) {
$base_url = get_author_posts_url(get_queried_object_id());
}
// Check if we're on search page
elseif (is_search()) {
$base_url = get_search_link();
}
// Default to current page URL
else {
$base_url = get_pagenum_link(1);
$base_url = remove_query_arg('paged', $base_url);
}
// Remove trailing slash for consistency
$base_url = rtrim($base_url, '/');
ob_start();
?>
<ul class="pagination">
<?php
// Previous page link
if ($current_page > 1) {
$prev_page = $current_page - 1;
$prev_url = ($prev_page == 1) ? $base_url : $base_url . '/page/' . $prev_page;
echo '<li class="page-item"><a class="page-link" href="' . esc_url($prev_url) . '" rel="prev">‹</a></li>';
}
// Calculate start and end of page range
$start = max(1, $current_page - $range);
$end = min($total_pages, $current_page + $range);
// Show first page if not in range
if ($start > 1) {
$first_url = $base_url;
echo '<li class="page-item"><a class="page-link" href="' . esc_url($first_url) . '">1</a></li>';
// Show ellipsis if gap exists
if ($start > 2) {
echo '<li class="page-item disabled"><span class="page-link">...</span></li>';
}
}
// Show page numbers in range
for ($i = $start; $i <= $end; $i++) {
if ($i == $current_page) {
echo '<li class="page-item active"><span class="page-link">' . $i . '</span></li>';
} else {
$page_url = ($i == 1) ? $base_url : $base_url . '/page/' . $i;
echo '<li class="page-item"><a class="page-link" href="' . esc_url($page_url) . '">' . $i . '</a></li>';
}
}
// Show last page if not in range
if ($end < $total_pages) {
// Show ellipsis if gap exists
if ($end < $total_pages - 1) {
echo '<li class="page-item disabled"><span class="page-link">...</span></li>';
}
$last_url = $base_url . '/page/' . $total_pages;
echo '<li class="page-item"><a class="page-link" href="' . esc_url($last_url) . '">' . $total_pages . '</a></li>';
}
// Next page link
if ($current_page < $total_pages) {
$next_page = $current_page + 1;
$next_url = $base_url . '/page/' . $next_page;
echo '<li class="page-item"><a class="page-link" href="' . esc_url($next_url) . '" rel="next">›</a></li>';
}
?>
</ul>
<?php
return ob_get_clean();
}
// Usage examples:
// Example 1: Default usage (uses global $wp_query)
// In any template file - archive.php, index.php, category.php, etc.
echo custom_pagination();
// Example 2: With custom WP_Query
$custom_query = new WP_Query($args);
if ($custom_query->have_posts()) {
while ($custom_query->have_posts()) {
$custom_query->the_post();
// Display posts
}
// Display pagination for custom query
echo custom_pagination($custom_query);
}
wp_reset_postdata();
// Example 3: With custom range (show more/fewer page numbers)
echo custom_pagination(null, 3); // Shows 3 pages before and after current
// Example 4: Ajax pagination (with custom query)
function ajax_load_posts() {
$paged = $_POST['page'];
$args = array(
'post_type' => 'product',
'posts_per_page' => 10,
'paged' => $paged
);
$query = new WP_Query($args);
if ($query->have_posts()) {
while ($query->have_posts()) {
$query->the_post();
// Output post content
}
}
// Return pagination
echo custom_pagination($query);
wp_die();
}
?>