Basic concepts

First things first: Wireframe loosely follows the MVC – Model View Controller – pattern. If you're unfamiliar with MVC itself, you can find a ton of stuff about it from the web (and we have a page containing some basic details here on this site as well).

Probably the most important thing to know about MVC is that it promotes separation of concerns between data, business logic, and user interface by splitting them into layers: the model (which represents the data), the view (the user interface), and the controller (which is sort of a mediator between model and view).

MVC was originally devised as a method of handling desktop software, and basically all the web based variants are exactly that: variants. Wireframe isn't anywhere near a 100% accurate implementation either, and one particularly notable difference is that it doesn't actually include a model layer. (Wait, what?!)

The reasoning here is that in the context of a ProcessWire site, ProcessWire itself is the model. This does, though, sometimes result in Wireframe Controllers containing plenty of business logic. That "fat model, thin controller" mantra you might've heard of? Absolutely doable, but will require a bit of extra effort.

Below you'll find a quick breakdown of the core concepts (and components) you'll definitely run into while working with Wireframe.

Wireframe bootstrap file

The Wireframe bootstrap file is a single file in your /site/templates/ directory, typically named wireframe.php. This file is inserted into the Alternate Template File setting for templates you want to utilize Wireframe for, and it is responsible for bootstrapping the Wireframe framework, and also providing it with any general-purpose settings (such as a site name or language) you may need. For an example of the bootstrap file, see the About page.

You'll find the default (rather bare-bones) Wireframe bootstrap file from the Wireframe module directory.


Wireframe is MVC-ish, and one reason for the "-ish" suffix is that there's actually no literal Model component in the framework.

Instead Wireframe treats ProcessWire as the model: you can access ProcessWire's excellent API from both your Controllers and Views, and tasks commonly associated with the Model – such as fetching data from the database, aggregating content items, or creating new items – are easily achieved with some simple API calls.


The View component is essentially the current rendering context. You can pass params from Controller to View using the $view API variable, and they'll become locally scoped variables for your layouts, views, and partials (<?= $this->some_var ?>).

Note that you can also access the $view API var from within layouts and views, which means that it's possible to pass data from a view to the layout. Due to rendering order, passing data from a layout to view is not possible.


Controllers are optional template-specific classes. Their main responsibilities include processing user input, fetching data from the Model (ProcessWire), formatting it as needed, and then passing it back to the View.

In Wireframe Controllers should contain business logic related to the template – or, at least, business logic that doesn't belong to a separate module or class. One of the key concepts of MVC is separation of concerns, and the first step towards that goal is not mixing business logic with markup generation.

Note that Controllers are indeed optional: if a Page can be rendered without complex business rules (meaning that you only need some basic control structures, loops, and echo/print statements), it is perfectly fine to leave Controllers out of the equation and request data directly from ProcessWire's API in the View.

When a Page is rendered, Wireframe checks if it can find and instantiate a Controller class. If it can't, it'll continue rendering the Page without one.


A layout is a wrapper (container) for page content. Most sites will likely only need one layout, or perhaps two at most – but this of course depends a lot on the site itself. Page-specific content is typically rendered using a view file and then injected into the layout using what we call View Placeholders.

Layouts are recommended, but technically optional. If you find that many of your pages include an identical (or almost identical) basic structure, such as a common header and footer, you can always include partial files for these common parts on each view – but that's also where layouts shine.

By moving those shared parts of the page markup into a layout file you avoid having to add include clauses all over your views.


Views are used to render actual page content. Each template may have one or more view: while you often only need one to render page content, you can add additional views for rendering page content in different ways, or in different contexts.

For an example a news-list template could have a "default" view for rendering a HTML markup for a news list, an "rss" view for rendering the child pages (items) as a machine-readable feed, a "json" view script for providing a JSON API – and so on.

Each view script can specify different content type, and you can use anything from GET parameters to URL segments – or even headers – for selecting which view to use.

Note: by default views are PHP files, which means that you can include loads of business logic within them. Regardless it is strongly recommended that you keep your view files as "dumb" as possible. Typical view level tasks include outputting content, and simple loops and other basic control structures.

View Placeholders

View Placeholders are the preferred way to inject the rendered page content – or any markup and/or variables produced by Controllers for that matter – into a Layout. View Placeholders can be accessed via the $placeholders variable.

Start by setting a value in a Controller:

$this->view->placeholders->title = $page->title;

Now you can read that value in a Layout file:

<title><?= $placeholders->title ?></title>

You can also define placeholders using views: create a view file matching the name of the intended placeholder, such as /site/templates/views/home/title.php, and use the placeholder variable (in this example `$placeholders->title`) in a layout – just like we did in the example above. When you do that, Wireframe renders the page using matching view file and inserts the rendered output into the placeholder variable.


Partials are smaller pieces of markup (usually specific parts or elements of the site) you can include within your view or layout files. Partials can come in handy any time you want to split a view file into smaller, more manageable chunks, but they are especially useful when it comes to defining reusable UI components.

Partials are embedded using PHP's native include or require commands:

<?php include 'partials/menu/top.php'; ?>

Wireframe also provides an alternative, object oriented way to access partials:

<?php include $partials->menu->top; ?>
Back to top