Pages / $pages

The $pages API variable loads, creates, saves and deletes Page objects to and from the database. It is the most frequently used API variable in ProcessWire

This document covers the most commonly used methods of $pages but it does not cover them all. See /wire/core/Pages/Pages.php and in /wire/core/Pages/*.php phpdoc for full methods reference, or the online Pages API reference.

Finding pages
// Find all pages matching a selector — returns PageArray
$items = $pages->find("template=blog-post, sort=-created, limit=10");

// Find one page — applies same access/status filtering as find()
$p = $pages->findOne("template=blog-post, sort=random");

// Get a page with no access/status exclusions
$p = $pages->get(1234);           // by ID
$p = $pages->get('/about/');      // by path
$p = $pages->get('name=contact'); // by selector

// Returns NullPage (id=0) when nothing found — always check before use
if($p->id) { /* found */ }

// Count matching pages without loading them
$n = $pages->count("template=blog-post, date>=2024-01-01");

// Check existence with no access/status exclusions
// Returns first matching page ID or 0 if not found
$id = $pages->has("template=blog-post, name=foo");

// Iterate any number of pages without running out of memory
foreach($pages->findMany("template=product") as $p) {
    // pages are loaded/unloaded in chunks as you iterate
}

Selectors

Selector format: field=value — combine multiple with commas for AND match:

$pages->find("template=blog-post, date>=2024-01-01, title~=processwire");

Use pipe | on field for OR-field matches or value for OR-value matches:

// match word "processwire" in title, summary or body
$pages->find("title|summary|body~=processwire");

// match word "process" or "wire" or "processwire" in title
$pages->find("title~=process|wire|processwire"); 

Most common operators: =, !=, <, <=, >, >=, ~= (contains word) %= (contains using LIKE), *= (contains using index), ^= (starts), $= (ends). See Selector Operators for a full list.

Include modes:

$pages->find("template=blog-post, include=hidden");      // include hidden
$pages->find("template=blog-post, include=unpublished"); // include unpublished + hidden
$pages->find("template=blog-post, include=all");         // include all + bypass access control

find() modifiers in selector

Common selector modifiers for find(), findOne(), get(), and related methods:

OptionDefaultDescription
include=statusStatus may be hidden, unpublished, or all — include non-visible pages
limit=n0Max pages to return or 0 for no limit (also enables $items->getTotal() count)
start=n0Pagination offset/start value
sort=nameField name to sort by, prefix name with - to reverse
join=fieldsFields should be pipe-separated list of field names to autojoin (where supported)

Specialized find methods

// Returns IDs only (faster when you don't need Page objects)
$ids = $pages->findIDs("template=product");

// Verbose: returns array of ['id', 'parent_id', 'templates_id'] per match
$ids = $pages->findIDs("template=product", true);

// Specify which fields to autojoin (overriding field autojoin settings)
$posts = $pages->findJoin("template=blog-post", ['title', 'date', 'summary']);

// No autojoin at all
$posts = $pages->findJoin("template=blog-post", false);

// Raw DB values — no Page objects, no output formatting
$a = $pages->findRaw("template=blog-post", ['title', 'date']);
$a = $pages->getRaw(1234, ['title', 'summary']);

// Get a non-cached copy of a page (fresh from DB, skips memory cache)
$copy = $pages->getFresh($page);
Creating pages
// Quick method — template, parent, optional name/title/values
$p = $pages->add('blog-post', '/blog/', 'My First Post');

// With field values
$p = $pages->add('blog-post', '/blog/', [
    'title' => 'My First Post',
    'body'  => 'Hello world.',
]);

// Selector-style interface — saves to DB immediately
$p = $pages->new("template=blog-post, parent=/blog/, title=My First Post");
$p = $pages->new('/blog/my-first-post'); // path implies parent+name+template (if family allows)
$p = $pages->new([
    'template' => 'blog-post',
    'parent'   => '/blog/',
    'title'    => 'My First Post',
]);

// Create a Page object without saving to DB
$p = $pages->newPage(['template' => 'blog-post', 'parent' => '/blog/']);

