How to manually write your own pagination in PHP

October 26, 2018

If you use a framework such as Laravel you almost always have some pagination features built in. Here is how to manually write out your own pagination feature in some simple to follow PHP.

For this code I'll still be using Eloquent, part of Laravel. It would be easy to write out the SQL too, so I've included that as well.

Let's begin by working out how many items we have in total

First we need to know the total number of rows that we are working with, and decide how many we will show per page.

$count = BlogPost::count();
$per_page = 15;

This would be the same as: select count(*) as c from blog_posts

Calculate how many pages there will be:

$pages = ceil($count / $per_page);

The ceil() function will round up to the next full integer. So if $count/$per_page was 4.1, it would return 5.

Also, get the current page!

We need to decide what page the user is currently on. The first page would be page 1 (so be sure to remember to hard code that, even if $_GET['page'] (or whatever you use) is not set. I will hard code it in though...

$current_page = (int) 8; // ensure it is an integer!
if ($current_page < 1) {
    $current_page = 1;
if ($current_page>$pages) {
    $current_page = $pages;
    // or really, do a HTTP temporary redirect to that page

Here we set the current page (but you could replace the 8 with $_GET['page'] ?? 1 (which will be the value of 'page' in the url (for example or default to 1.

If the selected page is greater than the number of pages then you should do something like show 404 error, just show the max page's content (which is what the code above does), redirect to another page, or just show 'nothing found' (like a soft 404 error).

Oh, and of course you want to check that the current page is no smaller than 1!

Now you want to decide how many items 'along' you want to start from... (LIMIT startfromhere, takethismany, or LIMIT takethismany OFFSET startfromhere).

$current_page_from = ($current_page - 1) * $per_page;

Putting it all together

Now we have everything we need!

If you are using a ORM like eloquent, you can do something like this:

$rows = BlogPost::orderBy("id", "asc")->skip($current_page_from)->take($per_page)->get()

This would generate something like this (for page 8, 15 per page): select * from interview_question_q_and_as order by id asc limit 15 offset 105.

The reason I am focusing on providing Eloquent code and not really playing with SQL direct is because this is a beginners topic (pagination), and I really don't recommend beginners start off with direct SQL as there are so many SQL injection attacks that you will probably leave yourself open for attack with. Always use prepared statements, don't put any variables direct in SQL. I'll have a guide soon explaining everything....

Pagination links

Don't forget to include pagination links. This will simply loop through them all. You might want to modify it to show prev/next links. If you have a { font-weight:bold;} css rule, the current page will be highlighted.

for($i=1;$i<=$pages;$i++) {
    $active = ($i === $current_page) ? " class='active' " : "";
    echo "<a href='?page=$i' $active>Page $i</a> ";

How to do it in Laravel's Eloquent

// it automatically works out what page you are on
$posts = BlogPost::paginate(15);
foreach($posts as $post) {
    // cycle through the posts
// creating the clickable links...
 echo $posts->appends( [] )->links();

You can use the array in appends() to automatically include any url parameters.

(for example, if your url was /?page=3&search_for=ducks, you should do appends(['search_for']) to ensure that it gets included in your pagination links.