ProcessWire caching explained

ProcessWire CMS / CMF is fast, even when dealing with large amounts of data. By learning the basics of built-in caching methods you can make it even faster.

I won't go into too much detail about caching in general at this time. I'll assume that you're already at least remotely familiar with the term itself and it's use in the context of web development.

Methods described in this post are all strictly related to caching markup generated by ProcessWire. There are many different caching methods for many different situations (such as opcode cachingmemory object caching and HTML5 application cache just to name a few) out of which methods mentioned here are just one tiny fragment.

Does caching markup matter?

Yes, it does. How much of an effect it will have on your site depends on multiple factors, though.

Below you can see test results from Apache Bench with 100 requests (10 concurrent) on a brand new ProcessWire 2.3.0 installation running Skyscrapers profile on an entry level Linode virtual server:

Template CacheTotal test timeminmeanmedianmax
Enabled7.956 seconds393 ms772 ms354.5 ms3472 ms
Disabled32.445 seconds1050 ms3148 ms3178 ms5680 ms

These figures show a tremendous difference between Template Cache being enabled and disabled, though like already pointed out above all this depends a lot on what kind of things your site is doing  and how much data it contains -- this site you're visiting right now, for an example, didn't benefit nearly as much from template caching, there being very few expensive queries / calculations going on behind the scenes.

Caching methods in ProcessWire

There are two main options at your disposal right from the start. I'll refer to these as Template Cache and Markup Cache. Both have valid use cases, though it's quite possible that you'll find Template Cache enough for all of your caching needs.

Template Cache caches whole templates exactly as they're rendered and Markup Cache is used for fine-grained caching of smaller, resource-intensive parts of your templates. Another notable difference is that Template Cache can be enabled via template settings GUI (in Admin) while Markup Cache is triggered at template file level by directly calling the MarkupCache module when and where needed.

There's also a third option called ProCache. That's an entirely different beast in two ways: first of all it's a commercial module provided by guy behind ProcessWires awesomeness (Ryan Cramer) and second of all it actually skips both PHP and MySQL, serving cached pages directly from disk via htaccess magic.

This article is about native ProcessWire caching methods so I'm not going to dig in any deeper into ProCache here, just thought it'd be important to mention as an option. If you're interested in it, take a look at ProCache in ProcessWire modules directory.

Template Cache

Template Cache is easy to set up and use. As mentioned above, it's used to cache whole pages exactly as they've been rendered -- and most of the time it's all your site actually needs.

When a page is being rendered, a module called PageRender kicks in, checks if caching is enabled and if it is, either returns existing, pre-generated (ie. cached) markup or generates such markup, saves it as a file to /site/assets/cache/Page/[current-page-id]/ directory and then returns it. This all happens behind the scenes and you don't really have to worry about it at this point. (Knowing how this stuff really works can be quite useful when debugging things, though.)

You can find settings for template cache by opening one your templates for editing within Settings area of Admin: Admin > Setup > Templates. Template cache is turned on by setting cache time (in seconds) to anything above zero.

For how long you should cache your templates depends on what that particular template is used for, what kind of content it has, does it pull some of it's content real-time from other sources, how often should this content be updated etc.

Long cache time isn't that important, unless your page is very slow to generate (and if that's the case, it might be worthwile investigating and fixing related problems first -- cache should never be used as an excuse for slow and/or broken code.) Generally speaking an hour should be enough for almost any condition and 5-10 minutes is a good option too.

Just for the record: I've been using a timeout of 5-10 minutes on pages with more dynamic content and anything between an hour to a day on templates related to pages that are very rarely updated.

After setting a timeout, you can also specify conditions on which cache is automatically invalidated; for an example you can (and probably should) specify that when pages with this template are saved, cached versions are instantly removed.

Possibly the biggest "gotcha" here is that if you turn cache on for templates that do dynamic stuff based on GET / POST requests, such as "Search", you'll have to specify variables that override cache yourself.