$pages->new() auto-detects template from parent family settings (and vice versa), derives name from title or path, and appends a numeric suffix if the name is already taken.

Saving pages
$p = $pages->get(1234);
$p->of(false);               // turn off output formatting before editing
$p->title = 'Updated title';
$pages->save($p);            // or: $p->save()

// Save only specific fields (faster)
$pages->saveField($p, 'title');
$pages->saveFields($p, ['title', 'body', 'summary']); // 3.0.242+
$pages->saveFields($p, 'title, body, summary');        // CSV string also ok

// Clone a page (recursive by default — also clones children and file assets)
$copy = $pages->clone($p);
$copy = $pages->clone($p, $newParent, false); // non-recursive

// Update modification time to now
$pages->touch($p);

// Set sort order
$pages->sort($p, 3); // move to position 3 among siblings
$pages->insertBefore($p, $beforePage);
$pages->insertAfter($p, $afterPage);

save() options

OptionDefaultDescription
uncacheAlltrueClear memory cache after save
resetTrackChangestrueReset page's change tracking
quietfalseSkip updating modified date/user
adjustNametrueAuto-adjust name to be unique within parent
ignoreFamilyfalseBypass family/parent restriction checks
noHooksfalseSkip before/after save hooks
noFieldsfalseSave only native page properties, not fields
Deleting and trashing pages
// Move to trash (recoverable)
$pages->trash($p);

// Restore from trash to original location
$pages->restore($p);

// Empty the entire trash (permanent)
$pages->emptyTrash();

// Permanently delete (non-recoverable)
$pages->delete($p);
$pages->delete($p, true); // recursive — also deletes children
Cache

ProcessWire maintains an in-memory cache of loaded pages keyed by ID. This cache is consulted before hitting the database on any get()/find() call.

// Remove specific pages from the memory cache
$pages->uncache($p);
$pages->uncache($pageArray);
$pages->uncache([1234, 1235, 1236]); // array of IDs 3.0.259+

// Clear entire memory cache — useful when processing large sets
$pages->uncacheAll();

uncacheAll() is typically used inside pagination loops that process thousands of pages, so that previous chunks can be freed:

$start = 0;
$limit = 200;
do {
    $chunk = $pages->find("template=product, start=$start, limit=$limit");
    if(!$chunk->count()) break;
    foreach($chunk as $p) { /* process */ }
    unset($chunk);
    $pages->uncacheAll();
    $start += $limit;
} while(true);
Creating page/array instances
$p    = $pages->newPage();                      // new unsaved Page (no template)
$p    = $pages->newPage(['template' => 'foo']); // with template/parent pre-set
$pa   = $pages->newPageArray();                 // empty PageArray
$null = $pages->newNullPage();                  // shared NullPage instance
Hooks

Useful hooks on $pages:

HookWhen fired
Pages::foundAfter find completes, receives the full PageArray
Pages::saveReadyJust before a page is saved
Pages::savedAfter a page is successfully saved
Pages::savePageOrFieldReadyBefore a page or a field is saved
Pages::savedPageOrFieldAfter a page or a field is saved
Pages::addReadyBefore a new page is added
Pages::addedAfter a new page is added
Pages::deleteReadyBefore a page is deleted
Pages::deletedAfter a page is deleted
Pages::trashReadyBefore a page is trashed
Pages::trashedAfter a page is trashed
Pages::restoreReadyBefore a page is restored from trash
Pages::restoredAfter a page is restored from trash
Pages::cloneReadyBefore a page is cloned
Pages::clonedAfter a page is cloned

Other useful Pages hooks include: moveReady, moved, sorted, templateChanged, renameReady, renamed, publishReady, published, unpublishReady, unpublished, saveFieldReady, and savedField. In addition, all $pages write methods can also be hooked directly with addHookBefore() or addHookAfter().

// Example: update field value and status on every newly added page
$wire->addHookAfter('Pages::added', function(HookEvent $e) {
    $page = $e->arguments(0); /** @var Page $page */
    if($page->template->name === 'blog-post') {
        $page->categories->add('/categories/pending-review');
        $page->addStatus('hidden');
        $page->save();
    }
});

