skip to content

PHP: Advanced Pagination

As soon as you connect to a database with PHP you will come across situations when you want to make accessible more content than can be displayed on a single page.

The solution, ubiquitous these days, is to split your data over a number of pages while displaying navigation links to let people navigate between pages.


Here we've created a dataset of just the numbers 1 through 150, and broken them up into blocks of 20 per page using just the code shown in the next section:

Page 1 | 2 | 3 ... 7 | 8 | Next »

1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20.

As you scroll through the pages, we adjust the links to try and keep them compact. This is more important when you have tens of pages. Basically, we're only displaying links that are within two positions of either end, or of the currently selected page.

The data displayed here is just numbers, but in reality each number would represent a row of data from a query, a product, search result, photo, blog entry, etc.

Pagination PHP Source Code

First we need to prepare our data and some basic variables. In the demonstration above we use the following, but you can replace them with real data:

<?PHP $NUMPERPAGE = 20; // max. number of items to display per page $this_page = "/php/pagination/"; $data = range(1, 150); // data array to be paginated $num_results = count($data); ?>

Then we use the following code to build the navigation links:

<?PHP // Original PHP code by Chirp Internet: // Please acknowledge use of this code by including this header. if(!isset($_GET['page']) || !$page = intval($_GET['page'])) { $page = 1; } // extra variables to append to navigation links (optional) $linkextra = []; if(isset($_GET['var1']) && $var1 = $_GET['var1']) { // repeat as needed for each extra variable $linkextra[] = "var1=" . urlencode($var1); } $linkextra = implode("&amp;", $linkextra); if($linkextra) { $linkextra .= "&amp;"; } // build array containing links to all pages $tmp = []; for($p=1, $i=0; $i < $num_results; $p++, $i += $NUMPERPAGE) { if($page == $p) { // current page shown as bold, no link $tmp[] = "<b>{$p}</b>"; } else { $tmp[] = "<a href=\"{$this_page}?{$linkextra}page={$p}\">{$p}</a>"; } } // thin out the links (optional) for($i = count($tmp) - 3; $i > 1; $i--) { if(abs($page - $i - 1) > 2) { unset($tmp[$i]); } } // display page navigation iff data covers more than one page if(count($tmp) > 1) { echo "<p>"; if($page > 1) { // display 'Prev' link echo "<a href=\"{$this_page}?{$linkextra}page=" . ($page - 1) . "\">&laquo; Prev</a> | "; } else { echo "Page "; } $lastlink = 0; foreach($tmp as $i => $link) { if($i > $lastlink + 1) { echo " ... "; // where one or more links have been omitted } elseif($i) { echo " | "; } echo $link; $lastlink = $i; } if($page <= $lastlink) { // display 'Next' link echo " | <a href=\"{$this_page}?{$linkextra}page=" . ($page + 1) . "\">Next &raquo;</a>"; } echo "</p>\n\n"; } ?>

expand code box

Displaying paginated data

We can display a single page - the currently selected page - of data by making use of the LimitIterator class:

<?PHP $data = new \ArrayIterator($data); // NOT needed if $data is already an Iterator! $it = new \LimitIterator($data, ($page - 1) * $NUMPERPAGE, $NUMPERPAGE); try { $it->rewind(); foreach($it as $row) { echo $row; // display record } } catch(\OutOfBoundsException $e) { echo "Error: Caught OutOfBoundsException"; } ?>

The try/catch statement prevents the loop from running if the initial value provided is out of bounds. If $page is negative, for example, or too large for the dataset. If you like you can use the exception block to set the $page variable back to 1 and then run the loop.

Join the three code blocks together and you should have a working pagination system. Note that there are a few sections where you might want to add or remove some lines - as noted in the comments.

If you're not familiar with iterators in PHP, you might find this article enlightening.

A caveat to this approach is that if your query is expensive, and not cached, then instead of LimitIterator you are better off using a query with OFFSET and LIMIT to select just the rows to be displayed, and a separate COUNT query to determine the total number of results.

Including extra link variables

The 'extra variables' section lets you define extra values to be passed from page to page when the navigation links are used. This could be a search keyword, filter setting, user id, or something else.

Variables need to be encoded using urlencode and will be passed as GET variables - as is the page variable. Here's a more fleshed out example:

<PHP ... $linkextra = []; if(isset($_GET['search']) && $search = $_GET['search']) { $linkextra[] = "search=" . urlencode($search); } if(isset($_GET['color']) && $color = $_GET['color']) { $linkextra[] = "color=" . urlencode($color); } $linkextra = implode("&amp;", $linkextra); if($linkextra) { $linkextra .= "&amp;"; } ... ?>

This will result in a string "search=search&amp;color=color" being appended to all the navigation links, so the values are preserved betwen pages.

Are you using this code, do you have questions or comment, use the Feedback form below to get in touch.



User Comments

Post your comment or question

3 October, 2022


Thank you for your help, I have successfully used this pagination project on my blog, it is very helpful to me, thank you again for your help!

2 October, 2020

Great tutorial.
How can I create pagination with filter (category for blog)?

24 June, 2020

Thanks, for perfect pagination code, thank you again God Bless You .

31 August, 2019

Thank you! The code is working perfectly.

20 August, 2018

great code working perfectly on my search-page but when i want to use it on another page, it doesnt work.. i have 3 pages of result and the first 2 work perfectly but when i go to the last page, i dont get any pagination links (previous, 1,2,3 etc).. im using the same code like on the search-page where its working perfectly..

13 July, 2018

Thank you for this perfect tutorial!

I got a little problem. I such this Pagination on an wordpress page. On startpage it works fine, but on other pages the link for every page looks like ?page=x but it links to /x

Where is the problem? Can you help me?

It sounds like you might have a plug-in converting GET variables into a search-engine-friendly format.

11 April, 2018

Great Tutorial! This PHP pagination tutorial have all the options. But I think it would be better if you add an option to change the total number of results. What do you think about it?