Miss this step and your search page, just as an example, will show same results for all queries, ie. fetch cached version regardless of it being called with different search query. Since that's not very useful for anyone, you can specify GET param "q" (on default search template) as "Cache disabling GET variable" for Search template to avoid this. (There's an input for this at the bottom of cache settings screen.)

This is pretty much everything you need to know in order to start using Template Cache. Certain things, such as rendering pages via other pages using a dynamically attached view, can cause a bit of confusion, but when you're doing that you've probably already got the experience to solve issues like that.

Next we'll cover basics of Markup Cache.

Markup Cache

Markup Cache is used for caching specific parts of your templates and using it requires some (simple) PHP code:

// get instance of MarkupCache
$cache = $modules->get("MarkupCache");

if (!$data = $cache->get("breadcrumbs")) {

    // "breadcrumbs" not found from cache
    $data = "<div id='breadcrumbs'>";
    foreach ($page->parents as $parent) {
        $data .= "<a href='{$parent->url}'>{$parent->title}</a> › ";
    $data .= "{$page->title}</div>";

    // save $data to cache as "breadcrumbs" (MarkupCache remembers the name
    // we gave with our previous $cache->get() call)


// output final markup (at this point it doesn't matter whether or not it
// originally came from cache)
echo $data;

By default cache is stored for an hour. To specify shorter (or longer) cache time, you'll need to give that as second parameter to get:

// cache for 5 minutes
if (!$data = $cache->get("breadcrumbs", 300)) {
    // etc.

As you can see, it's a bit more work than Template Cache, but it can be used in certain situations where caching whole page is out of question. For an example when your page contains ads or other dynamic content (as in "changes on every page load") you can still cache parts that are especially expensive resource-wise without affecting how those ads etc. are rotated.

Behind the scenes Markup Cache works just like Template Cache, only difference being that cache files are generated by module called MarkupCache and only when directly asked to do so. Cache files are stored in /site/assets/cache/MarkupCache/, under a directory specified by name given by you in the $cache->get() request (example above would create cache file /site/assets/cache/MarkupCache/breadcrumbs/breadcrumbs.cache.)

That's it, folks

If I'm missing something important here or something just didn't make sense, please don't hesitate to leave a comment or send me an email.

If you're already a ProcessWire user or interested in becoming one, I'd suggest registering at ProcessWire forum (unless you already did, that is.) We're always happy to see new faces around :-)

About the author



Posted by anon on Wednesday 7th of August 2013 15:38 pm

Very nice and easy to understand write-up of ProcessWire caching capabilities.


Posted by everfreecreative on Thursday 22nd of August 2013 20:07 pm

Thanks for the run down on this. Very helpful.


Posted by Sam on Friday 28th of March 2014 19:43 pm

Thanks for sharing this! PW is quite fast without caching, but with a cache you can get the last ms out of it :-)


Posted by Romaaan on Tuesday 24th of June 2014 12:27 pm

> By default cache is stored for an hour. To specify shorter (or longer)
> cache time, you'll need to give that as second parameter to save:"

No, to get:
```if (!$data = $cache->get("breadcrumbs", 300)) {```


Posted by teppo on Friday 27th of June 2014 17:17 pm

Thanks for pointing that out, @Romaaan! No idea what I was thinking while writing this. Corrected that on the post to avoid any further confusion :)


Posted by Darren on Friday 9th of January 2015 20:49 pm

Does ProcessWire's template cache query the database if there's an already existing cached page or does it completely bypass mysql?

Office benching in miami

Posted by Office benching in miami on Wednesday 18th of February 2015 17:22 pm

You’ve written nice post, I am gonna bookmark this page, thanks for info. I actually appreciate your own position and I will be sure to come back here. Office benching in miami


Posted by geoff on Wednesday 13th of April 2016 11:55 am

if anyone is looking for remote ruby on rails jobs? please check out http://webwork.io


Posted by Maya on Wednesday 6th of July 2016 16:13 pm

Thanks for sharing this Post, Keep Updating such topics.


Posted by Madhuri on Saturday 9th of July 2016 16:05 pm

Thanks for share this Post to communicate all member to each other and get best ideas and tips on any topics for better knowledge.

Post Comment