Strange paginate_links behavior. First page link is always whatever page I’m on, all other links are correct

The question:

I’m using the following code to generate some pagination:

$wp_query = new WP_Query();
$wp_query->query('posts_per_page=5'.'&paged='.$paged);
$big = 999999999;
echo '<div class="pagination">';
echo paginate_links(array(  'base' => '%_%',
                            'format' => str_replace($big, '%#%', esc_url(get_pagenum_link( $big ))),
                            'current' => max( 1, get_query_var('paged') ),
                            'total' => $wp_query->max_num_pages,
                            'end_size' =>4,
                            'type' => 'list'));     
    echo '</div>';

Its generating my links correctly on the first page, but if I go to any other page everything is still correct except the link for page 1 is always the url of whatever page I am on. Seems like I’m missing somthing simple, anyone know a fix?

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

Short answer:

Try

'base' => str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) ),
'format' => '?paged=%#%',

Long answer:

I took a look at the paginate_links() source code (v3.5.1) and there is this line (#)

$link = str_replace('%_%', 1 == $n ? '' : $format, $base);

that is giving you the empty first page link.

With your setup you have $base = "%_%" and $format = "http://example.com/page/%#%/" so this becomes:

$link = str_replace('%_%', 1 == $n ? '' : "http://example.com/page/%#%/", "%_%");

where we have two cases:

n=1:     $link = str_replace('%_%', '', "%_%");

n>1:     $link = str_replace('%_%', "http://example.com/page/%#%/", "%_%");

and after the replacement:

n=1:     $link = '';

n>1:     $link = "http://example.com/page/%#%/";

Here is an example of the output from paginate_links():

<ul class='page-numbers'>
    <li><a class="prev page-numbers" href="http://example.com/page/2/" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener">&laquo; Previous</a></li>
    <li><a class='page-numbers' href=''>1</a></li>
    <li><a class='page-numbers' href='http://example.com/page/2/'>2</a></li>
    <li><span class='page-numbers current'>3</span></li>
    <li><a class='page-numbers' href='http://example.com/page/4/'>4</a></li>
    <li><a class='page-numbers' href='http://example.com/page/5/'>5</a></li>
    <li><a class='page-numbers' href='http://example.com/page/6/'>6</a></li>
    <li><a class="next page-numbers" href="http://example.com/page/4/" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener">Next &raquo;</a></li>
</ul>

If you use instead (#):

'base' => str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) ),
'format' => '?paged=%#%',

then you get:

$link = str_replace('%_%', 1 == $n ? '' : "?paged=%#%", "http://example.com/page/%#%"); 

Since no replacement will take place

$link = "http://example.com/page/%#%";  

in both cases (n=1 and n>1) and you have a non empty first page link with the output of paginate_links():

<ul class='page-numbers'>
    <li><a class="prev page-numbers" href="http://example.com/page/2/" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener">&laquo; Previous</a></li>
    <li><a class='page-numbers' href='http://example.com/page/1/'>1</a></li>
    <li><a class='page-numbers' href='http://example.com/page/2/'>2</a></li>
    <li><span class='page-numbers current'>3</span></li>
    <li><a class='page-numbers' href='http://example.com/page/4/'>4</a></li>
    <li><a class='page-numbers' href='http://example.com/page/5/'>5</a></li>
    <li><a class='page-numbers' href='http://example.com/page/6/'>6</a></li>
    <li><a class="next page-numbers" href="http://example.com/page/4/" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener">Next &raquo;</a></li>
</ul>

To have a non empty first page link it looks like $format can be any string as long as $base doesn’t include the string "%_%", i.e. these should work fine:

'format' => '?paged=%#%',
'format' => 'page/%#%',
'format' => 'asdfasdfasdfasdfasdf',

If you don’t use permalinks, then the example in (#) will also give you non empty first page link since

$link = str_replace('%_%', 1 == $n ? '' : "?paged=%#%", "http://example.com/?paged=%#%");   

with replacements.

Method 2

Thanks birgire for help. I’m sharing the result of my paginate_links() which are working with custom taxonomy pages exactly as I need.

Hope this will help someone to fix it as quick as possible.

So here it is:

if (empty($pagerange)) {
    $pagerange = 2;
}
global $paged;
if (empty($paged)) {
    $paged = 1;
}
if ($numpages == '') {
    global $wp_query;
    $numpages = $wp_query->max_num_pages;
    if(!$numpages) {
        $numpages = 1;
    }
}        
    $pagination_args = array(
     'base'            => str_replace('%_%', 1 == $paged ? '' : "?page=%#%", "?page=%#%"),
     'format'          => '?page=%#%',
     'total'           => $numpages,
     'current'         => $paged,
     'show_all'        => False,
     'end_size'        => 1,
     'mid_size'        => $pagerange,
     'prev_next'       => True,
     'prev_text'       => __('<i class="fa fa-angle-left"></i>'),
     'next_text'       => __('<i class="fa fa-angle-right"></i>'),
     'type'            => 'list',
     'add_args'        => false,
     'add_fragment'    => ''
    );

$paginate_links = paginate_links($pagination_args);

if ($paginate_links) {
    echo "<nav class='custom-pagination'><ul>";
    echo $paginate_links;
    echo "</ul></nav>";
}

Method 3

I stumbled on a same problem and found out that I can replace:

'current' => max( 1, get_query_var('paged') ),

with:

'current' => max( 1, get_query_var('page') ),

So just renamed ‘paged’ >’page’ in query var and it works.


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