I am having a hard time understanding how exactly paginate_links works. I have read the documentation and used it a hundred times before, but I still do not get it fully. Especially 'base' attribute. More exactly, I had this:

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

Which was adding /page/2 to the URL. Then I changed it to this:

'base'          => @add_query_arg('paged','%#%'),

And now it is adding a GET parameter like this: &paged=5

Can anyone link me to a tutorial or an explanation of how the different attributes change the behaviour of the function, and how do they create the actual pagination?


1 Answer 1


So the purpose of the function is not that hard: generate a set of URLs of a total size with current page and some pretty parts.

The issue is that the way URL is configured is quite... original and documentation doesn't quite describe what happens accurately.

The documentation implies that these are default base and format arguments:

echo '<pre>', esc_html( paginate_links( [
    'base'    => '%_%',
    'format'  => '?page=%#%',
    'current' => 1,
    'total'   => 3,
    'type'    => 'plain',
] ) ), '</pre>';

<span class='page-numbers current'>1</span>
<a class='page-numbers' href='?page=2'>2</a>
<a class='page-numbers' href='?page=3'>3</a>
<a class="next page-numbers" href="?page=2">Next »</a>

That's not actually true. The default base and format are generated dynamically, depending on site's configuration. For my dev site they would be like this:

echo '<pre>', esc_html( paginate_links( [
    'base'    => 'http://dev.rarst.net/%_%',
    'format'  => 'page/%#%/',
    'current' => 1,
    'total'   => 3,
    'type'    => 'plain',
] ) ), '</pre>';

<span class='page-numbers current'>1</span>
<a class='page-numbers' href='http://dev.rarst.net/page/2/'>2</a>
<a class='page-numbers' href='http://dev.rarst.net/page/3/'>3</a>
<a class="next page-numbers" href="http://dev.rarst.net/page/2/">Next »</a>

So what happens there? Two things:

  1. %#% in format is replaced with current page number.
  2. Then %_% in base is replaced with format result.

So for page 2:

  1. 2 + page/%#%/ = page/2/
  2. page/2/ + http://dev.rarst.net/%_% = http://dev.rarst.net/page/2/

Rest of the arguments deals with "pretty" stuff like splitting into segments and such (so that you don't actually show 1000 links for 1000 pages).

So I guess the summary is: the function is very flexible and allows to build wildly different pagination schemes. But you really need to have specific goal in mind to build base and format correctly.

There are some higher level wrappers, that were added later and are more specific to the tasks, for example the_posts_pagination().

  • Thank you very much for your answer. Have you ever used any other scheme apart from page/2 and ?paged=2? What else can we use?
    – DekiGk
    Jul 19, 2016 at 19:13
  • I don't think I ever had a practical use cases that called for a completely custom pagination. WP generally handles everything for its own items and CPTs. Custom pagination is realm of solutions that need to query something very not–WP–ish.
    – Rarst
    Jul 19, 2016 at 19:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.