# ProcessWire API Documentation ProcessWire is a powerful, open-source content management system (CMS) and content management framework (CMF) built on PHP and MySQL. It provides a flexible, API-first approach to web development where everything is treated as a "Page" - content items, users, templates, and more. ProcessWire's architecture centers around a rich API that enables developers to find, manipulate, and display content through an intuitive object-oriented interface. The ProcessWire API is designed around several core concepts: Pages (content containers), Fields (data types), Templates (page structure definitions), and Selectors (query strings for finding content). The API provides global variables like `$page` (current page), `$pages` (page finder), `$input` (user input), `$sanitizer` (data sanitization), `$session` (session management), and `$config` (configuration). These API variables work together to provide a complete toolkit for building dynamic websites and applications with clean, readable code. --- ## $page - Current Page Object The `$page` API variable represents the current page being viewed and provides access to all page properties, fields, and traversal methods. Page objects store custom field data and provide methods for accessing related pages (parents, children, siblings). ```php title; // Page title echo $page->name; // URL-friendly page name echo $page->id; // Unique page ID echo $page->path; // Full path: /about/contact/ echo $page->url; // URL relative to site root echo $page->httpUrl; // Full URL with scheme and domain echo $page->template->name; // Template name echo $page->parent->title; // Parent page title echo $page->created; // Unix timestamp when created echo $page->modified; // Unix timestamp when modified // Access custom fields (defined in template) echo $page->headline; // Custom text field echo $page->body; // Custom textarea/HTML field echo $page->summary; // Custom summary field // Check page status if($page->isHidden()) echo "Page is hidden"; if($page->isUnpublished()) echo "Page is unpublished"; if($page->viewable()) echo "User can view this page"; if($page->editable()) echo "User can edit this page"; // Get/set output formatting (entity encoding) $page->of(false); // Disable output formatting for saving $page->set('title', 'New Title'); $page->save(); $page->of(true); // Re-enable output formatting // Render the page or a specific field echo $page->render(); // Render with template file echo $page->renderField('body'); // Render specific field echo $page->renderValue($value, 'field'); // Render arbitrary value ``` --- ## $pages - Page Finder and Manager The `$pages` API variable is used to find, load, create, save, and delete pages. It provides selector-based queries that return PageArray collections or single Page objects. ```php find("template=blog-post, limit=10, sort=-created"); $items = $pages->find("parent=/blog/, title%=ProcessWire"); $items = $pages->find("created>=today, template=news"); // Get a single page (no access control) $about = $pages->get("/about/"); $home = $pages->get(1); // By ID $post = $pages->get("template=blog-post"); // First match // Find one page (with access control) $article = $pages->findOne("template=article, featured=1"); // Count matching pages $count = $pages->count("template=product, price>100"); // Find pages and return only IDs (more efficient) $ids = $pages->findIDs("template=product"); // Find with raw data (no Page object instantiation) $data = $pages->findRaw("template=product", ["title", "price", "url"]); // Returns: [123 => ['title' => 'Product', 'price' => 99, 'url' => '/products/item/']] // Create and save a new page $p = new Page(); $p->template = 'blog-post'; $p->parent = $pages->get('/blog/'); $p->title = 'My New Post'; $p->body = '

Post content here

'; $pages->save($p); // Alternative: add() method $p = $pages->add('blog-post', '/blog/', 'my-new-post', [ 'title' => 'My New Post', 'body' => '

Post content

