ProcessWire CMS – A Beginner’s Guide
Systems for managing content are more often than not rather opinionated. For example, most of them expect a certain rigid content structure for inputting data and then have a specific engraved way of accessing and outputting that data, whether or not it makes sense. Additionally, they rarely offer effective tools to break out of the predefined trails if a case requires it.
ProcessWire is a content management system (CMS) distributed under the Mozilla Public License version 2.0 (MPL) and MIT License. It is designed from the ground up to tackle the issues caused by exactly this kind of opinionatedness (which, inevitably, results in frustrated developers and users) by being — you guessed it — non-opinionated. At its heart, it is based on a few simple core concepts and offers an exceptionally easy-to-use and powerful API to handle content of any kind. Let’s get right into it!
The Admin GUI
After installing ProcessWire (which requires PHP 5.3.8+, MySQL 5.0.15+ and Apache), you will see the home page of the default admin GUI:
Note: The pages you see in the hierarchical page tree (more on that later) are there because I chose the “Default (Beginner Edition)” website profile during the installation process. This is totally optional. You could also start with a blank website profile, which lets you build everything from scratch.
You can actually choose from many admin themes, although for ProcessWire 2.6+ the default theme or Reno theme is recommended. Because Reno comes prepackaged with every ProcessWire installation, switching to it is pretty easy: Just install it and select it in your user profile.
Let’s have a quick look at the main back-end navigation:
- “Pages” This is the entry point of the admin GUI. It features the hierarchical page tree and, thus, all of your website’s content in the back end.
- “Setup” This is the place to set up the general data model architecture of your installation through templates and fields (more on that later). This is also where ProcessWire modules often add an entry for their specific functionality and user interface — for example, visualizing log messages right in the admin GUI or managing all of the different languages when dealing with multi-language content.
- “Modules” This is where you manage all of your website’s modules. Think of ProcessWire modules as WordPress plugins: They extend and customize the system.
- “Access” Here is where you manage users, user roles and user permissions.
Three Simple Core Concepts
The core concepts that form the overall data model architecture of ProcessWire are exactly three: pages, fields and templates. Let’s look at each one by one.
Everything Is A Page: Or, One Page Tree To Rule Them All
A page in ProcessWire can generate a regular page in the front end of your website, ready to be visited by your users (like “Home” and “About” in the screenshot above). But a page can also exist solely in the back end, with no front-end counterpart — for example, a hidden settings page where you store the global slogan, logo and copyright notice of your website. When I say “everything is a page” in ProcessWire, I mean it. Heck, even the main navigation links in the admin GUI are made out of hidden pages in the hierarchical page tree!
This is so meta that I’m reminded of a certain Xzibit meme. But let’s leave it at that.
The concept of a page being visible only in the back end is pretty powerful because it opens up a whole world of possibilities on how to structure and access data through other pages (your imagination being the only limit). You could build a massive product catalog, or an intranet application with hundreds of thousands of items based on a complex page hierarchy, or just a simple blog with the usual blog categories and tags (every category and tag being a page in the page tree).
Joss Sanglier, a distinguished member in the ProcessWire community, breaks down the concept of pages to this:
"[I]n ProcessWire pages are […] not great gulps of information, but tiny little things, nothing more than a link to the more interesting world of fields and templates; just a little blip of data in your huge fascinating database. Pages in ProcessWire are used for all kinds of things. They can be used as a marker in your pages list. They can be used as a group parent for other pages. They can be used as categories, tags or lists or users. And they can even be used for simple drop-down selects — just to supply a label and value."
Let’s interact with the hierarchical page tree a little bit:
As you can see, pages can be edited, moved around or trashed, and they can have an infinite number of children and grandchildren.
Let’s open up the “Home” page:
This brings us to the next core concept of ProcessWire, fields.
Fields Are The Containers Into Which You Put Data
Fields are basically the containers into which you put data. At this point, it’s important to realize that ProcessWire doesn’t have the concept of custom fields, like WordPress does, because every field in ProcessWire is a custom field. When you create a field, you can give it a label, a description and some additional notes that will appear underneath it.
Let’s edit the “Title” field and add a description and a note to it:
The preinstalled field types cover most basic data-input needs. For example, you can create things like check boxes, date-pickers, field sets (a field that groups other fields into visually logical units), file and image uploaders and, of course, text and textarea fields (the default WYSIWYG editor being CKEditor).
There are also a lot of prepackaged and third-party field types to choose from. A useful core module, which is not installed by default, is the repeater field. It lets you dynamically create rows of data sets.
ProcessWire is also a good fit for handling images. For example, you can decide which image variants ProcessWire should automatically create of an image after uploading it (which enables nice use cases for responsive images). And choosing a thumbnail for an image is a breeze.
Another useful field type is the page field type. You can link other pages with the page you are currently editing and, thus, create a relationship between them. In the field’s settings, you can decide how the input’s appearance and interaction with the field should be — for example, whether a single page or multiple pages should be selectable, or whether only the child pages of a particular parent page should be selectable. If you were to write, say, a blog post, you could choose to allow only blog post categories to autocomplete.
A neat feature you can switch on in the settings of a field is the ability to edit the field’s content in the front end of your website. Once a user has logged into ProcessWire’s back end, they can switch to the website’s front end and edit and save the content right where it will eventually get rendered.
After looking at pages and fields in ProcessWire, you may ask yourself: How does a page know which fields it has? And where can I define how the fields are ordered and rendered on a page? So, let’s move on to the last core concept, templates.
Templates Are The Blueprints Of Pages
Every time you create a page in the hierarchical page tree, ProcessWire needs to know which template is associated with it. That’s because a page needs to know which fields it has to render, and that information is always a part of the respective template.
Long story short: Templates contain all of the information the page needs to know about its contents (what fields it has, how those fields are rendered and how they behave).
Let’s open the “Home” template from our sample installation.
The main thing to notice is the number of settings. There’s really a lot to discover here. For example, you can limit access to the pages created with this template to specific user roles. Or you can decide whether pages created with this template should be cached for a specific amount of time (to enhance performance), plus the conditions under which the cache must be cleared.
Another powerful setting is hidden in the “Family” tab. Here, you can define whether pages created with this template can have children pages and which templates are allowed for the parent page or its children pages. This allows you to create exactly the type of template family hierarchy that you want. It’s a flexible and handy way (and actually one of the most powerful ways) to structure your data, and it’s one of the many ways that ProcessWire shows its flexibility.
Let’s turn our attention to the list of fields in a template. Looking at the screenshot above, you can see that the order of the fields resembles the order in which the fields will get rendered on the home page. You can simply drag and drop fields to change the order in the list, thus changing the order of appearance when editing the home page.
You can also change the width of a field on the page. Just click on a field and change it. Let’s put the “Title” and “Headline” fields side by side.
Another example of how you can customize and tailor the user interface of a page and its fields are inputfield dependencies. These enable you to specify the conditions under which a particular field in the page editor is shown or required. Let’s make the “Headline” field visible in the UI only if the user enters something in the “Title” field, and let’s mark the “Summary” field as required only if the user enters something in the “Headline” field:
Here’s a video that shows you how inputfield dependencies can be used to enhance the user’s experience while working with ProcessWire:
The number, order and appearance of fields on a page are totally under your control. You can put just one field in a template, none at all (not very useful) or more than 50 fields, 100 or even more. You can order them in any way you want, specify which are required or visible and which aren’t, and specify under what circumstances they should be required or visible. Here is where ProcessWire’s non-opinionated approach shines.
Roundup: Pages, Fields, Templates
Let’s recap the technical relationship between pages, fields and templates: You add fields to templates, and you select a template when creating a new page. The fields you see when editing a page are the fields you’ve added to the selected template.
Another way to look at this would be through an analogy from the programming world:
- Templates are like classes.
- Fields are like the properties of classes.
- Pages are instances of classes.
Once you internalize these concepts, you’ll be equipped with everything you need to know to develop in ProcessWire. And the reason for this is that ProcessWire’s philosophy is based solely on these three concepts. Pretty cool, right?
Template Files And The API: A Couple Meant To Be Together
The place where you retrieve the data inputted in ProcessWire’s back end and output it in the front end is, of course, the file system — more specifically, the /site/templates/
folder of your ProcessWire installation. A template can have a physical PHP file of the same name associated with it; so, the home
template would have a home.php
file in the /site/templates/
folder.
Note: How you develop your template files is totally up to you. If you are familiar with the WordPress style of developing things, you can continue just as you are used to. Or, if you have a pretty complex and big set-up and want to create a more sophisticated architecture, you could use an MVC-inspired approach, which would work just as well. Ryan Cramer has a pretty good introductory tutorial, titled “How to Structure Your Template Files,” in which you can learn different approaches to template file development in ProcessWire.
The code you write in a template file will mostly consist of basic PHP constructs (if
conditions, foreach
loops, echo
statements), HTML markup and ProcessWire’s API. The API is heavily inspired by jQuery — so, it’s really kind of like iterating and traversing the content you’ve inputted in the back end via methods, selectors and chaining (fluent interface) capabilities. It’s easy to use and very expressive, just like jQuery.
Let’s start by looking at some simple examples to get you going with the API. But before we start, remember to bookmark the ProcessWire API cheat sheet, a helpful reference with an overview of all available API methods.
The thing we want to do first is access and output the content of a page’s field. The API exposes a variable for us to deal with this: $page
.
Getting The Current Page With The $page
Variable
The $page
variable contains all of the fields of a single page. This includes built-in fields (like the name of a page’s template), as well as the fields you, as the developer, have added to the page’s template.
Let’s open home.php
, which is the template file of the home
template, and add this line to it:
echo $page->title;
This tells ProcessWire to grab the “Title” field of the page we are currently on (“Home”) and output it. Let’s say we also have a “Headline” field on the page, which we want to use instead of the “Title” field but only if the user has entered something in it.
echo $page->get("headline|title");
We used the get
method to access a page’s field (so, $page->get("title")
is basically equivalent to the first code example above), and we wrote “headline|title”
in the get
method. This tells ProcessWire to first check the “Headline” field and output the headline’s content. But if the “Headline” field is empty, then the “Title” field is used as the fallback.
Using API variables in PHP strings is also possible. The following two echo
statements for outputting the number of children of a page are equivalent:
echo "This page has " . $page->numChildren . " children pages.";
echo "This page has {$page->numChildren} children pages.";
Let’s get the children of our root page (remember, we are still in home.php
) and output them as a list of links:
echo "<ul>";
foreach ($page->children as $child) {
echo "<li><a href='{$child->url}'>{$child->title}</a></li>";
}
echo "</ul>";
Another example of a built-in field (like children
and url
in the example above) is iterating through all parents of a page and creating breadcrumb navigation:
echo "<ul>";
foreach ($page->parents as $parent) {
echo "<li><a href='{$parent->url}'>{$parent->title}</a></li>";
}
// output the page itself at the end
echo "<li>{$page->title}</li>";
echo "</ul>";
On the root page (“Home”), this would just output its title, because $page->parents
would be empty.
Earlier, I showed you how to create image thumbnails in the admin GUI. Creating thumbnails can also be done programmatically with the help of the API. Let’s iterate through all images uploaded in the “Images” field, create a large image variant at 600 pixel wide with a proportional height, and a 150 × 150-pixel thumbnail, with specific options like crop settings and image quality. In the end, we want to link the thumbnail image to the large image. Sounds complicated? It isn’t.
$options = array(
"quality" => 90,
"cropping" => "northwest"
);
foreach ($page->images as $image) {
$large = $image->width(600);
$thumbnail = $image->size(150, 150, $options);
echo "<a href='{$large->url}'><img src='{$thumbnail->url}' alt=’></a>";
}
ProcessWire is pretty smart in this regard because it creates images at any sizes on the fly and keeps a cache of them, so that it has to create the versions just once.
Here is one last $page
example to show you that the API feels a lot like you’re interacting with the DOM when using jQuery. Let’s get the last child of the parent page we are currently on.
$wantedPage = $page->parent->children()->last();
Besides the $page
variable, the API exposes another important one: $pages
.
Getting All Pages With The $pages
Variable
With $pages
, you have access to all pages in your ProcessWire installation. In other words, it gives you access to all of your content from anywhere.
For example, you could have a hidden (meaning, not accessible in the front end) settings page in your ProcessWire installation; you could add global settings, like the title and description of your website; and you could access and output these content blobs from any template file you want.
$settings = $pages->get("template=settings");
echo "<h1>{$settings->global_title}</h1>";
echo "<p>{$settings->global_description}</p>";
One common use case for a single topic page of a blog is to show all blog posts in which the topic is referenced. Just write this in the template file of the topic:
$pages->find("template=blog-post, topics=$page");
Note: topics
is a field in the blog-post
template where you would add all topic categories that are specific to the blog post.
Let’s work a little more with ProcessWire’s selector engine. Let me show you some examples by referring you to ProcessWire’s demo website, a directory of US skyscrapers. The demo website contains many pages and has an interesting data model architecture (i.e. things like architects, cities, buildings and locations referencing each other), and it’s a good use case to show what you can do with selectors.
This example finds all skyscrapers that mention the phrase “empire state building” in their body copy:
$pages->get("template=cities")->find("template=skyscraper, body*=empire state building");
Note: First we get the page with the template cities
; then, we get all pages with the template skyscraper
. The reason why we can chain the methods in this way is because all skyscraper pages are sub-children of the “Cities” page.
Let’s find all skyscrapers by the architects Adrian Smith, Eric Kuhne or William Pereira and sort the results by height in ascending order:
$adrian = $pages->get("template=architect, name=adrian-smith");
$eric = $pages->get("template=architect, name=eric-kuhne");
$william = $pages->get("template=architect, name=william-pereira");
$skyscrapers = $pages->find("template=skyscraper, architects=$adrian|$eric|$william, sort=height");
You could optimize the code by finding all requested architects in a single step, instead of three:
$architects = $pages->find("template=architect, name=adrian-smith|eric-kuhne|william-pereira");
$skyscrapers = $pages->find("template=skyscraper, architects=$architects, sort=height");
Note: The get
method potentially always returns one page; the find
method potentially always returns multiple pages.
You can further revise the code by using sub-selectors (yes, you can have selectors inside of selectors):
$skyscrapers = $pages->find("template=skyscraper, architects=[name=adrian-smith|eric-kuhne|william-pereira], sort=height");
Other API Variables
$page
and $pages
are not the only API variables you can work with. There are a whole lot of other ones, such as $session
(to log users in and out and to redirect to other pages), $user
(to establish a connection to the user currently viewing the page) and $config
(which are for settings specific to your ProcessWire installation). Let’s look at two examples.
First, let’s redirect the user to the home page:
$session->redirect($pages->get("template=home")->url);
And let’s do something if the current user is logged in:
if ($user->isLoggedin()) { /* do something */ }
Extending ProcessWire’s Functionality With Modules
ProcessWire is built on a modular and easily extendable architecture, and it shows: Every installation consists of ProcessWire’s core (the essence of ProcessWire, which enables the basic functionality) and a set of prepackaged modules (so-called core modules) that sit on top of the core and extend it.
Core Modules
Some of these prepackaged modules are installed and activated by default, and others are uninstalled by default. For example, ProcessWire’s built-in comment system is a module you can switch on or off at any time. Also, things like the repeater field we talked about earlier and the multi-language support for content are basically just modules you can install if you need them in your project.
Other examples of neat little core modules are Page Names, which validates text input when you’re typing a page name (automatically transforming, say, umlauts like ä to ae), and Page Path History, which keeps track of past URLs where pages have lived and automatically redirects to the new location whenever an old URL is accessed.
Finding And Installing Modules
The official modules repository is the main spot where you can find and download ProcessWire modules. On a module’s page, you will find the description and purpose of the module and links to the respective GitHub repository and support forum. Module authors are highly encouraged to post their modules in the official repository because it has the highest visibility and is the place people think of first when they want to find a ProcessWire module.
Installing a module is as easy as dragging the module’s files to the /site/modules/
directory and installing it in the admin GUI. There are other ways to install a module, such as by installing the Modules Manager, which enables you to browse (and install) modules without leaving the admin GUI.
Commercial Modules
While most modules are free, there are a few commercial ones, too. The ones being promoted in ProcessWire’s store are by the lead developer, Ryan Cramer. There you will find the following modules:
- ProDrafts enables you to maintain separate draft and live versions of any page. It also provides a comparison and diff tool, as well as automatic saving capabilities.
- ProFields are a group of ProcessWire modules that help you manage more data with fewer fields, saving you time and energy.
- ProCache (among other things) provides an impressive performance boost for your website by completely bypassing PHP and MySQL and enabling your web server to deliver pages of your ProcessWire website as if they were static HTML files.
Don’t miss the screenshots and videos on the module pages to get a first impression. This is finely executed software.
There are also commercial modules outside of the official website, such as Padloper, an e-commerce platform built on top of ProcessWire. To be fair, what is definitely missing in the ProcessWire cosmos is a way for module authors to easily publish their commercial modules in a centralized spot.
How Do ProcessWire Modules Generally Compare To WordPress Plugins?
The reason why ProcessWire has so fewer modules than WordPress (approximately 400 versus more than 40,000) is not so much because it is less popular (an understatement, of course), but more because the core itself is already so feature-rich that adding a ton of modules to extend it is simply not necessary. For example, you don’t need a module to create a gallery slideshow or to get the first child of something or to generate thumbnails. All of that (and much more) is already covered out of the box.
So, whereas in WordPress your typical method of solving a problem would be to search for a plugin, in ProcessWire you would first look to the tools available in core; in 90% of cases, that would provide you with the solution.
What You Can Build With ProcessWire
Because ProcessWire behaves more like a framework than a CMS (the core is actually a framework, and the CMS is an application built on top of it), the use cases for building things with ProcessWire are pretty broad. You may want to check out some websites powered by ProcessWire (especially the most liked websites).
ProcessWire is a good fit if you want to develop a JSON REST API, an image-resizing app for employees, a front end for managing millions of products (scalability is pretty impressive — you can have literally millions of pages on a single installation), a web application for displaying the financial results of companies, a simple blog, a website for a big university, or just a simple one-page informational website.
Where To Go From Here: There’s A Lot To Discover
Naturally, a beginner’s guide can’t talk about everything the tool has to offer. So, here is a short list of other ProcessWire features, facts, links and tools worth mentioning:
- Check out ProcessWire Weekly and ProcessWire’s blog to stay up to date on the latest news.
- ProcessWire has built-in caching mechanisms (for example, a template and markup cache).
- Wireshell is a command-line interface for ProcessWire based on the Symphony Console component.
- Security is a top priority for ProcessWire.
- Visit grab.pw (isn’t that the coolest domain name ever?) to download the latest stable version of ProcessWire (ZIP file, 10MB).
- ProcessWire has a small and friendly community. The discussion board is the central place to discuss any questions and problems.
- ProcessWire has good multi-language support. The multi-language modules are part of the prepackaged core modules.
- ProcessWire has a transparent roadmap, and development is very active. There is a new minor release nearly every week.
- See what others have to say about ProcessWire in the reviews section and on alternativeTo. There’s also an interesting Quora thread titled “How does ProcessWire compare to WordPress.”
- ProcessWire.tv is a searchable collection of ProcessWire tutorial videos.
Summary
"ProcessWire is a system that rewards you [for] being curious. We aim to show you how to fish so that you can catch the big fish."
This statement by Ryan Cramer, the creator of ProcessWire, encapsulates what ProcessWire is all about.
I think what resonates with a lot of people is that ProcessWire is a system that goes from simple to complex, not the other way around. It doesn’t assume what you want to build, but instead lays a strong, non-opinionated foundation by offering you effective, powerful tools and leaving the rest to you. That conceptual aesthetic has, to me, a certain appeal to it.
Further Reading
- Designing for Content Management Systems
- Why Static Website Generators Are The Next Big Thing
- Content Management System (CMS) Icon Set (12 Free Icons)
- Getting Started With Content Management Systems