Building Public Listings in ProcessWire with $pages->find()
Learn how to retrieve and list pages in ProcessWire using $pages->find(), with a concrete blog index example, selector details, pagination, and common pitfalls.
20 Mar 2026, 07:48 UTC

Quick answer
Use $pages->find('selector') in a template file to get a PageArray of pages that match field‑based conditions such as template=blog, limit=10, sort=-created. The returned array is iterable, countable, and respects access control by default.
Worked example: a blog index template
Assume a template named blog-index assigned to a page that should list the latest five published blog posts.
<?php
// /site/templates/blog-index.php
$posts = $pages->find('template=blog-post, limit=5, sort=-created');
?>
<ul class="blog-list">
<?php foreach ($posts as $post): ?>
<li>
<a href="url ?>">title ?></a>
<time datetime="created) ?>">
created) ?>
</time>
</li>
<?php endforeach; ?>
</ul>
Key points in the selector:
template=blog-post– matches pages using theblog-posttemplate.limit=5– caps the result set, preventing memory spikes on large trees.sort=-created– orders by thecreatedfield descending (newest first). The leading-means descending; omit it for ascending.
How the mechanism works
- Selector parsing – ProcessWire’s
Selectorsclass tokenises the string, validates field names, and builds an internal SQL query. - Access check – Before a page is added to the
PageArray,$page->viewable()is evaluated for the current user. Unpublished or restricted pages are excluded unless the selector explicitly requests them (e.g.,include=all). - PageArray construction – Matching page IDs are fetched, then
Pageobjects are instantiated lazily as you iterate.
Limits and common mistakes
Memory exhaustion
Omitting limit on a site with thousands of pages loads every matching Page object into memory. Always paginate or add a sensible limit (or use $pages->find('selector, start=0, limit=20') for manual pagination).
Permission leakage
Assuming $pages->find() bypasses permissions can expose draft content. Verify by creating an unpublished page, then requesting the listing as a guest; the page must not appear.
Selector syntax errors
Malformed field names or unsupported operators throw ProcessWire\WireException or SelectorException at runtime. Test selectors in the admin Setup > Selectors tool before deploying.
Template caching vs. data freshness
ProcessWire’s template output caching (via $config->templateCache or third‑party modules) caches rendered markup, not the selector result. After publishing a new post, clear the cache or use a cache‑busting strategy (e.g., versioned cache keys).
Verification checklist
- Add 3–5 pages using the
blog-posttemplate, publish them. - Create an additional
blog-postpage but leave it unpublished. - Visit the page using the
blog-indextemplate as a guest; only the published posts should render. - Inspect the generated HTML – each list item must contain a correct link and timestamp.
- Check the PHP error log for any
WireExceptionorSelectorException.
Diagram labels
- Selector syntax
- PageArray iteration
- Access control enforcement
- Pagination & limits
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.