PageFinder
PageFinder translates ProcessWire selector strings into SQL queries and
executes them against the database
It is the core engine behind
Most code will never call Page Source file: wire/core/Page Expand all Collapse all API reference Main method. Accepts a selector string, array, or Selectors object,
builds the SQL query, executes it, and returns matching data. The return
value depends on the Throws Convenience wrapper around Returns an array of all columns from the Returns an array of parent IDs for each matched page (duplicates
removed via Returns an array of Returns the total number of matching pages without loading page data.
Uses The following methods return information about the most recent Returns the cumulative execution time (in seconds) for all Page All options are passed as the second argument to These are nested inside Page Page The How to get an instance: Site-wide option overrides via Page status filtering is automatic. Every Access control is on by default. Non-superusers see only
templates they have view access to. Disable with Return values are raw data, not Page objects. Page Sub-selectors and OR groups. Page Fieldtype-specific query building. For each custom field,
Page Source file: Hookable methods: Click any linked item for full usage details and examples. Hookable methods are indicated with the icon. In addition to those shown below, the In addition to the methods and properties above, Page$pages->find(), $pages->get(), $pages->count(), and all other
page-retrieval operations. Given a selector string, array, or
Selectors object, PageDatabaseQuerySelect — including joins, sub-selects, and access-control
WHERE clauses — and returns raw database rows (page IDs, parent IDs,
template IDs, scores, or full table columns), not Page objects.$finder = new PageProperty Type Description includeModestringInclude mode from the last find(): '', 'hidden', 'unpublished', 'trash', or 'all'. Read-only via __get.checkAccessboolWhether template access-control checking is active for the current find. false when include=all or check_access=0. Read-only via __get.find($selectors, $options)
returnVerbose, returnParentIDs,
returnTemplateIDs, and returnAllCols options — by default, an array of
arrays containing id, parent_id, templates_id, and score keys.// Default: returns verbose array like:
// [ ['id' => 1234, 'parent_id' => 1000, 'templates_id' => 50, 'score' => 0], ... ]
$rows = $finder->find('template=blog-post, sort=-created, limit=10');
// Return a simple array of page IDs
$ids = $finder->find('template=blog-post, limit=10', ['returnVerbose' => false]);
// Return only the DatabaseQuerySelect object without executing it
$query = $finder->find('template=blog-post', ['returnQuery' => true]);
echo $query->getQuery(); // inspect the generated SQLPage on database errors and
Page on selector syntax errors.findIDs($selectors, $options)
find() that returns a simple array of
page IDs (no parent, template, or score data).$ids = $finder->findIDs('parent=/about/, template=staff-member');
// [1023, 1024, 1025, ...]findVerboseIDs($selectors, $options)
pages table, indexed by page
ID. Supports joining additional fields, sortfields, child counts,
page paths, and Unix timestamps via options. (3.0.153+// Return all pages-table columns indexed by page ID
$rows = $finder->findVerboseIDs('template=article, limit=10');
// [ 1234 => ['id'=>1234, 'name'=>'hello-world', 'status'=>1, ...], ... ]
// Join additional custom fields and the sortfield column
$rows = $finder->findVerboseIDs('template=article, limit=10', [
'joinFields' => ['headline', 'summary'], // join these field tables
'joinSortfield' => true, // include pages_sortfields.sortfield
'getNumChildren' => true, // include numChildren per page
'unixTimestamps' => true, // return dates as Unix timestamps
]);findParentIDs($selectors, $options)
GROUP BY). Requires returnVerbose=false.$parentIDs = $finder->findParentIDs('template=product, limit=100');findTemplateIDs($selectors, $options)
pageID => templateID pairs. (3.0.152+$pairs = $finder->findTemplateIDs('parent=/blog/');
// [ 1234 => 50, 1235 => 51, ... ]count($selectors, $options)
COUNT(*) by default rather than SQL_CALC_FOUND_ROWS, making it
efficient. (3.0.121+$total = $finder->count('template=blog-post');
$total = $finder->count('template=blog-post, created>today');find()
or count() call. Call them only after a find operation.Method Returns Description getTotal()intTotal matches without the limit applied. Only populated when getTotal option is enabled (default on for paginated finds).getLimit()intThe limit from the last find, or 0 if no limit was set.getStart()intThe start/offset from the last find, or 0 if none.getParentID()intParent ID when the selector contained a single parent=, otherwise 0/null.getTemplatesID()int|nullTemplate ID when the selector contained a single template=, otherwise null.getOptions()arrayFull options array (merged defaults + runtime overrides) from the last find. getSelectors()Selectors|nullFully parsed final Selectors object from the last find. (3.0.146+ getPageArrayData($pageArray)arrayData that should be populated onto a resulting PageArray. Pass a PageArray to populate it directly. $ids = $finder->findIDs('template=article, limit=10, start=20');
echo $finder->getTotal(); // e.g. 137
echo $finder->getLimit(); // 10
echo $finder->getStart(); // 20getTotalTime() (static)
find() operations during the current request. Only accumulates when the
testMode option is enabled. (3.0.257+$finder->find('template=article, limit=10', ['testMode' => true]);
echo Pagefind() and related
methods. They are merged with the defaults defined in the
$defaultOptions property and any $config->Page overrides.Inclusion and access control
Option Type Default Description findHiddenboolfalseInclude hidden pages. Also enabled by include=hidden in selector.findUnpublishedboolfalseInclude hidden and unpublished pages. Also enabled by include=unpublished.findTrashboolfalseInclude hidden, unpublished, and trashed pages. Also enabled by include=trash.findAllboolfalseInclude everything — unpublished, trash, system, no-access. Also enabled by include=all.alwaysAllowIDsarray[]Page IDs that are never excluded, regardless of inclusion/access settings. Query shape and return type
Option Type Default Description findOneboolfalseOptimize for a single result (forces limit=1, start=0).loadPagesbooltrueWhen false, skips row retrieval — useful when you only need the total.returnVerbosebooltrueWhen true, returns arrays with id, parent_id, templates_id, score. When false, returns simple array of page IDs.returnParentIDsboolfalseReturn parent IDs instead of page IDs. Requires returnVerbose=false.returnTemplateIDsboolfalseReturn [pageID => templateID] pairs. Cannot combine with other return* options. (3.0.152+returnAllColsboolfalseReturn all pages table columns indexed by page ID. Cannot combine with other return* options. (3.0.153+returnAllColsOptionsarray[]Sub-options when returnAllCols=true. See below. (3.0.172+returnQueryboolfalseWhen true, returns the unexecuted DatabaseQuerySelect object.returnAllColsOptions sub-options
returnAllColsOptions when passed to find(). When using
findVerboseIDs(), they may also be passed flat at the top level of $options —
findVerboseIDs() automatically moves them into returnAllColsOptions internally.Key Type Default Description joinFieldsarray[]Names of additional custom fields to auto-join into columns. joinSortfieldboolfalseInclude sortfield from the pages_sortfields table.joinPathboolfalseInclude path from the pages_paths table (requires PagePaths module).getNumChildrenboolfalseInclude numChildren via a sub-select count.unixTimestampsboolfalseReturn created/modified/published as Unix timestamps instead of ISO-8601.Pagination and totals
Option Type Default Description getTotalbool|nullnullnull = auto (disabled when limit=1, enabled otherwise). true = always calculate total. false = never.getTotalTypestring'calc''calc' uses SQL_CALC_FOUND_ROWS. 'count' uses a separate COUNT(*) query.ID-based cursor control
Option Type Default Description startAfterIDint0Skip all pages until this page ID is encountered, then collect the rest. The page with this ID is excluded. stopBeforeIDint0Stop collecting once this page ID is found. The page with this ID is also excluded. softLimitint0Internal: used with startAfterID/stopBeforeID combined with a limit selector.Sorting and misc
Option Type Default Description reverseSortboolfalseReverse whatever sort is specified. allowCustomboolfalseAllow _custom='selector string' embedded sub-selectors.useSortsAfterboolfalseExperimental: let Page getSortsAfter()). Not recommended for production.bindOptionsarray[]Options passed through to DatabaseQuery::bindOptions() for the primary query.testModeboolfalseEnable exact timing accumulation, accessible via Page.___-prefixed methods are
hookable. The most commonly hooked methods:Hook When Arguments Purpose PageReplace or wrap the main find operation $selectors, $optionsModify the selectors or options before the query runs, or replace the return value. PageWhen building the SQL query $selectors, $optionsModify the query-building process or the DatabaseQuerySelect output.PageWhen a selector references a field name that does not exist as a ProcessWire Field $fieldName, $dataMap unknown field names to known fields, API variables, or custom handling. Return a Field object, true (handled), 1 (API var match), or false (no match).PageWhen a selector uses path= or url=$query, $selectorModify how path/URL matching joins the query (e.g., for custom URL resolution). PageWhen building access-control WHERE clauses $query, $whereModify the SQL WHERE clause used for template access control. Example: handle unknown field names
/**
* Map 'region' to a Page reference field named 'geographic_region'
*/
$wire->addHookAfter('PageExample: adjust access-control WHERE clause
/**
* Allow access to products template for all users
*/
$wire->addHookAfter('PageException Extends When thrown PageWireExceptionDatabase errors, query execution failures. PagePageMalformed selectors: unrecognized include modes, unsupported operators, missing fields, invalid field combinations, etc. try {
$ids = $finder->findIDs('some-invalid@selector');
} catch(PagesyntaxError($message) method is the public entry point that
throws Page. You can call it from hooks.new Page or $pages->getPage
to get the instance used internally by Pages.$config->Page You can
permanently override any default option by setting $config->Page
to an array in site/config.php. These overrides are merged before
per-call options, so per-call options still win.// site/config.php — always run in testMode to accumulate timing data
$config->Pagefind() call modifies
the selectors to add a status < statusHidden condition by default.
Use include=hidden, include=unpublished, include=trash,
include=all in the selector, or the corresponding findHidden,
findUnpublished, findTrash, findAll options to relax the
restriction.check_access=0 in
the selector (must be separate from OR conditions) or findAll=true.$pages->find() instead.[...] and OR groups (...) by recursively executing
sub-queries to resolve page IDs, then injecting them into the main
query. See Selectors for syntax details.getMatchQuery() method,
passing a Page (an abstract subclass of
DatabaseQuerySelect) that carries the originating Field, Selector,
and Pagewire/core/Page
(also Exceptions.php and Page in the
same directory)API reference: methods, properties, hooks
Page class also inherits all the methods and properties of: Wire.Common
Properties
Name Return Summary Page bool Page string Additional methods and properties
API reference based on ProcessWire core version 3.0.269