Pagination Class
The Pagination class generates page navigation links and calculates all the metadata your controller needs — current page, previous/next offsets, SQL limits, and the visible page window. It supports Bootstrap, Tailwind CSS, and fully custom CSS class sets out of the box, and picks up navigation labels automatically from your active language file.
Loading the Library
Load the Pagination library inside your controller’s constructor or method:
<?php
$this->call->library('pagination');
Once loaded it is available as:
<?php
$this->pagination
Note
The Pagination class automatically loads the language helper and the
session library on construction. It reads the active language from the
session (page_language) and falls back to config_item('language').
Navigation labels (First, Last, Next, Previous) are resolved from the
active language file if translations exist.
Basic Usage
The typical workflow in a controller is:
Count the total rows for the query.
Call
initialize()to get pagination metadata (including the SQLLIMITclause).Use the returned
limitvalue in your database query.Pass data to the view.
Call
paginate()in the view (or controller) to render the HTML.
<?php
// app/controllers/Products.php
class Products extends Controller
{
public function __construct()
{
parent::__construct();
$this->call->library('pagination');
$this->call->model('Product_model', 'product_model');
}
public function index($page_num = 1)
{
$total_rows = $this->product_model->count_all();
$rows_per_page = 10;
// 'products/index' is the base URL segment for page links
$meta = $this->pagination->initialize(
$total_rows,
$rows_per_page,
$page_num,
'products/index'
);
// $meta['limit'] contains the SQL LIMIT clause for this page
$data['products'] = $this->product_model->get_all($meta['limit']);
$data['pagination'] = $this->pagination->paginate();
$data['page_info'] = $meta['info'];
$this->call->view('products/index', $data);
}
}
In the view, render the pagination control:
<?php
// app/views/products/index.php
?>
<p><?= $page_info ?></p> <!-- e.g. "Page (2 of 12)" -->
<?php foreach ($products as $product) : ?>
<div><?= htmlspecialchars($product['name']) ?></div>
<?php endforeach; ?>
<?= $pagination ?>
Initialization
initialize() must be called before paginate(). It calculates all
page metadata and stores it internally for use when rendering links.
<?php
$meta = $this->pagination->initialize(
$total_rows, // int Total number of records
$rows_per_page, // int Records to show per page
$page_num, // int Current page number (1-based)
$url, // string Base URL segment (e.g. 'products/index')
$crumbs // int Visible page links in the window (default: 5)
);
Return value
initialize() returns an associative array with the following keys:
Key |
Type |
Description |
|---|---|---|
|
string |
SQL |
|
int |
The current page number (clamped between 1 and last page) |
|
int |
Previous page number (never less than 1) |
|
int |
Next page number (never greater than last page) |
|
int |
Total number of pages |
|
string |
Human-readable page indicator, e.g. |
|
array |
The visible page numbers in the current window, e.g. |
|
string |
The base URL passed to |
Example return value for page 2 of 12 with 5 crumbs:
[
'limit' => 'LIMIT 10,10',
'current' => 2,
'previous' => 1,
'next' => 3,
'last' => 12,
'info' => 'Page (2 of 12)',
'pages' => [1, 2, 3, 4, 5],
'url' => 'products/index',
]
Note
The current page is automatically clamped so passing 0 or a page
number beyond the last page will not cause an error — it will be snapped
to 1 or the last page respectively.
Themes
Three built-in themes are available. Select one before calling paginate().
<?php
$this->pagination->set_theme('bootstrap'); // default
$this->pagination->set_theme('tailwind');
$this->pagination->set_theme('custom');
Theme |
CSS classes applied |
|---|---|
|
Uses Bootstrap 5 classes: |
|
Uses Tailwind CSS utility classes with responsive sizing, border, and focus ring |
|
No classes are set automatically — define them with |
Bootstrap output example:
<nav class="d-flex justify-content-center">
<ul class="pagination">
<li class="page-item"><a class="page-link" href="...">‹ First</a></li>
<li class="page-item"><a class="page-link" href="..."><</a></li>
<li class="page-item"><a class="page-link " href="...">1</a></li>
<li class="page-item"><a class="page-link active" href="...">2</a></li>
<li class="page-item"><a class="page-link " href="...">3</a></li>
<li class="page-item"><a class="page-link" href="...">></a></li>
<li class="page-item"><a class="page-link" href="...">Last ›</a></li>
</ul>
</nav>
Custom CSS Classes
When using the custom theme (or to override individual classes in any
theme), use set_custom_classes():
<?php
$this->pagination->set_theme('custom');
$this->pagination->set_custom_classes([
'nav' => 'flex justify-center my-6',
'ul' => 'flex gap-1',
'li' => '',
'a' => 'px-4 py-2 rounded border text-sm hover:bg-gray-100',
'active' => 'bg-blue-600 text-white border-blue-600',
]);
The five customisable class keys are:
Key |
Maps to HTML element |
Description |
|---|---|---|
|
|
Outer wrapper element |
|
|
The unordered list containing all page items |
|
|
Each page list item |
|
|
Each page anchor link |
|
|
Extra class added to the currently active page link |
Customising Labels and Delimiter
Override navigation labels and the URL delimiter with set_options().
Any property that exists on the class can be set this way.
<?php
$this->pagination->set_options([
'first_link' => '« First',
'prev_link' => '‹ Prev',
'next_link' => 'Next ›',
'last_link' => 'Last »',
'page_delimiter' => '/', // default — produces: products/index/2
]);
Default label values:
Option key |
Default value |
Description |
|---|---|---|
|
|
Label for the “go to first page” link |
|
|
Label for the “previous page” link |
|
|
Label for the “next page” link |
|
|
Label for the “go to last page” link |
|
|
Character inserted between the base URL and the page number |
Note
If a translation exists for first_link, prev_link, next_link,
last_link, or page_delimiter in the active language file, those
translations are applied automatically on construction before any
set_options() call.
Method Reference
Method |
Signature |
Returns |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Complete Example
The following example puts all the pieces together — theme selection, custom labels, and rendering inside a controller and view.
Controller:
<?php
// app/controllers/Blog.php
class Blog extends Controller
{
public function __construct()
{
parent::__construct();
$this->call->library('pagination');
$this->call->model('Post_model', 'post_model');
}
public function index($page_num = 1)
{
// Configure before initialize()
$this->pagination->set_theme('bootstrap');
$this->pagination->set_options([
'first_link' => '«',
'prev_link' => '‹',
'next_link' => '›',
'last_link' => '»',
]);
$total = $this->post_model->count_published();
$meta = $this->pagination->initialize(
$total,
10,
(int) $page_num,
'blog/index',
7 // show 7 page links in the window
);
$data['posts'] = $this->post_model->get_published($meta['limit']);
$data['page_info'] = $meta['info'];
$data['pagination'] = $this->pagination->paginate();
$this->call->view('blog/index', $data);
}
}
View:
<?php
// app/views/blog/index.php
?>
<div class="posts">
<?php foreach ($posts as $post) : ?>
<article>
<h2><?= htmlspecialchars($post['title']) ?></h2>
<p><?= htmlspecialchars($post['excerpt']) ?></p>
</article>
<?php endforeach; ?>
</div>
<div class="d-flex justify-content-between align-items-center mt-3">
<small class="text-muted"><?= $page_info ?></small>
<?= $pagination ?>
</div>
Route (add to app/config/routes.php):
<?php
$router->get('/blog/index/{page}', 'Blog@index')->where_number('page');
$router->get('/blog/index', 'Blog@index');
Tips and Best Practices
Always call
set_theme()andset_options()beforeinitialize()— the theme sets class defaults whichinitialize()may use.Store
$meta['limit']and pass it directly to your model. Never construct theLIMITclause manually — let the class calculate the correct offset.Use
$meta['info'](e.g."Page (3 of 12)") to show the user where they are without extra logic in the controller.Set
$crumbsto an odd number (5, 7, 9) so the current page sits in the centre of the visible window naturally.If you are building an API that returns JSON rather than HTML, skip
paginate()and return$meta['current'],$meta['last'], and$meta['next']directly in your response payload.For query-string pagination (
?page=2instead of/2), setpage_delimiterto?page=viaset_options().