Stand With Ukraine. Stop Putin. Stop War.

Update 29/4: Thank you Bert Oost of OostDesign for the tip on supporting different getPage configurations!

If you've ever created custom components, chances are that you have had to create accompanying snippets to actually show the data on the front-end. That can be a lot of work, and once data starts piling up you may want to add some pagination to it. This brief article will explain the requirements that getPage puts on your coding to properly paginate custom objects.

Getting the number of Results

First of all, we will need to tell getPage what the total number of results matching any filters set in place by our snippet is. In our snippet, we can easily set up the xPDOQuery object the way we normally would and take that object to get the total amount of results. No - we don't use getCollection and count() the array - that would be an insane waste of processing time. Instead we use the little jewel called modX::getCount, which is actually extended from xPDO::getCount. This will, without retrieving all the data from the database, get the total number of results for your query. Let's show an example of how we could use this - in this example we look up the amount of resources that have a class of modWeblink or modSymLink and are published:

So that will give us a number in the $total var - but that doesn't tell getPage anything - yet! Having looked at the getPage documentation trying to figure out this part, I've overlooked the answer many times and it is surprisingly simple. The documentation tells us there's a totalVar property:

And that's our answer. We need to set a placeholder, of which the key matches the value of the totalVar property: by default that's "total", though users have the ability to change this in their getPage call, so we'll need to get the totalVar property and set a placeholder with that name. Let's update our example accordingly to set the placeholder and that's all there is to it.

Starting at the right offset

Secondly we will need to make sure our snippet understand which results to display - and that it passes this on to our xPDOQuery object. In this case all we need to do is lookout for two properties: limit and offset. Limit will be set by getPage to the &limit property, which indicates how many items to show at once. The offset will be calculated based on the "page" request and the limit per page.

If we would update our example, we could end up having this - which works perfect with getPage for pagination.

You may notice a few important things:

  • We get the total amount of results, and set the total placeholder *before* we limit the query. While the docs say it may ignore the limit property, I like to be sure.
  • We use modX::getOption() (extended from xPDO::getOption) to get the "limit" and "offset" properties from our scriptProperties array available in snippets. If it does not exist we assign default values of 10 and 0 respectively.
  • We use xPDOQuery::limit() to set the limit and offset to the query. We then pass that on to our getCollection call and be on our way to process it further and give the site visitor what they want.

Hopefully this brief article will help more developers making their snippets getPage-proof, which will make it easier for front-end developers to use one tool (getPage) for all their pagination needs. Please feel free to share your thoughts and suggestions below!

I develop a number of MODX Extras, both open source and bespoke code, which I typically build on the latest stable release. Using a build script the code is transformed into a transport package, which by default ends up in "core/packages" of the MODX installation. This short how-to will explain you how to adjust your build script and project setup and stay in control of your packages.

My Localhost

Now, before I go into detail on how to make this ridiculously easy change, I want to briefly discuss my project set up as that is of course a vital part of staying in control of your data. I've found this works for me, but of course different developers will have different strategies.

All my files are accessible via http://localhost/, ie they are in the "www" folder of WAMP. In there I have a number of MODX installations of various versions. These are for development & testing of stuff I develop and act as a source of documentation as well. On the same level (so immediately under "root") I have a folder called "projects". So to recap, we've got this:

  • www
    • modx-1.0.5
    • modx-2.0.8
    • <...>
    • modx-2.1.3
    • modx-git
    • projects

This allows me to keep my MODX installs totally separate from my project files. Using system settings I then "link" my project into the MODX install I'm developing that project in, and we're set (possible a more extensive blog post on that later!). If I break a MODX install or otherwise screw up, I can simply delete all the files of that install and start over.

In my projects directory I have one directory per project, which in 99% of the cases is also a Git Repository (Like VersionX2, or HandyMan). In there I have a _build, core and assets directory with the right contents - I assume you're familiar with that if you're reading this article.

The Problem..

When I develop a lot of addons, or make a lot of builds, all these are added to the core/packages directory of the MODX install I linked my package to (through a config.core.php file). May be fine if you then want to install the package there, but I don't to keep my links pointing to my own files. And after some time it gets tough to find that one package in between one of the other 100's..

What I want is store packages in a _packages dir in my project Git repository so I instantly know where a package should be (in the projects dir) and as an added bonus the package is also uploaded to Git - giving an easy way to distribute it for people that do not know how / don't want to run the build but do want to check out development.

Aha! The Solution!

