Pagination Doesn’t Work

I’ve experienced this with several plugins of my own, while trying to display a numerical pagination for my custom post types and custom taxonomies.

It’s my understanding that by using WP_Query to fetch posts from the database in your own custom way (other than the default) will prevent you from using such functions as expected.

They’re intended to be used for the default posts query. So if you would like to use those functions as intended, then you’ll need to modify the default query BEFORE the query is performed. You can do this using the hook pre_get_posts.

However, if you would like to use your own custom query using WP_Query, then you’ll need to also customize how the numerical pagination works. You can get the same net result using standard WordPress functionality, but it requires a few extra lines of code to achieve the numerical pagination as expected.

Let’s say you have a custom query using WP_Query and it looks something like this:

$query = new WP_Query( $query_args );

This means you have a completely BRAND NEW query which is different than the main default query which is performed when the page is loaded.

Now WordPress is aware of TWO queries for the current page:

  1. Query #1 being the default query.
  2. Query #2 being your custom query you just created using WP_Query.

If you want your numerical pagination to work with your custom query, then you need to be aware of the current page the request is performed on.

The current page number is actually referred to as paged. You can determine the current page number using some code like this:

$current_page = 1;

if ( get_query_var( 'paged' ) ) {
    $current_page = get_query_var( 'paged' );
}

Once the current page has been determined, you can setup your custom query to look similar to this:

$query_args = array(
    'post_type'      => 'products',
    'post_status'    => 'publish',
    'posts_per_page' => 10,
    'paged'          => absint( $current_page )
);

$query = new WP_Query( $query_args );

Once the query has been performed, you then need to check if it’s located any posts in the database which match your criteria:

if ( $query->have_posts() ) {

    while ( $query->have_posts() ) {

        $query->the_post();

        // Post content here...

    }

} else {

    // No posts...

}

Now for the numerical pagination! I recommend using a WordPress function called paginate_links() for this part.

I don’t really understand the really unlikely integer part for the base, but that’s what’s demonstrated on the WordPress Codex page linked above.

  • You need to specify the current page (paged) — once again.
  • You need to know the total number of posts (which can be obtained
    from the $query variable object).
  • You need to specify a return type for this function. (Personally, I
    like it to be in array format, so that I can customize the pagination
    however I see fit).

$big = 999999999; // need an unlikely integer

$previous_text="« Previous";
$next_text="Next »";

$pagination = paginate_links( array(
    'base'      => str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) ),
    'format'    => '?current_page=%#%',
    'current'   => max( 1, $current_page ),
    'total'     => $query->max_num_pages,
    'type'      => 'array',
    'prev_text' => $previous_text,
    'next_text' => $next_text
) );

This code needs to be placed within the condition which states that we have posts available. Not inside the loop, but immediately AFTER the loop.

Once the numerical pagination has been configured, it’s ready for output (or ready to be displayed). This is where paginated items are returned in array format.

I like to wrap it with a conditional check and then loop through the items performing additional conditional checks along the way.

if ( $pagination ) {

    $content .= '<div class="clearfix"></div>' . PHP_EOL;
    $content .= '<nav id="numerical-pagination" class="text-center">' . PHP_EOL;
    $content .= '<ul class="pagination">' . PHP_EOL;

    foreach ( $pagination as $pagination_item ) {

        $class="";

        if ( stripos( $pagination_item, 'current' ) !== false ) {
            $class=" class="active"";
        }

        if ( stripos( $pagination_item, 'dots' ) !== false ) {
            $class=" class="disabled"";
        }

        $content .= '<li' . $class . '>' . $pagination_item . '</li>' . PHP_EOL;

    }

    $content .= '</ul>' . PHP_EOL;
    $content .= '</nav><!-- end #numerical-pagination .text-center -->' . PHP_EOL;
    $content .= '<div class="clearfix"></div>' . PHP_EOL;

    echo $content;

}

Note: I use Bootstrap for my WordPress themes. So if you want your pagination to look awesome, with minimal effort involved. Try out Bootstrap.

To conclude everything mention above, here’s a all-in-one copy/paste starter solution for anyone looking to create a numerical pagination with a custom posts query using WP_Query.

$current_page = 1;

if ( get_query_var( 'paged' ) ) {
    $current_page = get_query_var( 'paged' );
}

$query_args = array(
    'post_type'      => 'products',
    'post_status'    => 'publish',
    'posts_per_page' => 10,
    'paged'          => absint( $current_page )
);

$query = new WP_Query( $query_args );

if ( $query->have_posts() ) {

    while ( $query->have_posts() ) {

        $query->the_post();

        // Post content here...

    }

    $big = 999999999; // need an unlikely integer

    $previous_text="&laquo; Previous";
    $next_text="Next &raquo;";

    $pagination = paginate_links( array(
        'base'      => str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) ),
        'format'    => '?current_page=%#%',
        'current'   => max( 1, $current_page ),
        'total'     => $query->max_num_pages,
        'type'      => 'array',
        'prev_text' => $previous_text,
        'next_text' => $next_text
    ) );

    $content="";

    if ( $pagination ) {

        $content .= '<div class="clearfix"></div>' . PHP_EOL;
        $content .= '<nav id="numerical-pagination" class="text-center">' . PHP_EOL;
        $content .= '<ul class="pagination">' . PHP_EOL;

        foreach ( $pagination as $pagination_item ) {

            $class="";

            if ( stripos( $pagination_item, 'current' ) !== false ) {
                $class=" class="active"";
            }

            if ( stripos( $pagination_item, 'dots' ) !== false ) {
                $class=" class="disabled"";
            }

            $content .= '<li' . $class . '>' . $pagination_item . '</li>' . PHP_EOL;

        }

        $content .= '</ul>' . PHP_EOL;
        $content .= '</nav><!-- end #numerical-pagination .text-center -->' . PHP_EOL;
        $content .= '<div class="clearfix"></div>' . PHP_EOL;

        echo $content;

    }

    wp_reset_postdata();

} else {
    // No posts...
}

wp_reset_query();

Leave a Comment