Creating pagination with PHP

Creating pagination with PHP

Wed May 18 20161,114 words

When creating any website with a grouping of similar pages such as a blog, chances are you will need to create a paginated menu to navigate those pages.

Creating a paginated menu from scratch is a good way to learn conditional logic, loops, working with numbers, and some handy SEO tips along the way.

Paginated menus are not just for pages, you will see paginated menus used for things like carousels also. The logic is the same, its just the UI and click action that is different.

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

The SEO benefits of pagination

Pagination signals to search engine thats a grouping of pages are related to each other and the order in which they appear.

Generally search engines can determine on their own the structure of paginated pages - what is page 1, page 2 etc, but you can also add rel="prev" rel="next" Meta tags to signal the previous and next pages in a paginated set.

Example if we are on page 2:

<link rel="prev" href="https://php.fyi/articles?page=1" />

<link rel="next" href="https://php.fyi/articles?page=3" />

Setting up paginated pages incorrectly can lead to duplicate content issues for your website and its nearly always recommended to include a dynamic robots Meta tag that sets index,follow on unique pages, and noindex,nofollow on duplicate pages.

Getting the total pages

To start off all you need is a single value - the total items. The total can be returned from your back end system or you can count the number of items you have.

Using an SQL query like this one, you can get the count of the number of items in your database table.

SELECT COUNT(id) FROM products LIMIT 1

For the purpose here we will say we have 90 products.

The next number thats needed is the number of items per page. A good default number for a paginated page is usually around 20, but this can vary based on the items in question or the UI design.

If we divide the total by the items per page we get the number of pages: 90 / 20 = 4.5

We always round up the number as the last page can have a variable number of items, which gives us: 5 pages

When you know the number of pages - you know both the first and last page number also (1 and 5)

PHP has all the required functions to calculate this for you.

class Pagination 
{
   public function __construct(
      protected number $perPage = 20,
      protected number $total = 90
   ) {}

   public function totalPages(): number 
   {
      return ceil($this->total / $this->perPage);
   }

   public function firstPage(): number 
   {
      return 1;
   }

   public function lastPage(): number 
   {
      return $this->totalPages();
   }
}

Getting the current page

Most website pagination works from a page parameter in the URL. As the user navigates your website the param changes, and the list of page items is updated.

In a single page application the URL may not change but the page param is stored in some other storage medium.

You only need the current page number to work out the next and previous pages, and using PHP or another language like JavaScript you can easily generate these.

class Pagination 
{
   public function previousPage(): number 
   {
      return $this->currentPage() - 1;
   }

   public function currentPage(): number 
   {
      return (int) $_GET['page'] ?? 1;
   }

   public function nextPage(): number 
   {
      return $this->currentPage() + 1;
   }
}

Getting the page offset

The complicated part is finding the page offset. The offset is numbers where the items start and end in a set.

For the purpose here we are on page 3

If we are on page 3 and we have 20 items per page, we want to start at item number 41 and end at item number 60.

PHP can do this for you.

class Pagination 
{
   public function offset(): number 
   {
      return (($this->total * $this->perPage) - $this->perPage) + 1;
   }
}

Using an SQL query you can set the offset start and number of items limit. SQL starts at a 0 index, so instead of 41 here, we use 40.

SELECT id,brand FROM products LIMIT 20 OFFSET 40

The text, page number, and CSS class will be what varies between each link in a simple pagination.

Its quite easy to build a simple method to generate the link HTML that other methods will call with custom parameters.

For more complex sites built using a framework, you will more than likely use a template for your pagination.

class Pagination 
{
   public function link(string $class, string $text, int $page): string 
   {
      return '<a class="' . $class . '" href="/articles?page=' . $page . '">' . $text . '</a>'
   }

   public function previousLink(): string
   {
      return $this->link('a-prev', 'Prev' $this->previousPage());
   }

   public function nextLink(): string
   {
      return $this->link('a-next', 'Next', $this->nextPage());
   }

   public function pageLink(int $number): string
   {
      return $this->link('a-page', $number, $number);
   }
}

Creating the navigation

In the pagination menu the first page link will only show if the current page is greater than 1.

A for loop runs for the number of total pages and creates a link for each page.

The next page link will only show if we are currently not on the last page.

class Pagination 
{
   protected array $links = [];

   public function create(): string
   {
      if($this->currentPage() > 1) {
         $this->links[] = $this->previousLink();
      }
      for($i = 1; $i <= $this->totalPages(); $i++) {
         $this->links[] = $this->pageLink($i);
      }
      if($this->currentPage() !== $this->totalPages()) {
         $this->links[] = $this->nextLink();
      }
      return implode($this->links);
   }
}

And there you have basic pagination logic.

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

You could build on this class with such things as:

  • A check on the page loop to set a custom CSS class on the current page.
  • A page path class property to make the pagination class re-usable across pages / URL's.