In a random moment where I was again browsing into the MODX install dir to get a package, I decided to check out the modPackageBuilder class API docs.

As often is the case, this problem had already been foreseen and there is a very easy way to change the directory the files and transport zip are outputted to. It's so easy, it would have fit in a tweet - but how much fun would that be? So that's why you''ve been reading this blog.

Oh you want to know how now you got this far?

Okay.

Let's say this is part of our regular build script:

That's where it instantiates the modPackageBuilder class. So that's where we'll want to tell it where to output to. We'll be using a public property of the modPackageBuilder for that: $directory. Hah, bet you didn't see that coming!

So let's just make that single small adjustment to our build script that you've been reading this for..

We're simple traversing up two directories (first we're in _build, then we go up to the root, and lastly add _packages to it, putting it in our all new special directory :)

Now hold on.. what about all those files?

Yes - the package builder also creates a lot of files (that's what gets zipped up, actually) and we probably don't feel the need to upload all that to our git repository. To fix that, we'll create a real simple .gitignore file and put that in our _packages directory.

It will ignore all folders, but not files in the root (our transport package).

And that's it folks. :) Thanks for the masterminds Shaun & Jason for thinking of stuff like this ahead of time!

There is something, well, maybe not magical, but certainly productive about using xPDO queries within MODX as opposed to using plain SQL. I've created a really simple snippet which fetches children of a resource (if any) and outputs them in an unordered list. And this took no more than a few minutes to pull off.

Before getting started

You may be wondering what xPDO is. If you've not wrote custom code in MODX Revolution yourself yet, I can imagine the term might not sound familiar. xPDO stands for "open eXtensions to PDO" and it has been developed by part of the MODX Core Development team to provide an Object Oriented Programming approach to relational databases built upon PDO - a core function of PHP > 5.1. At the same time, it also provides (although slightly limited) support for PHP versions under that.

Anyway - that's not what I wanted to explain in this article. This article is about how you can use xPDO within MODX to easily create custom snippets which are very easy to read, fast to execute and can be customized at will without spending years learning a special language - it's all PHP.

getChildren

I designed this snippet cause I needed a simple way to output an unordered list of children of the current resource, but where using an existing addon (like getResources or Wayfinder) would feel like overkill. Of course they both have their own advantages compared to using this custom approach, but I'm being given the power to use this by MODX, it's probably faster (I didn't test it - but just have a look at the lines of code getResources uses and what my snippet uses) and I wont be touching it often after developing it anyway.

This is the actual snippet I'm using:

It's commented line by line, and those familiar with PHP will see what it does in an instant. There's a few things I'd like to point out in this case though:

  1. The script starts off with calling the $modx->resource->getMany('Children') method. What this does is tell MODX to use the current resource, and find associated children based on that resource.
  2. On line 6 shows the modX::getOption (inherited from xPDO:getOption) method, which is considered best practice to get settings and properties from in MODX Revolution. It accepts three parameters:
    1. (string) name of the option (setting, property) you want to retrieve. In this case I'm looking for the tpl parameter.
    2. (options array) variable name you want to get it from. Within snippets you'll use $scriptProperties.
    3. (string) default value if there's no value found for the option name. In this case I set it to an empty string.
  3. When it starts going through each of the children found, it first sets an array with the different resource fields I want to have available in my template chunk, and get the value using the ->get('fieldname') method. When it has all the data in the $out array, it will take those fields and use $modx->getChunk($chunkname,$placeholders) to populate the template with the placeholders, and in turn add that output to the $o variable.
  4. Lastly, it finishes the outer markup and returns the output to the snippet call.
Now let's look at the tpl chunk.

The chunk is really straight forward. It creates a list item element, adds in an anchor (hyperlink) tag and uses the placeholders that are set. It also uses the link tag syntax to create a link and the "default" output filter, which sets the value of the placeholder to what's included in the `` quotes if the placeholder value is empty. So in this case, that acts as a backup in case I didn't set a menu or a longtitle (assuming there will always be a pagetitle).

What remains now is showing you how to call it (assuming you named your Snippet getChildren, and your chunk getChildrenTpl):

Conclusion

Don't be hesistant to coding your own snippets - xPDO and the MODX api makes the most common tasks ridiculously easy. This snippet took a couple of minutes to make and by spending a couple more minutes you could improve it easily to also use an outer template instead of mixing PHP and HTML... but it suited my needs as it is :)

What do you think about using custom coding in your development?