Published: 20th Dec 2017 | Words: 2,517 | Reading Time: 13 minutes


Using PHP to build pagination

I thought I would write this particular article to show the logic behind pagination and to give and insight into how you can work out complex logic to make complex programs. In an ecommerce site you will almost certainly need pagination. If you don’t know what pagination is, it’s breaking up similar content across pages with a menu that navigates those particular pages only. Although a particular catalogue within an ecommerce site may be split across these paginated pages they are in fact the same page just split up. For SEO reasons you should be including rel meta tags to show search engines these separate pages are in fact a group of pages and should really be treated as one entity. Generally a product catalogue will run across the pages in a paginated series and you need to build a way for users to navigate easily across these pages. Your products will usually be draw from a database and how many pages there are in the paginated pages depends on factors like this.

Start with a single value

I personally think learning how to build pagination is a great tool to allow you to work out logic behind other features you may wish to build within your site. The simple thing about building pagination is that once you have a single value to start with you can work out everything else from it. For the purpose of this article we are going to be building a very simple ecommerce product catalogue with a pagination menu that navigates between the catalogue pages.

The total

So what do we need first? Simple really, the total number of products to display. While this may seem complex to work out, generally you will be querying a database with the specific products to display on these pages such as by brand or make. You may also be displaying every product in the database across these pages. In any situation you need to query the database and count the number of products / database rows that match what you want.

$stmt = $this->mysqli->stmt_init(); // initialise stmt object

$stmt->prepare("SELECT COUNT(id) FROM products WHERE brand = 'ddmseo' LIMIT 1"); // we only need one result – the total


$stmt->bind_result($total); // assign the total to a variable so you can reference it



For the purpose of this article we are going to assume the total is 100.

The number of pages

So how do we know how many pages to break up the total 100 products across? That’s actually pretty easy. By default the pages should have a default total to run across each page. For here we are going to say 15 products per page. If you divide 15 into 100 you will find the catalogue needs 7 pages. 6 pages with 15 products and a 7th page with 10 products. Using PHP you can find the total the following way.

$perPage = 15; // you can set a default value yourself

$pages = ceil($total / $perPage); // 100 divided by 15 equals 7 using the ceil function

The ceil function returns how many times $perPage divides and even if on the last division it only partially divides it returns another 1. What this does is give you the number of pages required to effectively display all the products even if the last page doesn’t have the full 15. To take this further on an ecommerce site you will almost certainly have options for users to change the number of products per page. The following uses a perpage URL paramter to set a new $perPage value;

