Smart pagination algorithm [closed]

Here is some code based on original code from this very old link. It uses markup compatible with Bootstrap’s pagination component, and outputs page links like this:

[1] 2 3 4 5 6 ... 100
1 [2] 3 4 5 6 ... 100
...
1 2 ... 14 15 [16] 17 18 ... 100
...
1 2 ... 97 [98] 99 100
<?php

// How many adjacent pages should be shown on each side?
$adjacents = 3;

//how many items to show per page
$limit = 5;

// if no page var is given, default to 1.
$page = (int)$_GET["page"] ?? 1;

//first item to display on this page
$start = ($page - 1) * $limit;

/* Get data. */
$data = $db
    ->query("SELECT * FROM mytable LIMIT $start, $limit")
    ->fetchAll();

$total_pages = count($data);

/* Setup page vars for display. */
$prev = $page - 1;
$next = $page + 1;
$lastpage = ceil($total_pages / $limit);
//last page minus 1
$lpm1 = $lastpage - 1;

$first_pages = "<li class="page-item"><a class="page-link" href="https://stackoverflow.com/questions/163809/?page=1">1</a></li>" .
    "<li class="page-item"><a class="page-link" href="?page=2">2</a>";

$ellipsis = "<li class="page-item disabled"><span class="page-link">...</span></li>";

$last_pages = "<li class="page-item"><a class="page-link" href="?page=$lpm1">$lpm1</a></li>" .
    "<li class="page-item"><a class="page-link" href="?page=$lastpage">$lastpage</a>";

$pagination = "<nav aria-label="page navigation">";
$pagincation .= "<ul class="pagination">";

//previous button

$disabled = ($page === 1) ? "disabled" : "";
$pagination.= "<li class="page-item $disabled"><a class="page-link" href="?page=$prev">« previous</a></li>";

//pages 
//not enough pages to bother breaking it up
if ($lastpage < 7 + ($adjacents * 2)) { 
    for ($i = 1; $i <= $lastpage; $i++) {
        $active = $i === $page ? "active" : "";
        $pagination .= "<li class="page-item $active"><a class="page-link" href="?page=$i">$i</a></li>";
    }
} elseif($lastpage > 5 + ($adjacents * 2)) {
    //enough pages to hide some
    //close to beginning; only hide later pages
    if($page < 1 + ($adjacents * 2)) {
        for ($i = 1; $i < 4 + ($adjacents * 2); $i++) {
            $active = $i === $page ? "active" : "";
            $pagination .= "<li class="page-item $active"><a class="page-link" href="?page=$i">$i</a></li>";
        }
        $pagination .= $ellipsis;
        $pagination .= $last_pages;
    } elseif($lastpage - ($adjacents * 2) > $page && $page > ($adjacents * 2)) {
        //in middle; hide some front and some back
        $pagination .= $first_pages;
        $pagination .= $ellipsis
        for ($i = $page - $adjacents; $i <= $page + $adjacents; $i++) {
            $active = $i === $page ? "active" : "";
            $pagination .= "<li class="page-item $active"><a class="page-link" href="?page=$i">$i</a></li>";
        }
        $pagination .= $ellipsis;
        $pagination .= $last_pages;
    } else {
        //close to end; only hide early pages
        $pagination .= $first_pages;
        $pagination .= $ellipsis;
        $pagination .= "<li class="page-item disabled"><span class="page-link">...</span></li>";
        for ($i = $lastpage - (2 + ($adjacents * 2)); $i <= $lastpage; $i++) {
            $active = $i === $page ? "active" : "";
            $pagination .= "<li class="page-item $active"><a class="page-link" href="?page=$i">$i</a></li>";
        }
    }
}

//next button
$disabled = ($page === $last) ? "disabled" : "";
$pagination.= "<li class="page-item $disabled"><a class="page-link" href="?page=$next">next »</a></li>";

$pagination .= "</ul></nav>";

if($lastpage <= 1) {
    $pagination = "";
}


echo $pagination;

foreach ($data as $row) {
    // display your data
}

echo $pagination;

Leave a Comment