paginate_links() adds empty href to first page and previous link

All we need is an easy explanation of the problem, so here it is.

This is really weird. In attempting to solve this problem i ended up with an almost perfect use of paginate_links() instead of a custom pagination function:

$myquery = new WP_Query($args);

$paged = get_query_var('page');
($paged == 0 ? $paged = 1 : $paged = $paged);

    $pagination = paginate_links(array(

    'total'     => $myquery->max_num_pages,
    'current'   => $paged,
    'show_all'  => true,
    'type'      => 'list',
));

This seemed to work fine. Until i found out that no matter what i do, whenever i’m after page 1, the function prints an empty href="" on my first links.

So i get these markups:

<!-- base page - example.com/parent-page/child-page/ -->
<!-- same for page 1 - example.com/parent-page/child-page/?page=1 -->
<ul class="page-numbers">
<li><span class="page-numbers current">1</span></li>
<li><a class="page-numbers" href="?page=2" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener">2</li>
<li><a class="page-numbers" href="?page=3" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener">3</li>
<li><a class="page-numbers" href="?page=4" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener">4</li>
<li><a class="next page-numbers" href="?page=2" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener">Next</li>
</ul>

<!-- page 2 - example.com/parent-page/child-page/?page=2 -->
<ul class="page-numbers">
<li><a class="prev page-numbers" href="">Previous</a></li> <!-- empty href=" rel="nofollow noreferrer noopener"" -->
<li><a class="page-numbers" href="">1</li><!-- empty href=" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener"" -->
<li><span class="page-numbers current">2</span></li>
<li><a class="page-numbers" href="?page=3" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener">3</li>
<li><a class="page-numbers" href="?page=4" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener">4</li>
<li><a class="next page-numbers" href="?page=2" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener">Next</li>
</ul>

<!-- page 3 and onwards - example.com/parent-page/child-page/?page=3 -->
<ul class="page-numbers">
<li><a class="prev page-numbers" href="?page=2" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener">Previous</a></li> <!-- correct -->
<li><a class="page-numbers" href="">1</li><!-- empty href=" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener"" -->    
<li><a class="page-numbers" href="?page=2" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener">2</li>
<li><span class="page-numbers current">3</span></li>
<li><a class="page-numbers" href="?page=4" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener">4</li>
<li><a class="next page-numbers" href="?page=2" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener"></li>
</ul>

Digging into paginate_links() on wp-includes/general-template.php (circa line 1954) i found that for some reason it explicitly passes empty link arguments to the Previous link when on page 2:

if ( $prev_next && $current && 1 < $current ) :
        $link = str_replace('%_%', 2 == $current ? '' : $format, $base);

and to the first link (line 1968)

if ( $show_all || ( $n <= $end_size || ( $current && $n >= $current - $mid_size && $n <= $current + $mid_size ) || $n > $total - $end_size ) ) :
                $link = str_replace('%_%', 1 == $n ? '' : $format, $base);

any thoughts on why that would be, and if it’s possible to avoid it w/o creating yet another pagination function?

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

Have you tried specifying the base and format arguments for paginate_links()? It assumes the default values of:

    'base' => '%_%',  
    'format' => '?page=%#%',  

Your base should be something like /parent-page/child-page/%_%; then the first page link will be to /parent-page/child-page/, and subsequent links will follow the format /parent-page/child-page/?page=3 (example for page 3).

In the base, the %_% is replaced by the format argument.
In the format, the %#% is replaced by the page number.

http://codex.wordpress.org/Function_Reference/paginate_links

Method 2

For anyone else interested, here is the code that worked for me:

 echo paginate_links( array(
    'current' => max(1, get_query_var('paged')),
    'total' => $wp_query->max_num_pages,
    'base' => get_pagenum_link(1) . '%_%',  
        'format' => 'page/%#%',
) );

Method 3

Hideously out of date, but I’ve been having trouble with this and I got the following to work –

echo paginate_links(array(
    'base'      => remove_query_arg('page', get_pagenum_link(1)).'%_%',
    'current'   => max(1, get_query_var('page')),
    'end_size'  => 2,
    'total'     => $this->items->max_num_pages,
));

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

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 Reply