Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Pagination

When there are hundreds of posts, they cannot be shown in one list: the page loads slowly and is awkward to use. Pagination splits the list into pages of a few records and adds links to move between them. In CodeIgniter it is built into the model.

The paginate method

Replace findAll() with paginate() in the controller:

// app/Controllers/Posts.php
public function index(): string
{
    $posts = model(PostModel::class);
 
    return view('posts/index', [
        'posts' => $posts->orderBy('id', 'DESC')->paginate(10),
        'pager' => $posts->pager,
    ]);
}

paginate(10) returns the ten records of the requested page. The model reads the page number from the address itself: /posts?page=2. The $posts->pager property is an object that knows how many pages there are and can draw the links.

<!-- app/Views/posts/index.php -->
<ul>
    <?php foreach ($posts as $post): ?>
        <li><?= esc($post['title']) ?></li>
    <?php endforeach ?>
</ul>
 
<?= $pager->links() ?>

A row of links with page numbers appears under the list. Open /posts and click "2" — the address becomes /posts?page=2 and the list shows the next ten posts.

Instead of numbers you can output only "previous" and "next":

<nav class="pager">
    <?= $pager->simpleLinks() ?>
</nav>

Page information

MethodWhat it returns
$pager->getCurrentPage()The current page number
$pager->getPageCount()The number of pages
$pager->getTotal()The total number of records
$pager->getPerPage()The number of records per page

For example, the line <p>Page <?= $pager->getCurrentPage() ?> of <?= $pager->getPageCount() ?></p> prints "Page 2 of 5".

Together with conditions

paginate() stands at the end of the chain, like findAll(), and respects all conditions:

$posts = model(PostModel::class);
 
$list = $posts->where('status', 1)
    ->orderBy('created_at', 'DESC')
    ->paginate(10);

The number of pages is counted over published posts only.

Settings

The settings live in app/Config/Pager.php. The $perPage property sets the default number of records — then paginate() can be called without an argument. The $templates property lists the link templates:

// app/Config/Pager.php
public array $templates = [
    'default_full' => 'CodeIgniter\Pager\Views\default_full',
    'default_simple' => 'CodeIgniter\Pager\Views\default_simple',
    'blog' => 'App\Views\pagers\blog',
];
 
public int $perPage = 10;

To change the markup of the links, copy the built-in template default_full.php from the vendor/codeigniter4/framework/system/Pager/Views folder to app/Views/pagers/blog.php, adjust its tags and classes and call $pager->links('default', 'blog').

Common mistake

The pager property is filled only after paginate() is called on the same model object. If the records were fetched with findAll(), or pager is taken from another object created with new PostModel(), the view fails with "Call to a member function links() on null". Store the model in a variable, call paginate() on it and take pager from the same variable, as in the first example.

Thanks for reading!

Donate to the site — we work hard for you.