Diagnosing Slow Page Rendering in ProcessWire Caused by Inefficient $pages->find() Selectors
Learn how to spot and fix slow ProcessWire pages caused by inefficient $pages->find() selectors, with step‑by‑step checks, fixes, and when to escalate.
17 Sept 2025, 14:04 UTC

Recognizable condition
Page load times consistently exceed 2 seconds. With Debug Mode enabled, the SQL panel shows a high query count (>30) and many repetitive SELECT statements targeting the pages and field_* tables. CPU usage spikes during the request.
Cause / Diagnostic table
| Possible cause | What you’ll see in Debug Mode |
|---|---|
| Selector uses wildcard (*) or unindexed field | Repeated similar queries like SELECT ... FROM pages WHERE (template='blog-post' AND ...) with no index usage |
| Loading unnecessary fields via find() | Queries pull many columns (SELECT *) even though only a few are displayed |
| Missing template file caching | Each request re‑parses the template file, adding overhead but not extra SQL |
| High limit without pagination | Large result sets cause a single query to return hundreds of rows, increasing transfer and processing time |
Ordered checks
- Enable Debug Mode and inspect the SQL panel
Edit
/site/config.php(requires file‑system write access) and set$config->debug = true;. Reload the problematic page and open the Debug toolbar → SQL tab.Risk: Debug Mode exposes internal details; disable it on production after troubleshooting.
- Review each
$pages->find()call in the templateLook for patterns like
$pages->find("template=blog-post, limit=0")or$pages->find("template=blog-post")without a field list. - Verify field indexing
In the admin, go to Setup → Fields, edit each field used in a selector (e.g.,
title,date, custom fields). Ensure the Input tab has the Indexed checkbox enabled.Risk: Changing a field to Indexed triggers an ALTER TABLE; backup the database first.
- Consider using
$pages->get()for single‑item retrievalIf you only need one page (e.g., a sidebar widget), replace
$pages->find("template=sidebar-item, limit=1")with$pages->get("template=sidebar-item"). - Check for pagination parameters
See if the template uses
$config->usePageNumor manually passeslimit=andstart=values. Absence of pagination often leads to unlimited result sets.
Fixes tied to findings
Add indexes to selector fields
In the field editor, enable Indexed for each field used in a selector. After saving, ProcessWire will prompt to update the schema; confirm the action.
Replace wildcard selectors with explicit field lists
// Before (inefficient)
$items = $pages->find("template=blog-post, limit=0");
// After (explicit fields, limited)
$items = $pages->find("template=blog-post, title|body|date, limit=10");
Only the listed fields are fetched, reducing column load.
Apply sensible limits or use $pages->findMany()
For large collections, paginate:
$limit = 20;
$start = $input->pageNum ? ($input->pageNum - 1) * $limit : 0;
$items = $pages->find("template=blog-post, limit=$limit, start=$start");
If you need the full set for processing (e.g., export), consider $pages->findMany() with batching.
Enable template file caching
Admin → Setup → Templates → [your template] → Files → check Use file compiler (or Cache template file in older versions). This reduces PHP parsing overhead.
Escalation criteria
- After applying the above fixes, the page still loads >1.5 seconds or generates >20 SQL queries per request.
- Consider upgrading to the latest ProcessWire 3.x release, which includes improved core pagination and query optimizations.
- If the problem persists, post the Debug SQL output on the ProcessWire forums or consult the core team for deeper analysis.
- As a last resort, implement a custom service layer that caches heavy
$pages->find()results (e.g., using WireCache) for infrequently changing data.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.