Try Live
Add Docs
Rankings
Pricing
Docs
Install
Install
Docs
Pricing
More...
More...
Try Live
Rankings
Enterprise
Create API Key
Add Docs
ProcessWire
https://github.com/processwire/processwire
Admin
ProcessWire is a friendly and powerful open source CMS and CMF with an API that is a joy to use at
...
Tokens:
80,233
Snippets:
629
Trust Score:
7
Update:
2 months ago
Context
Skills
Chat
Benchmark
62.8
Suggestions
Latest
Show doc for...
Code
Info
Show Results
Context Summary (auto-generated)
Raw
Copy
Link
# ProcessWire CMS/CMF ProcessWire is a powerful open-source content management system (CMS) and content management framework (CMF) built on PHP. It provides a flexible, jQuery-like API for working with content where everything is treated as a Page object with custom fields. The system uses selectors (similar to CSS selectors) to find and filter content, making database queries intuitive and readable. ProcessWire's architecture centers around Pages, Templates, and Fields. Pages represent content stored in the database, Templates define the structure and behavior of pages (including which fields they contain), and Fields are custom data types attached to templates. The API provides access through global variables like `$pages`, `$page`, `$config`, `$input`, `$sanitizer`, `$session`, `$user`, `$cache`, `$files`, and `$modules`, enabling developers to build sophisticated web applications while maintaining clean, readable code. --- ## Pages API ($pages) The `$pages` API variable is the most commonly used object in ProcessWire, providing methods to find, load, save, and delete Page objects from the database. It uses a selector-based syntax similar to CSS/jQuery for querying content. ```php <?php namespace ProcessWire; // Find all pages with a specific template $articles = $pages->find("template=blog-post, limit=10, sort=-created"); foreach($articles as $article) { echo "<h2>{$article->title}</h2>"; echo "<p>{$article->summary}</p>"; } // Find pages with complex selectors $products = $pages->find("template=product, price>=100, price<=500, categories.name=electronics"); // Get a single page by path, ID, or selector $about = $pages->get("/about/"); $page123 = $pages->get(123); $featured = $pages->get("template=article, featured=1"); // Count pages matching a selector (without loading them) $numPosts = $pages->count("template=blog-post, published>today"); // Create and save a new page $newPage = new Page(); $newPage->template = 'blog-post'; $newPage->parent = $pages->get('/blog/'); $newPage->title = 'My New Post'; $newPage->body = 'This is the content...'; $pages->save($newPage); // Add a page using shorthand method $page = $pages->add('basic-page', '/about/', 'team', [ 'title' => 'Our Team', 'body' => 'Meet our amazing team members.' ]); // Clone a page (with children) $copy = $pages->clone($originalPage, $newParent, true); // Move a page to trash $pages->trash($page); // Restore from trash $pages->restore($page); // Permanently delete $pages->delete($page, true); // true = recursive // Find pages for iteration without memory limits $allPages = $pages->findMany("template=product"); foreach($allPages as $p) { // Process each page - memory efficient for large result sets } ``` --- ## Page Object ($page) The `$page` API variable represents the current page being viewed, but Page objects are used throughout ProcessWire. They provide access to custom fields, traversal methods for navigating page hierarchy, and status/permission checking. ```php <?php namespace ProcessWire; // Access page properties and custom fields echo $page->id; // Numeric page ID echo $page->name; // URL-safe page name echo $page->title; // Page title (custom field) echo $page->path; // Full path from root: /about/team/ echo $page->url; // URL from document root echo $page->httpUrl; // Full URL with scheme and host echo $page->template; // Template object echo $page->parent; // Parent page object echo $page->created; // Unix timestamp of creation echo $page->modified; // Unix timestamp of last modification echo $page->createdUser; // User who created the page echo $page->modifiedUser; // User who last modified // Page traversal - navigate the page hierarchy $parent = $page->parent; $grandparent = $page->parent->parent; $parents = $page->parents; // PageArray of all ancestors $rootParent = $page->rootParent; // Top-level parent (section) $children = $page->children; // Direct children $children = $page->children("template=article, sort=title"); $firstChild = $page->child; $siblings = $page->siblings; $next = $page->next; $prev = $page->prev; // Check if page has children if($page->hasChildren) { echo "This page has {$page->numChildren} children"; } // Find descendants (children, grandchildren, etc.) $descendants = $page->find("template=product"); // Permission checking if($page->viewable()) { /* user can view */ } if($page->editable()) { /* user can edit */ } if($page->editable('body')) { /* user can edit body field */ } if($page->publishable()) { /* user can publish */ } if($page->deleteable()) { /* user can delete */ } if($page->addable()) { /* user can add children */ } // Page status if($page->isHidden()) { /* page is hidden */ } if($page->isUnpublished()) { /* page is unpublished */ } if($page->isTrash()) { /* page is in trash */ } // Modify page status $page->addStatus(Page::statusHidden); $page->removeStatus(Page::statusHidden); // Save changes to a page $page->title = "New Title"; $page->body = "Updated content"; $page->save(); // Save only a specific field $page->save('title'); // Output formatting (for display vs manipulation) $page->of(true); // Enable output formatting $page->of(false); // Disable for manipulation // Get page references (pages linking to this one) $references = $page->references(); $links = $page->links(); // Pages linking in textarea/HTML fields ``` --- ## Selectors Selectors are ProcessWire's powerful query language for finding pages. They use a CSS-like syntax with field=value pairs that can be combined with operators and subfield access. ```php <?php namespace ProcessWire; // Basic selectors $pages->find("template=blog-post"); $pages->find("parent=/blog/"); $pages->find("id=123"); $pages->find("name=about-us"); // Comparison operators $pages->find("price>100"); // Greater than $pages->find("price>=100"); // Greater than or equal $pages->find("price<500"); // Less than $pages->find("price<=500"); // Less than or equal $pages->find("price!=0"); // Not equal $pages->find("title%=wire"); // Contains word "wire" $pages->find("title~=process wire"); // Contains all words $pages->find("title*=wire"); // Contains substring $pages->find("title^=Hello"); // Starts with $pages->find("title$=World"); // Ends with // Multiple conditions (AND logic) $pages->find("template=product, price>100, stock>0"); // OR logic with pipe $pages->find("template=article|blog-post"); $pages->find("categories=electronics|computers"); // Subfield access $pages->find("parent.template=blog"); $pages->find("author.name=Ryan"); $pages->find("categories.title=Technology"); // Sorting and limiting $pages->find("template=article, sort=title"); $pages->find("template=article, sort=-created"); // Descending $pages->find("template=article, sort=random"); $pages->find("template=article, limit=10"); $pages->find("template=article, limit=10, start=20"); // Pagination // Date comparisons $pages->find("created>today"); $pages->find("created>=2024-01-01"); $pages->find("modified<-1 week"); $pages->find("published>=-30 days"); // Include hidden/unpublished pages $pages->find("template=article, include=hidden"); $pages->find("template=article, include=unpublished"); $pages->find("template=article, include=all"); // Check access permissions $pages->find("template=article, check_access=1"); // Has parent / has children $pages->find("has_parent=/products/"); $pages->find("hasChildren=1"); $pages->find("numChildren>5"); // Negation $pages->find("template!=admin"); $pages->find("parent!=/trash/"); // Empty/non-empty fields $pages->find("body!=''"); // Has body content $pages->find("image.count>0"); // Has images ``` --- ## Input API ($input) The `$input` API variable provides access to GET, POST, and COOKIE variables with built-in sanitization options. It also provides URL segment access and request information. ```php <?php namespace ProcessWire; // GET variables (?id=123&name=test) $id = $input->get('id'); // Raw value $id = $input->get->int('id'); // Sanitized as integer $name = $input->get->text('name'); // Sanitized as text $q = $input->get('q', 'text'); // Alternative syntax (3.0.125+) $q = $input->get('q', 'text', 'default'); // With fallback value // POST variables $email = $input->post('email'); $email = $input->post->email('email'); // Sanitized as email $message = $input->post->textarea('message'); // Multiline text $items = $input->post('items[]'); // Array values // Validate against whitelist $color = $input->post('color', ['red', 'blue', 'green']); $size = $input->get('size', ['S', 'M', 'L', 'XL'], 'M'); // With default // COOKIE variables $preference = $input->cookie('user_preference'); $input->cookie->set('theme', 'dark', 86400); // Set cookie for 24 hours // URL segments (requires template setting: /page/url/segment1/segment2/) $segment1 = $input->urlSegment1; $segment2 = $input->urlSegment2; $allSegments = $input->urlSegments; // Array $segmentStr = $input->urlSegmentStr; // String: segment1/segment2 // Check specific URL segment value if($input->urlSegment1 === 'edit') { // Handle edit mode } // Page number for pagination $pageNum = $input->pageNum; // 1, 2, 3... // Request information $url = $input->url; // Current URL path $httpUrl = $input->httpUrl; // Full URL with scheme $queryString = $input->queryString; $scheme = $input->scheme; // http or https // Request method checking if($input->requestMethod('POST')) { // Handle POST request } if($input->requestMethod('GET')) { // Handle GET request } // Whitelist for secure variable passing between requests $input->whitelist('searchQuery', $sanitizer->text($input->get('q'))); $query = $input->whitelist('searchQuery'); // Retrieve later ``` --- ## Sanitizer API ($sanitizer) The `$sanitizer` API variable provides methods for sanitizing and validating user input. It ensures data matches expected formats before storage or output. ```php <?php namespace ProcessWire; // Text sanitization $clean = $sanitizer->text($dirty); // Single line text $clean = $sanitizer->textarea($dirty); // Multiline text $clean = $sanitizer->purify($dirty); // HTML with HTMLPurifier $clean = $sanitizer->entities($dirty); // HTML entities for output $clean = $sanitizer->unentities($dirty); // Decode HTML entities // String sanitization $clean = $sanitizer->name($dirty); // Page/field name format $clean = $sanitizer->pageName($dirty); // URL-safe page name $clean = $sanitizer->filename($dirty); // Safe filename $clean = $sanitizer->path($dirty); // File system path $clean = $sanitizer->url($dirty); // URL $clean = $sanitizer->selectorValue($dirty); // Safe for use in selectors // Number sanitization $clean = $sanitizer->int($dirty); // Integer $clean = $sanitizer->intUnsigned($dirty); // Positive integer $clean = $sanitizer->float($dirty); // Float/decimal $clean = $sanitizer->digits($dirty); // Only digits (string) $clean = $sanitizer->digits($dirty, 5); // Max 5 digits // Email and communication $clean = $sanitizer->email($dirty); // Email address $clean = $sanitizer->emailHeader($dirty); // Safe for email headers // Arrays $clean = $sanitizer->array($dirty); // Force to array $clean = $sanitizer->intArray($dirty); // Array of integers $clean = $sanitizer->options($dirty, ['a', 'b', 'c']); // Whitelist // Date and time $clean = $sanitizer->date($dirty); // Date string $clean = $sanitizer->date($dirty, 'Y-m-d'); // With format // Truncation $excerpt = $sanitizer->truncate($text, 100); // 100 chars $excerpt = $sanitizer->truncate($text, ['maxLength' => 200, 'ellipsis' => '...']); // Remove specific characters $clean = $sanitizer->removeWhitespace($dirty); $clean = $sanitizer->removeNewlines($dirty); // Alphanumeric only $clean = $sanitizer->alpha($dirty); // Letters only $clean = $sanitizer->alphanumeric($dirty); // Letters and numbers // Chained sanitizers (3.0.125+) $clean = $sanitizer->text_entities($dirty); // text then entities $clean = $sanitizer->textarea_purify($dirty); // Validation (returns null if invalid) $email = $sanitizer->validate($dirty, 'email'); if($email === null) { // Invalid email } // Custom hook sanitizer (in /site/ready.php) $sanitizer->addHook('zipcode', function($event) { $value = $event->arguments(0); $value = $event->object->digits($value, 5); $event->return = strlen($value) === 5 ? $value : ''; }); $zip = $sanitizer->zipcode($input->post('zip')); ``` --- ## Session API ($session) The `$session` API variable manages user sessions, authentication, flash messages, redirects, and CSRF protection. ```php <?php namespace ProcessWire; // Set and get session variables $session->set('cart', ['item1', 'item2']); $cart = $session->get('cart'); $session->remove('cart'); // Alternative property syntax $session->myVariable = 'value'; $value = $session->myVariable; // Check if session variable exists if($session->get('user_preference')) { // Variable exists } // User authentication $user = $session->login('username', 'password'); if($user) { echo "Welcome, {$user->name}!"; } else { echo "Login failed"; } // Logout current user $session->logout(); // Force login (skip password check - use carefully) $session->forceLogin($user); // Check if user is logged in if($user->isLoggedin()) { echo "You are logged in"; } // Redirects $session->redirect('/thank-you/'); $session->redirect($pages->get('/contact/')->url); $session->redirect('https://example.com/', false); // 302 redirect // Flash messages (notices shown on next request) $session->message('Your changes have been saved.'); $session->warning('Please check your input.'); $session->error('Something went wrong.'); // CSRF protection $token = $session->CSRF->getTokenName(); $value = $session->CSRF->getTokenValue(); // In form template: // <input type="hidden" name="<?=$session->CSRF->getTokenName()?>" value="<?=$session->CSRF->getTokenValue()?>"> // Validate CSRF token on form submission if($input->post('submit')) { if(!$session->CSRF->validate()) { throw new WireException('CSRF validation failed'); } // Process form... } // Get/set IP address (for logging, etc.) $ip = $session->getIP(); // Get browser/user agent $browser = $session->get('browser'); ``` --- ## Cache API ($cache) The `$cache` API variable provides persistent caching of strings, arrays, or PageArrays with automatic expiration. ```php <?php namespace ProcessWire; // Basic cache with callback (most common pattern) $data = $cache->get('my-cache-key', 3600, function() { // This runs only if cache expired or doesn't exist return $pages->find("template=product, limit=100"); }); // Get existing cache (returns null if not found) $cached = $cache->get('my-cache-key'); // Save to cache with expiration $cache->save('my-cache-key', $myData, 3600); // 1 hour $cache->save('my-cache-key', $myData, WireCache::expireDaily); $cache->save('my-cache-key', $myData, WireCache::expireWeekly); $cache->save('my-cache-key', $myData, WireCache::expireNever); // Cache that expires when a page is saved $cache->save('nav-cache', $navHtml, 'template=basic-page'); $cache->save('product-list', $html, $page); // Expire when $page is saved // Delete specific cache $cache->delete('my-cache-key'); // Delete all caches matching a pattern $cache->deleteFor('my-*'); // Delete all user-created caches $cache->deleteAll(); // Cache page rendering $html = $cache->get('homepage-content', 3600, function() use($page) { return $page->render(); }); // Store arrays (automatically serialized) $cache->save('user-preferences', [ 'theme' => 'dark', 'language' => 'en' ], WireCache::expireDaily); $prefs = $cache->get('user-preferences'); echo $prefs['theme']; // 'dark' // Render and cache using MarkupCache module $cache = $modules->get('MarkupCache'); if(!$data = $cache->get('sidebar', 3600)) { $data = renderSidebar(); // Your custom function $cache->save($data); } echo $data; ``` --- ## Files API ($files) The `$files` API variable provides helpers for working with files and directories, respecting ProcessWire's security and permission settings. ```php <?php namespace ProcessWire; // Create directory $files->mkdir($config->paths->assets . 'custom/', true); // true = recursive // Remove directory $files->rmdir($config->paths->cache . 'temp/', true); // true = recursive // Copy file $files->copy($sourcePath, $destPath); // Rename/move file $files->rename($oldPath, $newPath); // Delete file $files->unlink($filePath); // Check if file/directory exists and is writable if($files->exists($path)) { /* exists */ } if($files->writable($path)) { /* is writable */ } // Get file extension $ext = $files->extension($filename); // 'jpg' // Get filename without extension $name = $files->nameWithoutExtension($filename); // Get file contents $content = $files->fileGetContents($path); // Write file contents $files->filePutContents($path, $content); // Include a PHP file with variables in scope $files->include($config->paths->templates . 'partials/header.php', [ 'title' => 'My Page', 'showNav' => true ]); // Render a file and return output $html = $files->render($config->paths->templates . 'partials/card.php', [ 'item' => $page ]); // Get CSV file data $data = $files->getCSV($csvPath); foreach($data as $row) { echo $row['column_name']; } // Send file for download $files->send($filePath, [ 'forceDownload' => true, 'filename' => 'download.pdf' ]); // Zip files $zipPath = $files->zip($config->paths->assets . 'backup.zip', [ $config->paths->templates . 'styles/', $config->paths->templates . 'scripts/' ]); // Unzip files $files->unzip($zipPath, $config->paths->cache . 'extracted/'); // Working with page files $page->images->add('/path/to/image.jpg'); $page->files->add('/path/to/document.pdf'); $page->save(); // Get file URL $url = $page->images->first()->url; $httpUrl = $page->images->first()->httpUrl; // Get file path $path = $page->images->first()->filename; // Create image variations $thumb = $page->images->first()->size(200, 200); $cropped = $page->images->first()->crop(400, 300); ``` --- ## Templates API ($templates) The `$templates` API variable provides access to all templates in ProcessWire. Templates define the structure of pages and which fields they contain. ```php <?php namespace ProcessWire; // Get a template by name $template = $templates->get('blog-post'); // Access template properties echo $template->id; echo $template->name; echo $template->label; echo $template->filename; // Path to template file // Get all fields in a template foreach($template->fields as $field) { echo "{$field->name}: {$field->type}<br>"; } // Check if template has a specific field if($template->hasField('body')) { // Template has body field } // Get all templates foreach($templates as $t) { if($t->flags & Template::flagSystem) continue; // Skip system templates echo $t->name . "<br>"; } // Find templates matching criteria $templates->find("name^=blog"); $templates->find("flags=0"); // Non-system templates // Template settings echo $template->allowChildren; // Allowed child templates echo $template->parentTemplates; // Allowed parent templates echo $template->urlSegments; // URL segments enabled? echo $template->https; // Force HTTPS? echo $template->slashUrls; // Trailing slash in URLs? // Get number of pages using template $count = $pages->count("template=$template"); ``` --- ## Fields API ($fields) The `$fields` API variable provides access to all fields defined in ProcessWire. Fields define the data types for page content. ```php <?php namespace ProcessWire; // Get a field by name $field = $fields->get('body'); // Access field properties echo $field->id; echo $field->name; echo $field->type; // Fieldtype object echo $field->label; echo $field->description; // Get all fields foreach($fields as $f) { echo "{$f->name} ({$f->type})<br>"; } // Find fields by type $textFields = $fields->find("type=FieldtypeText"); $imageFields = $fields->find("type=FieldtypeImage"); // Check field type if($field->type instanceof FieldtypeTextarea) { // It's a textarea field } // Get templates using a field foreach($field->getFieldgroups() as $fieldgroup) { echo $fieldgroup->name . "<br>"; } // Create a new field programmatically $field = new Field(); $field->type = $modules->get('FieldtypeText'); $field->name = 'subtitle'; $field->label = 'Subtitle'; $field->description = 'Optional subtitle for the page'; $field->maxlength = 255; $fields->save($field); // Add field to a template's fieldgroup $template = $templates->get('basic-page'); $template->fieldgroup->add($field); $template->fieldgroup->save(); ``` --- ## Modules API ($modules) The `$modules` API variable provides access to all installed modules. Modules extend ProcessWire's functionality. ```php <?php namespace ProcessWire; // Get a module by name $module = $modules->get('MarkupPagerNav'); // Alternative syntax $module = $modules->MarkupPagerNav; // Check if module is installed if($modules->isInstalled('ModuleName')) { $module = $modules->get('ModuleName'); } // Get module info $info = $modules->getModuleInfo('MarkupPagerNav'); echo $info['title']; echo $info['version']; echo $info['summary']; // Get module config data $config = $modules->getModuleConfigData('ModuleName'); // Save module config $modules->saveModuleConfigData('ModuleName', [ 'setting1' => 'value1', 'setting2' => 'value2' ]); // Install a module $modules->install('ModuleName'); // Uninstall a module $modules->uninstall('ModuleName'); // Get all installed modules foreach($modules as $module) { $info = $modules->getModuleInfo($module); echo "{$info['title']} v{$info['version']}<br>"; } // Common module usage examples // Pagination with MarkupPagerNav $items = $pages->find("template=blog-post, limit=10"); $pagination = $modules->get('MarkupPagerNav'); echo $pagination->render($items); // Simple contact form with FormBuilder (Pro module) $form = $modules->get('FormBuilder')->render('contact'); echo $form; ``` --- ## Hooks Hooks allow you to modify or extend ProcessWire's behavior by attaching custom code to methods. Hooks can run before or after the original method. ```php <?php namespace ProcessWire; // Add hook in /site/ready.php or module // Hook AFTER a method (modify return value or add behavior) $wire->addHookAfter('Page::render', function(HookEvent $event) { $page = $event->object; $html = $event->return; // Modify the rendered HTML $event->return = str_replace('</body>', '<script>/* analytics */</script></body>', $html); }); // Hook BEFORE a method (modify arguments or prevent execution) $wire->addHookBefore('Pages::save', function(HookEvent $event) { $page = $event->arguments(0); if($page->template == 'blog-post' && empty($page->summary)) { // Auto-generate summary from body $page->summary = substr(strip_tags($page->body), 0, 200) . '...'; } }); // Hook to add a new method to Page $wire->addHook('Page::fullName', function(HookEvent $event) { $page = $event->object; $event->return = "{$page->title} ({$page->name})"; }); // Usage: echo $page->fullName(); // Hook to add a new property to Page $wire->addHook('Page::authorName', function(HookEvent $event) { $page = $event->object; $event->return = $page->createdUser->name; }); // Usage: echo $page->authorName; // Conditional hooks (only run for specific conditions) $wire->addHookAfter('Pages::saved', function(HookEvent $event) { $page = $event->arguments(0); if($page->template != 'blog-post') return; // Send notification when blog post is saved $mail = wireMail(); $mail->to('admin@example.com') ->subject("Blog post updated: {$page->title}") ->body("View: {$page->httpUrl}") ->send(); }); // Hook Page::path for custom URL structure $wire->addHookAfter('Page::path', function(HookEvent $event) { $page = $event->object; if($page->template == 'product') { // Custom URL: /shop/category-name/product-name/ $event->return = "/shop/{$page->parent->name}/{$page->name}/"; } }); // Multiple hooks on same method $wire->addHookAfter('Page::render', function(HookEvent $event) { // First hook }, ['priority' => 50]); $wire->addHookAfter('Page::render', function(HookEvent $event) { // Second hook (runs after first due to higher priority number) }, ['priority' => 100]); ``` --- ## Template File Examples Template files in `/site/templates/` define how pages are rendered. They have full access to ProcessWire's API. ```php <?php namespace ProcessWire; // Basic template file: /site/templates/blog-post.php /** @var Page $page */ /** @var Pages $pages */ /** @var Config $config */ ?> <article class="blog-post"> <h1><?= $page->title ?></h1> <div class="meta"> <span class="date"><?= date('F j, Y', $page->created) ?></span> <span class="author"><?= $page->createdUser->name ?></span> <?php if($page->categories->count): ?> <span class="categories"> <?= $page->categories->implode(', ', '<a href="{url}">{title}</a>') ?> </span> <?php endif; ?> </div> <?php if($page->featured_image): ?> <figure class="featured-image"> <img src="<?= $page->featured_image->size(800, 400)->url ?>" alt="<?= $page->featured_image->description ?>"> </figure> <?php endif; ?> <div class="content"> <?= $page->body ?> </div> <?php if($page->images->count): ?> <div class="gallery"> <?php foreach($page->images as $img): ?> <a href="<?= $img->url ?>"> <img src="<?= $img->size(150, 150)->url ?>" alt="<?= $img->description ?>"> </a> <?php endforeach; ?> </div> <?php endif; ?> <nav class="post-navigation"> <?php if($page->prev): ?> <a href="<?= $page->prev->url ?>" class="prev">← <?= $page->prev->title ?></a> <?php endif; ?> <?php if($page->next): ?> <a href="<?= $page->next->url ?>" class="next"><?= $page->next->title ?> →</a> <?php endif; ?> </nav> </article> <?php // Related posts $related = $pages->find("template=blog-post, categories={$page->categories}, id!={$page->id}, limit=3"); if($related->count): ?> <section class="related-posts"> <h2>Related Posts</h2> <?php foreach($related as $post): ?> <article> <a href="<?= $post->url ?>"><?= $post->title ?></a> <p><?= $post->summary ?></p> </article> <?php endforeach; ?> </section> <?php endif; ?> ``` --- ## Configuration ($config) The `$config` API variable provides access to ProcessWire's configuration settings and paths. ```php <?php namespace ProcessWire; // Important paths echo $config->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->assets; // /var/www/site/site/assets/ echo $config->paths->files; // /var/www/site/site/assets/files/ echo $config->paths->cache; // /var/www/site/site/assets/cache/ echo $config->paths->logs; // /var/www/site/site/assets/logs/ // URL equivalents echo $config->urls->root; // / echo $config->urls->site; // /site/ echo $config->urls->templates; // /site/templates/ echo $config->urls->assets; // /site/assets/ echo $config->urls->admin; // /processwire/ // HTTP settings echo $config->httpHost; // example.com echo $config->https; // true/false // Debug mode if($config->debug) { // Show debug information } // Database settings (from /site/config.php) echo $config->dbName; echo $config->dbHost; // Current user and page echo $config->adminRootPageID; // Admin page ID echo $config->trashPageID; // Trash page ID // Timezone echo $config->timezone; // America/New_York // Add custom config in /site/config.php: // $config->myCustomSetting = 'value'; // Access: $config->myCustomSetting // Set runtime configuration $config->styles->add($config->urls->templates . 'styles/custom.css'); $config->scripts->add($config->urls->templates . 'scripts/custom.js'); ``` --- ## Summary ProcessWire excels at building custom websites and applications where content structure varies significantly. Its selector-based API makes complex database queries readable and maintainable, while the Page-based architecture provides a consistent interface for all content types. Common use cases include corporate websites, blogs, e-commerce platforms, multi-language sites, REST APIs, and custom web applications where traditional CMS constraints would be limiting. Integration with ProcessWire typically involves creating custom templates in `/site/templates/`, defining fields through the admin interface, and using the API in template files to query and display content. The hook system enables deep customization without modifying core files, and the module architecture allows for extending functionality. ProcessWire works well with modern front-end frameworks when building headless/API-driven applications, and its flat learning curve combined with comprehensive documentation makes it accessible for developers of all skill levels.