Guide
Implement Paginated Blog Listings in ProcessWire Using the Selector API
Learn how to add a paginated list of blog posts in a ProcessWire template using the selector API, with safe page‑number handling and fallback options.
Published by Tasadduq Burney
01 Apr 2026, 07:39 UTC
2 min109.5K views0

Desired outcome
Show a paginated list of blog posts with title and summary, plus previous/next navigation links.
Prerequisites
- ProcessWire 3.0+ installed.
- A template file (e.g.,
site/templates/blog.php) that will render the listing. - Blog post pages use a template named
blog-postwith fieldstitle(text) andsummary(text or textarea). - Access to the
$pagesAPI and$inputfor page numbers.
Procedure
- Open the template file for editing.
- Define the number of items per page (
$limit) and retrieve the current page number from the URL, casting it to an integer. - Calculate the start offset for the selector.
- Build a selector string that selects pages of template
blog-post, sorted by date descending (assuming a date fielddate). - Execute the paginated find and capture the PageArray.
- Output each item's title and summary, escaping HTML.
- Render the pagination markup using the built‑in paginator.
- Optional: handle empty results with a fallback message.
// blog.php
$limit = 10; // items per page
$pageNum = (int)$input->pageNum; // defaults to 1 if not set
if ($pageNum < 1) $pageNum = 1;
$start = ($pageNum - 1) * $limit;
$selector = 'template=blog-post, sort=-date';
$items = $pages->find('$selector, limit=$limit, start=$start');
<ul class="blog-list">
foreach ($items as $item) {
echo '<li>';
echo '<h2>' . $item->title . '</h2>';
echo '<p>' . $item->summary . '</p>';
echo '</li>';
}
echo '</ul>';
echo $items->getPagination()->render();
if ($items->getTotal() === 0) {
echo '<p>No blog posts found.</p>';
}
Expected checks
- Visit the page URL; the list should show up to
$limititems. - Hover over pagination links; they should point to URLs like
?page=2,?page=3, etc. - Enable debug mode (
$config->debug = true;) and review the SQL log; the query must containLIMIT $limit OFFSET $start. - On the final page, the number of items may be less than
$limit; navigation should not link beyond the last page.
Recovery options
If the selector returns an empty PageArray or an error occurs:
- Show a fallback message (as in step 8).
- Clear any cached selector results:
$cache->remove('blog-list-selector');then retry. - As a last resort, load all matching pages without pagination:
$items = $pages->find('template=blog-post');and display them.
To revert changes, restore the previous version of blog.php from version control or a backup.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.