// $pages can also be hooked directly like this
$pages->addHookAfter('added', function(HookEvent $e) {
    // ...
}); 
Helper classes (wire/core/Pages/)

The $pages object delegates to several helper classes. These are lazy-loaded and should not be accessed directly from the public API unless they provide a method not available on $pages, or if otherwise directed.

PropertyClassPurpose
$pages->loaderPagesLoaderAll find/get/load operations
$pages->editorPagesEditorsave, add, delete, clone
$pages->cacherPagesLoaderCacheIn-memory page cache
$pages->trasherPagesTrashtrash, restore, emptyTrash
$pages->namesPagesNamesPage name generation and uniqueness
$pages->rawPagesRawfindRaw / getRaw
$pages->pathFinderPagesPathFinderPath-to-page resolution
$pages->requestPagesRequestCurrent HTTP request page resolution
$pages->parentsPagesParentsAncestor/parent tree queries
$pages->porterPagesExportImportImport/export
Notes
  • $pages->get() never excludes pages by status or access — it returns whatever matches, including hidden, unpublished, and admin pages. Use $pages->findOne() if you need access/status filtering.
  • Output formatting is on for front-end requests and off in the admin. Always call $page->of(false) before modifying and saving a page that may have been loaded in a front-end context.
  • $pages->newNullPage() returns a shared (cached) NullPage instance. Use $pages->newNullPage(true) only when you explicitly need a fresh instance.
  • All $pages write methods (save, add, delete, trash, etc.) are hookable via the triple-underscore ___methodName() pattern.
API reference: methods, hooks

Methods in this class should be accessed from $pages->request(), i.e.

$page = $pages->request()->getPage();

Click any linked item for full usage details and examples. Hookable methods are indicated with the icon. In addition to those shown below, the PagesRequest class also inherits all the methods and properties of: Wire.

Show $var?     Show args?       Only hookable?    

Common

NameReturnSummary 
$pages->request->checkScheme(Page $page)
None

If the template requires a different scheme/protocol than what is here, then redirect to it.

 
$pages->request->getClosestPage()
Page NullPage

Get closest matching page when getPage() returns an error/NullPage

$pages->request->getFile()
string

Get the requested file

 
$pages->request->getLanguageName()
string

Get request language name

 
$pages->request->getLoginPageOrUrl()
string Page null

Get login Page object or URL to redirect to for login needed to access given $page

$pages->request->getPage()
Page NullPage

Get the requested page

$pages->request->getPageForUser(Page $page, User $user)
Page NullPage

Update/get page for given user

$pages->request->getPageInfo()
array

Get array of page info (as provided by PagePathFinder)

 
$pages->request->getPageNum()
null int

Get the requested pagination number

 
$pages->request->getPageNumPrefix()
null string

Get the requested pagination number prefix

 
$pages->request->getRedirectType()
int

Get the redirect type (0, 301, 302, 307, 308)

 
$pages->request->getRedirectUrl()
string

Get the redirect URL

 
$pages->request->getRequestFile()
string

Get the requested file (alias of getFile method)

 
$pages->request->getRequestPage()
NullPage Page

Get page that was requested

 
$pages->request->getRequestPath()
string

Get request path

 
$pages->request->getResponseCode()
int

Get response http code for this request

 
$pages->request->getResponseCodeName()
string

Get response type name for this request

 
$pages->request->getResponseCodeNames()
array

Get all possible response code names indexed by http response code

 
$pages->request->getResponseError()
string

Get message about response only if response was an error, blank otherwise

 
$pages->request->getResponseMessage()
string

Get message string about response

 
$pages->request->setPage($page)
Page NullPage null

Set current request page

 
$pages->request->setRedirectPath(string $redirectPath)
None

Set the redirect path

 
$pages->request->setRedirectUrl(string $redirectUrl)
None

Set the redirect URL

 
$pages->request->setRequestPath(string $requestPath)
None

Set request path

 
$pages->request->setResponseMessage(string $message)
None

Set response message

 

Additional methods and properties

In addition to the methods and properties above, PagesRequest also inherits the methods and properties of these classes:

API reference based on ProcessWire core version 3.0.261