*UPDATE[2019/01]: There's a new MODX Extra that is designed from the ground up to be more accurate and flexible—able to handle the "Most Popular Pages" use case plus a whole lot more. Check it out here.
If you've ever wanted to display a list of Most Popular pages or blog posts on your MODX CMS site, you either wrote your own PHP Snippet or you used this method using HitsPage. But now, there's a New Kid in Town...
Hits is written by MODX core team alumni @jpdevries. How it differs from HitsPage is that instead of storing hits in a TV, it uses a custom database table. The implementation is fast and easy: call the Snippet one way and it logs hits against Resource IDs; call it another way and it outputs the IDs with the most hits. Feed that to getResources and you're done.
- You can install it via Package Management in MODX Revolution.
- You can also download the package here
- There's no docs for it in the official docs yet, but the Snippet itself gives you all the usage examples you need. One caveat: as of version 1.2.0 there's a couple of errata so I'm gonna run through the setup in detail here.
Record Your Hits
This part is ridiculously easy. Somewhere in the Template of every page on which you want to record hits, call the Snippet like this:
That's it. That records a hit for the current Resource every time it is requested.
Show The Most Popular Pages
There's two (very easy) steps to this. First you call the Hits Snippet again, this time to list the IDs with the most hits:
[[Hits? &parents=`2,6,10` &limit=`3` &outputSeparator=`,` &chunk=`hitID` &toPlaceholder=`hits` ]]
Break it down:
- &parents=`2,6,10` » An arbitrary, comma-separated list of Resource IDs, the child Resources of which will be queried for hits. This allows you to limit the scope of the popularity contest to certain sections of the site. If you leave it empty it uses the parent of the Resource on which you're currently calling the Snippet.
- &limit=`3` » This just tells it how many results to return.
- &outputSeparator=`,` » If you're feeding the results to another Snippet, like we are, this makes the output comma-separated.
- &chunk=`hitID` » This is the output template (see below).
- &toPlaceholder=`hits` » This sends the results to a placeholder that we can use in our getResources call (again, see below).
The "hitID" chunk contains only this:
[[+hit_key]]. This represents the ID of the Resource being queried. The getResources call will now "get" the Resources with the most hits, like this:
[[getResources? &parents=`-1` &resources=`[[+hits]]` &tpl=`myPostTpl` ]]
Break it down:
- &parents=`-1` » This tells getResources to not even look for parents. The Hits Snippet already did that for us. This has the nice side effect of making the getResources query quite fast (more on that later).
[[+hits]]` » We do need to tell getResources which Resources to "get". This property is populated with the value returned by the Hits Snippet, because we've put the placeholder
[[+hits]]in there. So it's gonna get the Most Popular Resources.
- &tpl=`myPostTpl` » A required property of getResources - the chunk to use as the output template.
And we're done! We don't even have to tell getResources to limit the results because the Hits Snippet only supplies the number of IDs that we want to the &resources property. There's a few other options for Hits, like if you want to list the least popular pages, or if you want to offset the results so you're showing some "medium" popular pages ;)
The downside of this setup is that, because it's not storing values in a TV, you can't use the getResources TV filters, so it's a little bit less flexible. However, the big bonus is that it's considerably faster - 20% faster by my tests, but potentially more. That's because all those TV queries are actually quite slow. An efficiently designed custom table will win on speed over one designed for infinite configuration. That's the cost of flexibility sometimes.
So there you have it. Now go make something awesome with MODX - that's what it was made for :D