' ]); // Clone a page $clone = $pages->clone($originalPage, $newParent); // Delete/trash pages $pages->trash($p); // Move to trash $pages->restore($trashedPage); // Restore from trash $pages->delete($p); // Permanently delete $pages->delete($p, true); // Delete recursively with children // Save specific field only $pages->saveField($page, 'title'); $pages->saveFields($page, ['title', 'summary', 'body']); ``` --- ## Selectors - Query Syntax Selectors are ProcessWire's query language for finding pages. They use a simple field=value syntax with various operators for matching. ```php find("title=Home"); // Exact match $pages->find("title!=Home"); // Not equal $pages->find("title%=wire"); // Contains (case-insensitive) $pages->find("title~=wire"); // Contains all words $pages->find("title*=wire"); // Contains (case-sensitive, partial word) $pages->find("title^=Pro"); // Starts with $pages->find("title$=Wire"); // Ends with $pages->find("price>100"); // Greater than $pages->find("price>=100"); // Greater than or equal $pages->find("price<50"); // Less than $pages->find("price<=50"); // Less than or equal // Multiple conditions (AND) $pages->find("template=product, price>100, featured=1"); // OR conditions with pipe $pages->find("template=product|service"); $pages->find("parent=/about/|/services/"); // Subfield selectors $pages->find("images.count>0"); // Has images $pages->find("category.title=News"); // Related page field // Date selectors $pages->find("created>=today"); $pages->find("created>=-7 days"); $pages->find("modified>=2024-01-01"); $pages->find("publishedfind("status<" . Page::statusHidden); // Not hidden $pages->find("include=hidden"); // Include hidden pages $pages->find("include=unpublished"); // Include unpublished $pages->find("include=all"); // Include all statuses $pages->find("check_access=0"); // Skip access control // Sorting and limiting $pages->find("template=news, sort=-created, limit=10"); $pages->find("template=product, sort=price, sort=-title"); // Owner page $pages->find("has_parent=/products/"); // Under /products/ $pages->find("parent!=/trash/"); // Not in trash ``` --- ## Page Traversal Methods Page traversal methods allow navigation through the page hierarchy - accessing parents, children, siblings, and ancestors. ```php children(); // All children $children = $page->children("template=product"); // Filtered children $child = $page->child("sort=title"); // First child $count = $page->numChildren(); // Count children $hasKids = $page->hasChildren(); // Boolean check // Parents and ancestors $parent = $page->parent(); // Direct parent $parent = $page->parent("template=section"); // Closest matching parent $ancestors = $page->parents(); // All ancestors $ancestors = $page->parents("template!=home"); // Filtered ancestors $root = $page->rootParent(); // First ancestor under home $depth = $page->numParents(); // Depth from home // Find upward until match $section = $page->closest("template=section"); $matched = $page->parentsUntil("template=home"); // Siblings - pages at same level $siblings = $page->siblings(); // All siblings $siblings = $page->siblings("template=product"); // Filtered siblings $next = $page->next(); // Next sibling $prev = $page->prev(); // Previous sibling $nextAll = $page->nextAll(); // All following siblings $prevAll = $page->prevAll(); // All preceding siblings // Descendants - all pages under (recursive) $all = $page->find("template=product"); // Find in descendants $first = $page->findOne("featured=1"); // First matching descendant $count = $page->numDescendants(); // Count all descendants // References - pages linking to this page $refs = $page->references(); // Pages with Page fields pointing here $links = $page->links(); // Pages linking here in textarea fields ``` --- ## $input - User Input Handling The `$input` API variable provides access to GET, POST, and COOKIE data with built-in sanitization support. ```php get->int('id'); // Sanitize as integer $name = $input->get->text('name'); // Sanitize as single-line text $q = $input->get->selectorValue('q'); // Safe for use in selectors $page = $input->get('page', 'int', 1); // With fallback value // POST variables (from form submissions) $title = $input->post->text('title'); $body = $input->post->textarea('body'); // Multi-line text $email = $input->post->email('email'); $url = $input->post->url('website'); $ids = $input->post->intArray('selected'); // Array of integers // COOKIE variables $preference = $input->cookie->text('pref'); $remember = $input->cookie->int('remember'); // Whitelist - store validated/sanitized values $input->whitelist('id', $sanitizer->int($input->get('id'))); $id = $input->whitelist('id'); // Retrieve later // URL segments (parts of URL after page path) // URL: /products/category/electronics/ $segment1 = $input->urlSegment1; // "category" $segment2 = $input->urlSegment2; // "electronics" $segment = $input->urlSegment(1); // Same as urlSegment1 $segments = $input->urlSegments(); // Array of all segments $segmentStr = $input->urlSegmentStr(); // "category/electronics" // Pagination $pageNum = $input->pageNum(); // Current pagination number // Request information $method = $input->requestMethod(); // GET, POST, etc. $url = $input->url(); // Current request URL $httpUrl = $input->httpUrl(); // Full URL with scheme $queryString = $input->queryString(); // Query string portion // Check request type if($input->is('post')) { /* Handle POST */ } if($input->is('ajax')) { /* Handle AJAX */ } if($input->is('get')) { /* Handle GET */ } ``` --- ## $sanitizer - Data Sanitization The `$sanitizer` API variable provides methods for sanitizing and validating user input and other data. ```php text($value); // Single line, no HTML $text = $sanitizer->textarea($value); // Multi-line, no HTML $text = $sanitizer->line($value); // Single line, unlimited length $markup = $sanitizer->purify($html); // Sanitize HTML with HTMLPurifier // Encode for output $safe = $sanitizer->entities($value); // HTML entity encode $safe = $sanitizer->entities1($value); // Entity encode (no double-encode) // Convert markup to text $text = $sanitizer->markupToText($html); // Strip HTML, keep content $line = $sanitizer->markupToLine($html); // Single line, no HTML // Names and identifiers $name = $sanitizer->pageName($value); // URL-safe page name $name = $sanitizer->fieldName($value); // Valid field name $name = $sanitizer->filename($value); // Safe filename $class = $sanitizer->htmlClass($value); // HTML class attribute // Numbers $int = $sanitizer->int($value); // Integer (unsigned) $int = $sanitizer->intSigned($value); // Signed integer $float = $sanitizer->float($value); // Floating point $range = $sanitizer->range($value, 0, 100); // Clamp to range // Email and URL $email = $sanitizer->email($value); // Valid email or blank $url = $sanitizer->url($value); // Valid URL or blank $url = $sanitizer->httpUrl($value); // URL with http/https required // For use in selectors $safe = $sanitizer->selectorValue($value); // Escape for selector use // Arrays $arr = $sanitizer->array($value, 'int'); // Sanitize array elements $ids = $sanitizer->intArray($value); // Array of integers $opts = $sanitizer->options($value, $allowed); // Only allowed values // Boolean/checkbox $bool = $sanitizer->bool($value); // Convert to boolean $bit = $sanitizer->bit($value); // 0 or 1 // Date $date = $sanitizer->date($value, 'Y-m-d'); // Formatted date string $ts = $sanitizer->date($value, 'ts'); // Unix timestamp // String manipulation $str = $sanitizer->truncate($value, 100); // Truncate to length $str = $sanitizer->truncate($value, 100, ['type' => 'word']); // Word boundary $str = $sanitizer->alpha($value); // Letters only $str = $sanitizer->alphanumeric($value); // Letters and numbers $str = $sanitizer->digits($value); // Digits only // Case conversion $str = $sanitizer->camelCase($value); // camelCase $str = $sanitizer->snakeCase($value); // snake_case $str = $sanitizer->kebabCase($value); // kebab-case // Validation (returns value if valid, null if not) $valid = $sanitizer->validate($value, 'email'); if($sanitizer->valid($value, 'int')) { /* is valid */ } ``` --- ## $session - Session Management The `$session` API variable provides session handling, authentication, and notice messages. ```php set('cart', $cartData); $cart = $session->get('cart'); $session->remove('cart'); // Shorthand access $session->cart = $cartData; $cart = $session->cart; // Namespaced session data (for modules) $session->setFor('MyModule', 'setting', $value); $value = $session->getFor('MyModule', 'setting'); $session->removeFor('MyModule', 'setting'); $session->removeAllFor('MyModule'); // Get all session data $all = $session->getAll(); $moduleData = $session->getAllFor('MyModule'); // User authentication $user = $session->login('username', 'password'); if($user) { echo "Logged in as: " . $user->name; } else { echo "Login failed"; } // Force login (without password - use carefully!) $user = $session->forceLogin('username'); $user = $session->forceLogin($userPage); // Logout $session->logout(); // Redirects $session->redirect('/some/page/'); // 301 redirect $session->redirect('/some/page/', false); // 302 redirect $session->location('/some/page/'); // 302 temporary redirect // Flash messages (shown once on next page view) $session->message('Operation successful!'); $session->warning('Please check your input'); $session->error('An error occurred'); // With flags $session->message('Info', Notice::allowMarkup); $session->error('Error', Notice::log); // Also log to file // Get client IP $ip = $session->getIP(); // String IP address $ipInt = $session->getIP(true); // Integer IP // CSRF protection $token = $session->CSRF()->getToken(); // Get token for forms $session->CSRF()->validate(); // Validate on submission // In forms: // Session history (if enabled in config) $history = $session->getHistory(); ``` --- ## $cache - Caching System The `$cache` API variable provides easy persistent caching of data, markup, and PageArrays. ```php save('my-cache', $data); // Save with default expiry $data = $cache->get('my-cache'); // Retrieve // With expiration (seconds) $cache->save('hourly-data', $data, 3600); // 1 hour $cache->save('daily-data', $data, WireCache::expireDaily); $cache->save('weekly-data', $data, WireCache::expireWeekly); $cache->save('never', $data, WireCache::expireNever); // Expire when pages matching selector are saved $cache->save('products', $data, "template=product"); // Get with callback (auto-regenerate if expired) $data = $cache->get('expensive-query', 3600, function() use($pages) { // This runs only if cache doesn't exist or is expired return $pages->find("template=product, limit=1000")->explode(['title', 'url']); }); // Cache a rendered file $markup = $cache->renderFile('/site/templates/partials/sidebar.php', 3600, [ 'data' => $someData // Variables passed to template ]); // Delete cache $cache->delete('my-cache'); // Single cache $cache->delete('my-*'); // Wildcard delete $cache->deleteAll(); // Delete all caches (careful!) // Namespaced caches (for modules) $cache->saveFor('MyModule', 'data', $data, 3600); $data = $cache->getFor('MyModule', 'data'); $cache->deleteFor('MyModule', 'data'); $cache->deleteFor('MyModule'); // All for namespace // Cache info $info = $cache->getInfo(); // Array of all caches // Cache PageArrays $featured = $pages->find("featured=1, limit=10"); $cache->save('featured-pages', $featured, 3600); $featured = $cache->get('featured-pages'); // Returns PageArray ``` --- ## PageArray and WireArray PageArray is the collection type returned by `$pages->find()`. WireArray is the base class providing powerful iteration, filtering, and manipulation methods. ```php find("template=product"); foreach($items as $item) { echo "

