Custom ProcessWire Template Development: Speed, Flexibility, Control

You launched an e-commerce store on ProcessWire, but pages take 3 seconds to load and LCP is off the charts? The default theme adds tons of unused scripts, and the markup isn't adaptable to your data. A custom template solves this – you get exactly what you need, no bloat. With 8 years of ProcessWir

Development and maintenance of all types of websites:

Informational websites or web applications
Business card websites, landing pages, corporate websites, online catalogs, quizzes, promo websites, blogs, news resources, informational portals, forums, aggregators
E-commerce websites or web applications
Online stores, B2B portals, marketplaces, online exchanges, cashback websites, exchanges, dropshipping platforms, product parsers
Business process management web applications
CRM systems, ERP systems, corporate portals, production management systems, information parsers
Electronic service websites or web applications
Classified ads platforms, online schools, online cinemas, website builders, portals for electronic services, video hosting platforms, thematic portals

These are just some of the technical types of websites we work with, and each of them can have its own specific features and functionality, as well as be customized to meet the specific needs and goals of the client.

Our competencies:

Frequently Asked Questions

Latest works

  • image_website-b2b-advance_0.webp
    B2B ADVANCE company website development
    1414
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1285
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    980
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1240
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    982
  • image_bitrix-bitrix-24-1c_fixper_448_0.webp
    Website development for FIXPER company
    994

You launched an e-commerce store on ProcessWire, but pages take 3 seconds to load and LCP is off the charts? The default theme adds tons of unused scripts, and the markup isn't adaptable to your data. A custom template solves this – you get exactly what you need, no bloat. With 8 years of ProcessWire experience, we guarantee a reliable solution. Switching to custom templates reduces TTFB by 2-3x by eliminating unused modules.

How to Develop a Custom ProcessWire Template?

A template in ProcessWire is a PHP file in /site/templates/, whose name matches the template name in the database. The file receives the $page object with current page data and full access to $pages, $config, $user, and the rest of the API. Pure PHP – no default engine, though you can integrate Twig via the TemplateEngineTwig module. For production we recommend pure PHP: it's faster and adds no extra abstraction layer.

Why Is a Custom Template Better Than a Standard Theme?

Standard themes are often overloaded with unused scripts and styles, increasing LCP and CLS. A custom template outputs only needed data, uses server-side rendering for heavy components, and implements lazy loading for images. In one of our projects – a ProcessWire e-store with 5000+ products – switching to custom templates reduced memory consumption by 60% and sped up page generation by 2x. Additionally, we cut database queries from 50 to 3 per page.

Template Architecture: Splitting Options

Option 1: _init.php + _main.php

The most common approach. ProcessWire automatically includes _init.php before each template and _main.php after, if the "Prepend/Append template file" option is enabled in the template settings:

// _init.php и _main.php — единый поток $baseUrl = $config->urls->root; $homePage = $pages->get("/"); $mainNav = $pages->find("parent=/,template!=error404,sort=sort"); ?><!DOCTYPE html> <html lang="<?= $user->language->name ?>"> <head> <meta charset="utf-8"> <title><?= $page->title ?> | <?= $homePage->title ?></title> <link rel="stylesheet" href="<?= $config->urls->templates ?>css/main.css"> </head> <body> <?php include("partials/nav.php"); ?> <main><?= $content ?></main> <?php include("partials/footer.php"); ?> </body> </html> 

Option 2: Controller + View

For complex templates, logic is extracted into a separate controller file. This simplifies maintenance and testing:

// templates/services.php — точка входа require __DIR__ . '/controllers/services.php'; extract($viewData); require __DIR__ . '/views/services.view.php'; // templates/controllers/services.php — контроллер $viewData = [ 'items' => $pages->find("template=service, sort=sort, limit=12"), 'categories' => $pages->find("template=service-category, sort=sort"), 'pagination' => $modules->get("MarkupPagerNav"), ]; 

Approach Comparison

Feature init/main controller+view
Complexity Low Medium
Maintainability Simple Flexible
Testability Low High
Performance High High
Recommendation Small projects Complex projects

Working with Images

ProcessWire processes images on the fly via the size() method. Example with WebP:

$img = $page->images->first(); if ($img) { $thumb = $img->size(800, 600, ['cropping' => 'center', 'quality' => 85]); echo "<img src='{$thumb->url}' alt='{$img->description}' loading='lazy'>"; $webp = $img->size(800, 600, ['suffix' => 'webp', 'webpAdd' => true]); } 

Custom 404 and Redirects

if ($page->redirect_url) { $session->redirect($page->redirect_url, 301); } if (!$user->isLoggedin() && $page->requires_login) { throw new Wire404Exception(); } 

How to Optimize Images: Step-by-Step

  1. Select an image from the page gallery.
  2. Call $img->size() with desired parameters.
  3. Specify suffix: 'webp' and webpAdd: true to generate WebP.
  4. Add the loading='lazy' attribute for deferred loading.
  5. Use $pages->findMany() for bulk conversion on high-traffic sites.

Performance: Lazy Loading Relationships

By default, FieldtypePage loads related objects upon access. For large lists, use $pages->findMany() – stream processing without loading everything into memory:

foreach ($pages->findMany("template=product, sort=title") as $product) { echo $product->title . "\n"; } 
Details about findMany() findMany() processes pages one by one, not storing them in memory. This is especially important on pages with thousands of products. It works as a generator: each iteration loads only the current page.

Typical Template Development Timelines

Task Estimate
Basic template (layout + nav + footer) 4–8 h
List template with pagination and filter 8–16 h
Detailed page with relationships 4–10 h
Template system for 10+ content types 3–6 days
Twig integration + component approach 2–4 days

What's Included in Development?

  • Template architecture (init/main or controller+view)
  • Configuration of prepend/append files
  • Markup for all typical pages (list, detail, 404)
  • Image optimization (size, WebP, lazy loading)
  • Basic SEO markup (meta title, description, og:image)
  • Template and access documentation
  • Client team training (1 hour online)
  • 3-month code warranty

Training and documentation are separate items: we transfer knowledge so you can maintain the project independently.

Typical Problems and Solutions

Not using output buffering with prepend/append leads to duplicate headers. Solution – always enable prepend/append or use the controller pattern. Loading all related pages at once – for sets over 100 records use $pages->findMany(). Ignoring image caching – ProcessWire caches variants, but if content changes frequently, clear the cache in /site/assets/files/. A 404 page is mandatory: always throw Wire404Exception for protected sections.

Contact us for a free consultation – we'll discuss your project. Order custom ProcessWire template development and get flexibility and performance.

MDN Lazy loading guide – more about the loading attribute. Wikipedia Core Web Vitals – performance metrics.