Combining WordPress pagination functions for archives and search results

The question:

I am currently modernising an old WordPress theme (a standalone theme, not a child of any official themes). Trying to build pagination I am finding some issues creating one function that works for both archives and search. The first snippet works fine with archives (categories, loops, etc):

function pagination_bar() {
    global $wp_query;

    $total_pages = $wp_query->max_num_pages;

    if ($total_pages > 1){
        $current_page = max(1, get_query_var('paged'));

        echo paginate_links(array(
            'base'      => get_pagenum_link(1) . '%_%',
            'format'    => 'page/%#%',
            'current'   => $current_page,
            'total'     => $total_pages,
            'prev_text' => __('« Previous page'),
            'next_text' => __('Next page »'),
        ));
    }
}

The problem is that if I use in search results pages the links end up being domain.com/?s=QUERYpage/2 (whilst it should be domain.com/page/2/?s=query)

So I created a custom function just for pagination in search:

function pagination_bar_search() {
    global $wp_query;

    $total_pages = $wp_query->max_num_pages;

    if ($total_pages > 1){
        $current_page = max(1, get_query_var('paged'));

        echo paginate_links(array(
            'base'      => get_home_url() . '%_%',
            'format'    => '/page/%#%/',
            'current'   => $current_page,
            'total'     => $total_pages,
            'prev_text' => __('« Previous page'),
            'next_text' => __('Next page »'),
        ));
    }
}

Both work correctly, but do you have any ideas for how I can combine the 2 functions and make one that works correctly for both archives and search?

I’m on the latest WordPress (5.2.3).

This is the search.php loop function:

<?php
$paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
if ($wp_query->max_num_pages > 1)
echo 'Page ' . $paged.' of '.$wp_query->max_num_pages; 
?>

...

<?php if (have_posts()) : while (have_posts()) : the_post(); ?>

...

<?php endwhile; ?>

<?php pagination_bar_search(); ?>

The Solutions:

Below are the methods you can try. The first solution is probably the best. Try others if the first one doesn’t work. Senior developers aren’t just copying/pasting – they read the methods carefully & apply them wisely to each case.

Method 1

From the Codex:

To add pagination to your search results and archives, you can use
the following example:

<?php
global $wp_query;

$big = 999999999; // need an unlikely integer

echo paginate_links( array(
  'base' => str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) ),
  'format' => '?paged=%#%',
  'current' => max( 1, get_query_var('paged') ),
  'total' => $wp_query->max_num_pages
) );
?>

So based on that, I modified your function:

function pagination_bar( $query = null ) {
    global $wp_query;

    $total_pages = $query ?
        $query->max_num_pages :
        $wp_query->max_num_pages;

    if ( $total_pages > 1 ) {
        $big = 999999999; // need an unlikely integer
        $current_page = max( 1, get_query_var( 'paged' ) );

        echo paginate_links( array(
            'base'      => str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) ),
            'format'    => '?paged=%#%',
            'current'   => $current_page,
            'total'     => $total_pages,
            'prev_text' => __( '« Previous page' ),
            'next_text' => __( 'Next page »' ),
        ) );
    }
}

and it worked well, both with archives and search results.

I also added support for custom query (i.e. new WP_Query), so that you could for example do:

$my_query = new WP_Query( array( ... ) );
pagination_bar( $my_query );

Method 2

I’m facing the same problem even after using the above approach, the problem for me isn’t coming from the WP_Query Class or the pagination.

I just figured out that the offset parameter ignores and breaks the paged parameter and the whole pagination, and the thing is I can’t let go of the offset parameter as my theme structure relies on it. Is there any solution for this matter?
Thanks

Method 3

To keep the same format rather than using a query argument, I added a check in the function to see if we are on a search page or not and modified the base and format.

/**
 * Numbered pagination
 */
function so_348298_pagination_links() {
    global $wp_query;

    $total_pages = $wp_query->max_num_pages;

    if ( $total_pages > 1 ) {
        $current_page = max( 1, get_query_var( 'paged' ) );

        $base = get_pagenum_link( 1 ) . '%_%';
        $format = 'page/%#%';

        if (is_search()) {
            $base = get_home_url() . '%_%';
            $format = '/page/%#%/';
        }

        echo '<div class="pagination-links col-12 text-center mb-5">' .
             paginate_links( array(
                 'base'    => $base,
                 'format'  => $format,
                 'current' => $current_page,
                 'total'   => $total_pages,
                 'type'    => 'list',
             ) ) .
             '</div>';
    }
}


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Comment