{$item->title}

"; } // Count and check $count = $items->count(); if($items->count()) { /* has items */ } if(!$items->count()) { /* empty */ } // Get specific items $first = $items->first(); $last = $items->last(); $third = $items->eq(2); // Zero-indexed $random = $items->getRandom(); $randoms = $items->findRandom(3); // Get 3 random // Array access $item = $items[0]; // First item $item = $items['page-name']; // By name/key // Filtering (returns new PageArray, doesn't modify original) $filtered = $items->find("price>100"); $filtered = $items->filter("featured=1"); $filtered = $items->not("status>=hidden"); // Sorting $sorted = $items->sort("price"); // Ascending $sorted = $items->sort("-price"); // Descending $sorted = $items->sort("price, -title"); // Multiple fields $items->shuffle(); // Randomize in place // Manipulation (modifies original) $items->add($page); // Add item $items->prepend($page); // Add to beginning $items->append($page); // Add to end $items->remove($page); // Remove item $items->removeItems($pagesToRemove); // Remove multiple $items->removeAll(); // Clear all // Insert relative to other items $items->insertBefore($newItem, $existingItem); $items->insertAfter($newItem, $existingItem); // Slicing $slice = $items->slice(0, 5); // First 5 $slice = $items->slice(5); // From 6th onward // Convert to arrays $ids = $items->explode('id'); // Array of IDs $titles = $items->explode('title'); // Array of titles $data = $items->explode(['id', 'title', 'url']); // Array of arrays $keys = $items->getKeys(); // Array of keys $values = $items->getValues(); // Array of values // Combine into string $csv = $items->implode(',', 'id'); // "1,2,3,4" $list = $items->implode('|', 'title'); // "Title 1|Title 2|..." // Each/map operations $items->each(function($item) { echo $item->title; }); $result = $items->each('title'); // Shorthand for property $urls = $items->each('url'); // Get all URLs // Unique and reverse $unique = $items->unique(); $reversed = $items->reverse(); // Check for item if($items->has($page)) { /* contains page */ } if($items->has("id=123")) { /* has matching */ } // Combining PageArrays $combined = $items->and($moreItems); // Returns new combined array $items->import($moreItems); // Import into existing ``` --- ## Images and Files ProcessWire provides powerful image manipulation and file handling through Pagefiles and Pageimages. ```php images; // All images $image = $page->images->first(); // First image $image = $page->images->last(); // Last image $image = $page->images->getRandom(); // Random image $image = $page->images->get('filename.jpg'); // By filename // Image properties echo $image->url; // Web URL echo $image->filename; // Server path echo $image->description; // Description text echo $image->tags; // Tags string echo $image->width; // Original width echo $image->height; // Original height echo $image->filesize; // Bytes echo $image->filesizeStr; // "245 KB" // Image resizing (creates variation) $thumb = $image->size(200, 200); // Exact size (crops) $thumb = $image->width(400); // Proportional by width $thumb = $image->height(300); // Proportional by height $thumb = $image->maxWidth(800); // Max width constraint $thumb = $image->maxHeight(600); // Max height constraint $thumb = $image->maxSize(800, 600); // Max both dimensions // Size with options $thumb = $image->size(400, 300, [ 'cropping' => 'center', // center, north, south, east, west 'quality' => 90, // JPEG quality 1-100 'sharpening' => 'medium', // none, soft, medium, strong 'upscaling' => false, // Don't upscale small images 'suffix' => 'thumb' // Custom suffix ]); // Focus point for cropping $image->focus(50, 30); // Set focus at 50% x, 30% y $thumb = $image->size(400, 300); // Crop will focus there $focus = $image->focus(); // Get current: ['top' => 30, 'left' => 50] // WebP format $webp = $image->webp(); // Get WebP version echo $webp->url; // Custom crop $crop = $image->crop(100, 100, 400, 300); // x, y, width, height // Image variations $variations = $image->getVariations(); // All size variations $image->removeVariations(); // Delete all variations // Render image tag echo $image->render(); // ... echo $image->render("{description}"); // Files (non-image) $files = $page->files; // Pagefiles array $file = $page->files->first(); echo $file->url; // Download URL echo $file->filename; // Server path echo $file->basename; // Filename only echo $file->ext; // Extension echo $file->description; echo $file->filesize; // Add files programmatically $page->of(false); $page->images->add('/path/to/image.jpg'); $page->images->add('https://example.com/photo.jpg'); $page->files->add('/path/to/document.pdf'); $page->save(); // Delete files $page->images->delete($image); $page->images->deleteAll(); // Finding by tags $tagged = $page->images->findTag('gallery'); $featured = $page->images->getTag('featured'); ``` --- ## Templates and Fields Templates define page structure and connect pages to fields. Fields define data types and storage. ```php get('blog-post'); $template = $templates->get(45); // By ID // Template properties echo $template->name; echo $template->label; echo $template->filename; // Template file path echo $template->filenameExists(); // Boolean // Check template fields if($template->hasField('body')) { } $fieldgroup = $template->fieldgroup; // All fields in template // Get pages using template $count = $template->getNumPages(); // Get fields $field = $fields->get('body'); $field = $fields->get(52); // By ID // Field properties echo $field->name; echo $field->label; echo $field->type; // Fieldtype module name echo $field->getTable(); // Database table name // Field settings echo $field->maxlength; // Text field max length echo $field->rows; // Textarea rows echo $field->inputfieldClass; // Input type // Find fields by type $textFields = $fields->find("type=FieldtypeText"); $imageFields = $fields->find("type=FieldtypeImage"); // Check which templates use a field $usingTemplates = $field->getTemplates(); $count = $field->getTemplates(true); // Count only // Create new template programmatically $t = new Template(); $t->name = 'my-template'; $t->label = 'My Template'; $t->fieldgroup = $fieldgroups->get('my-fieldgroup'); $t->save(); // Create new field programmatically $f = new Field(); $f->type = $modules->get('FieldtypeText'); $f->name = 'subtitle'; $f->label = 'Subtitle'; $f->maxlength = 255; $f->save(); // Add field to template $template->fieldgroup->add($field); $template->fieldgroup->save(); ``` --- ## $modules - Module Management The `$modules` API variable provides access to all installed ProcessWire modules. ```php get('MarkupPagerNav'); $purifier = $modules->get('MarkupHTMLPurifier'); // Alternative syntax $module = $modules->MarkupPagerNav; // Check if module is installed if($modules->isInstalled('ModuleName')) { } // Get module info $info = $modules->getModuleInfo('ModuleName'); echo $info['title']; echo $info['version']; echo $info['summary']; // Get module configuration $config = $modules->getConfig('ModuleName'); $value = $modules->getConfig('ModuleName', 'settingName'); // Save module configuration $modules->saveConfig('ModuleName', ['setting' => 'value']); // Find modules by prefix $inputfields = $modules->findByPrefix('Inputfield'); $fieldtypes = $modules->findByPrefix('Fieldtype'); // Find by info properties $autoload = $modules->findByInfo('autoload=true'); // Install/uninstall (admin operations) $modules->install('ModuleName'); $modules->uninstall('ModuleName'); $modules->refresh(); // Refresh module cache // Common modules usage // MarkupPagerNav - Pagination $results = $pages->find("template=product, limit=10"); echo $results->renderPager(); // Uses MarkupPagerNav // MarkupHTMLPurifier - Sanitize HTML $purifier = $modules->get('MarkupHTMLPurifier'); $clean = $purifier->purify($dirtyHtml); ``` --- ## WireHttp - HTTP Requests WireHttp enables sending HTTP requests, downloading files, and interacting with external APIs. ```php get('https://api.example.com/data'); if($response !== false) { $data = json_decode($response, true); } else { $error = $http->getError(); } // GET with query parameters $response = $http->get('https://api.example.com/search', [ 'q' => 'search term', 'limit' => 10 ]); // POST request $response = $http->post('https://api.example.com/submit', [ 'name' => 'John', 'email' => 'john@example.com' ]); // POST JSON data $http->setHeader('Content-Type', 'application/json'); $response = $http->post('https://api.example.com/data', json_encode($data)); // Custom headers $http->setHeaders([ 'Authorization' => 'Bearer ' . $apiKey, 'Accept' => 'application/json' ]); $response = $http->get($url); // Set timeout $http->setTimeout(30); // 30 seconds // Other HTTP methods $http->put($url, $data); $http->patch($url, $data); $http->delete($url); // HEAD request (get headers only) $headers = $http->head($url); // Get status code $status = $http->status($url); // Returns int like 200 $statusText = $http->statusText($url); // Returns "200 OK" // Response headers $headers = $http->getResponseHeaders(); $contentType = $http->getResponseHeader('content-type'); // Download file $localFile = $http->download( 'https://example.com/file.zip', '/path/to/save/file.zip' ); // Check for errors $code = $http->getHttpCode(); if($code >= 400) { $error = $http->getError(); } ``` --- ## WireMail - Email Sending WireMail provides email sending capabilities with support for HTML, attachments, and more. ```php new(); // Or: $mail = wireMail(); // Basic email $mail->to('recipient@example.com') ->from('sender@example.com') ->subject('Hello World') ->body('Plain text message body') ->send(); // With names $mail->to('recipient@example.com', 'John Doe') ->from('sender@example.com', 'My Company') ->replyTo('support@example.com', 'Support Team') ->subject('Important Message') ->body('Plain text version') ->bodyHTML('