if(isset($_GET['perpage']) && is_numeric($_GET['perpage'])) {
   $perPage = $_GET['perpage']; // its now 30

$pages = ceil($total / $perPage); // 100 divided by 30 equals 4 using the ceil function here

As you can see it doesn’t really matter what the total products per page is just as long as you keep track of the value changing (generally on page reload but you can also build pagination with AJAX) then you can adjust other totals accordingly.

Going forward we are going to say $pages = 7.

The current page

Again an easy thing to work out. To paginate between pages you need a page URL parameter. Now if this is not set it means you are on the first page. If it is set it and let’s say it shows as “page=3”, you know you are on the 3rd page of the paginated catalogue. // we get what page we are on using the page parameter

if(isset($_GET['page']) && is_numeric($_GET['page'])) {
   $page = $_GET['page']; // page is 3
} else {
   $page = 1; // if no page parameter is set we are on the first page

Going forward we are going to say $page = 3.

The SQL for selecting the products

All these initial values you have gotten will help you put together an SQL query that will select the product data form your database. Using the variables above you know what page you are on therefore you know at which point to start selecting products within the total and you also know where to stop because you know the total number to return. The total products in the catalogue is 100. Of that 15 products display on each page and we are on the third page. Therefore we start at the 31st product. The first 2 pages contain 30 products in total (2 x 15). This value can be used within an SQL query to specify where to start selecting from in the 100 matching products / database rows. TO do this automatically we could do.

$start = ($page * $perPage) - $perPage; // $start = (3 multiplied by 15) minus 15

The reason we take away $perPage at the end is because although we are on the third page 3 x 15 gives 45 because it counts the current page products. We want to start at the start of the 3rd page and not the end there fore we take away the total products for the page (15). Now our start is 30. While we said earlier we need to start on the 31st product our start number is 30. When you select rows from a database the index of the returned array starts at 0.

row[0] // the first returned row is index 0
row[1] // the second returned row is index 1 etc.

Therefore you can look at it as we are starting to select from the 30th index which is the 31st row. For our next SQL query; the one that will select the specific 15 products for the third page we are on we can use.

$stmt->prepare("SELECT id,brand FROM products WHERE brand = 'ddmseo' LIMIT 30,15");

The two values at the end of the query refer to the 30th index which is the 31st product and the 15 refers to how many rows / products to return. We got both these values earlier. To make this dynamic we can use.

$stmt->prepare("SELECT id,brand FROM products WHERE brand = 'ddmseo' LIMIT $start,$perPage");

If you are inserting variables into statements like this make sure you’re validating them or you can end up with security holes. As you see now though these two values will also update based on the page URL parameter. As you navigate through the paginated pages the page URL parameter is read, the starting product and number of products per page is worked out, and the appropriate products are returned from the database. To display the products on your page you will need to loop through them and assign them to a variable and output it.

The navigation

While we have returned the exact products we need for the page we are on. We have not given users a way of navigating between the pages in the manner of a catalogue. The logic is fairly straightforward and the totals we have gotten previously will give us everything we need to build these buttons. The first thing we can look at is a previous button to take us back to the page beforehand. Simple really, if the current page is greater than 1 we will need a button to go back to the previous page if not we are on the first page and there is no need for the button. If there is the need for the button we set the page parameter in the link back to the previous page to the current page minus 1.

if($page > 1) {
   $prevButtonHtml = '<a href="/catalogue.html?page='.($page - 1).'">Prev</a>';
   // create a link to the previous page
[ prev ] // now we have a previous page link

Next we can have individual links to each page with the number of the page on them. We need 7 links as we know there are 7 pages in the paginated series. To do this dynamically we create a PHP for loop.

$pageButtonsHtml = ""; // Create an empty variable to hold the different buttons HTML.

for($i = 1; $i <= $pages; $i++) {
   if($i != $page) {
      $pageButtonsHtml .= '<a href=”/catalogue.html?page='.($i).'">'.$i.'</a>';
   } else {
      $pageButtonsHtml .= $i;
| 1 | 2 | 3 | 4 | 5 | 6 | 7 |

Every time the for loop runs here it generates a button. The $i variable is set to one and every time the loop runs $i increments by 1 so 1, 2, 3 etc. The $i variable is used within the HTML also to generate the number for each button and this loop runs while $i is less than or equal to the total number of $pages. Within this there is an if state that says if we are not on the current page ($page) generate a link around the page number text otherwise generate the page number text only. This is because you don’t need a link to the current page you are on and it gives you a way of showing what page the user is on. The final button is the next button. Straight forward again, this button should show on every page except the last one or if we are on the first page and there is no next page.

if($page < $pages) {
   $nextButtonHtml = '<a href="/catalogue.html?page='.($page + 1).'">Next</a>';
   // create a link to the next page
| Next | // now we have a next page link

In our example here $pages is equal to 7 therefore the next button will show if our current page is less than 7. We are on page 3 and a next button will show in this situation. Our final pagination for the current page would look something like this.

| Prev | 1 | 2 | 3 | 4 | 5 | 6 | 7 | Next |

Because we are generating this dynamically no matter what page you are on the corresponding pre and next buttons will show and the page buttons will be worked out even if the total products in the database changes. This is in essence a very basic working pagination system and shows how you can work things out very easily if you know the logic. To put this live on a page you would just combined the different variables that contain the button HTML code into one variable and just output it although this is a very basic example and you would want something much more complex.