HTML Version

') ->send(); // Multiple recipients $mail->to([ 'user1@example.com', 'user2@example.com', 'user3@example.com' ]); // Attachments $mail->attachment('/path/to/document.pdf'); $mail->attachment('/path/to/image.jpg'); // Custom headers $mail->header('X-Priority', '1'); $mail->header('X-Mailer', 'ProcessWire'); // Check send result $numSent = $mail->send(); if($numSent) { echo "Email sent successfully"; } else { echo "Failed to send email"; } // Using wireMail() function directly $sent = wireMail() ->to('recipient@example.com') ->from('sender@example.com') ->subject('Quick Email') ->body('Message content') ->send(); // Send to page's email field $mail->to($page->email) ->subject("Contact from website") ->body($message) ->send(); ``` --- ## Hooks - Extending ProcessWire Hooks allow you to modify or extend ProcessWire's core behavior without modifying core files. ```php addHookBefore('Pages::save', function(HookEvent $event) { $page = $event->arguments(0); // Get first argument if($page->template->name === 'blog-post') { $page->modified_by_hook = true; } }); // Hook AFTER a method (modify return value) $wire->addHookAfter('Pages::saved', function(HookEvent $event) { $page = $event->arguments(0); if($page->template->name === 'blog-post') { // Send notification, update cache, etc. $event->message("Blog post saved: {$page->title}"); } }); // Hook to replace method entirely $wire->addHookBefore('Page::render', function(HookEvent $event) { $page = $event->object; if($page->template->name === 'api-endpoint') { header('Content-Type: application/json'); echo json_encode(['id' => $page->id, 'title' => $page->title]); $event->replace = true; // Don't run original method } }); // Hook with priority (lower runs first) $wire->addHookAfter('Pages::save', function($e) { }, ['priority' => 50]); // Hook property access $wire->addHookProperty('Page::fullUrl', function(HookEvent $event) { $page = $event->object; $event->return = $page->httpUrl . '?v=' . time(); }); // Add custom method to class $wire->addHook('Page::sendEmail', function(HookEvent $event) { $page = $event->object; $to = $event->arguments(0); wireMail()->to($to)->subject($page->title)->body($page->summary)->send(); }); // Usage: $page->sendEmail('user@example.com'); // Common hook points // Pages::saveReady - Before page save // Pages::saved - After page save // Pages::deleteReady - Before delete // Pages::deleted - After delete // Pages::trashed - After trash // Page::render - When page renders // Session::loginSuccess - After login // Session::logoutSuccess - After logout // Hooks in /site/ready.php (runs after API ready) // Hooks in /site/init.php (runs during bootstrap) // Hooks in module's init() or ready() method ``` --- ## Configuration and Paths The `$config` API variable provides access to site configuration and path information. ```php paths->root; // /var/www/site/ echo $config->paths->site; // /var/www/site/site/ echo $config->paths->templates; // /var/www/site/site/templates/ echo $config->paths->modules; // /var/www/site/wire/modules/ echo $config->paths->siteModules; // /var/www/site/site/modules/ echo $config->paths->assets; // /var/www/site/site/assets/ echo $config->paths->files; // /var/www/site/site/assets/files/ echo $config->paths->logs; // /var/www/site/site/assets/logs/ echo $config->paths->cache; // /var/www/site/site/assets/cache/ // Common URLs echo $config->urls->root; // / echo $config->urls->templates; // /site/templates/ echo $config->urls->admin; // /processwire/ echo $config->urls->files; // /site/assets/files/ // Environment echo $config->httpHost; // example.com echo $config->https; // true/false echo $config->ajax; // true if AJAX request echo $config->modal; // true if in modal echo $config->debug; // Debug mode on/off // Database echo $config->dbName; echo $config->dbHost; echo $config->dbUser; // System IDs echo $config->adminRootPageID; // Admin page ID echo $config->trashPageID; // Trash page ID echo $config->http404PageID; // 404 page ID echo $config->usersPageID; // Users parent ID echo $config->rolesPageID; // Roles parent ID echo $config->permissionsPageID; // Permissions parent ID // Pagination echo $config->pageNumUrlPrefix; // "page" // Custom config values (from /site/config.php) echo $config->myCustomSetting; // File tools $files->mkdir($path); // Create directory $files->rmdir($path); // Remove directory $files->copy($from, $to); // Copy file $files->rename($old, $new); // Rename file $files->unlink($file); // Delete file $files->fileGetContents($url); // Get URL/file contents ``` --- ## Translation Functions ProcessWire provides built-in translation functions for multi-language sites. ```php title; // Current language title echo $page->getLanguageValue('de', 'title'); // German title echo $page->localUrl('de'); // URL in German // Set language $user->language = $languages->get('de'); // Check current language if($user->language->isDefault()) { // Default language } // Get all languages foreach($languages as $language) { echo $language->title; echo $page->localUrl($language); } // Language-aware page names echo $page->localName(); // Name in current language echo $page->localPath(); // Path in current language echo $page->localHttpUrl(); // Full URL in current language ``` --- ProcessWire's API is designed for building content-driven websites and applications with a focus on flexibility and developer experience. The core pattern involves using `$pages->find()` to retrieve content based on selector queries, then iterating through the resulting PageArray to output content. Templates connect pages to their fields and determine how they render, while the extensive hook system allows modification of nearly any aspect of the system's behavior. Common integration patterns include: using `$input` and `$sanitizer` for secure form handling, `$cache` for performance optimization, `$session` for user authentication flows, WireHttp for consuming external APIs, and hooks for extending functionality. The API's consistent object-oriented design means similar patterns work across pages, files, images, users, and other data types, making it straightforward to build complex applications while maintaining clean, readable code.