MODX : Using getCollection or “Getting stuff fast, really fast.”

getCollection in MODX

The more I learn about MODX and coding in general, the clearer it becomes that there are so many ways of doing the same thing. As the Vorlons from Babylon 5 say, “Truth is a three edged sword. Your side, my side and the truth.” I think with doing any sort of coding that sword has somewhere upwards of several thousand edges.

Lately, I’ve been working on increasing speed and building faster ways of doing the same thing. While a lot of MODX veterans or experienced PHP coders will have done this in the past, hopefully this will give those learning beyond the basic concepts a jump-start in building their own custom Snippets.

Lets say you want to build a set of press releases for your site. You have an overview page, and maybe you have them all listed underneath the overview page in the document tree or you’ve installed the awesome “Collections” tool to keep them organized. (Check back here! We’re going to be talking about the Collections tool soon!)

On your overview page you’ve placed a getResources snippet like this:

1
2
3
4
5
6
7
[[getResources?
&parents=`53`
&tpl=`tplPressReleaseLine`
&limit=`0`
&sortby=`publishedon`
&sortdir=`DESC`
]]

With your tplPressReleaseLine chunk looking something like this:

1
 

[[+longtitle:notempty=`[[+longtitle]]`:default=`[[+pagetitle]]`]] – [[+publishedon:strtotime:date=`%A, %B %e, %Y`]]
[[+introtext:notempty=`[[+introtext]] `]]

Here is an alternate way of doing things that is extremely fast, and contains everything inside a single snippet.

getCollection is a MODX function that allows you to get an array of objects meeting whatever criteria you set down. Once you have your array you can manipulate it however you see fit.

We are going to use MODX’s getCollection to grab everything we need and walk the data back through a foreach loop, outputting our press releases.
First lets look at the completed snippet, “buildPressReleases”, before breaking it down.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<!--?php //clear the output $output = ''; //the Parent ID of where your press releases are $ids = $modx-&gt;getChildIds(53);&lt;/p&gt; &lt;p&gt;//Start defining your criteria&lt;br ?--> $criteria = $modx-&gt;newQuery('modResource');
$criteria-&gt;where(array(
'id:IN' =&gt; $ids,
'published' =&gt; '1',
'template' =&gt; '7'
));

$criteria-&gt;sortby('publishedon', 'DESC');

//Get your array of objects using getCollection
$pressReleases = $modx-&gt;getCollection('modResource', $criteria);

//Now walk through the array
foreach ($pressReleases as $pressRelease) {

//check to see if we have a longtitle
$title = $pressRelease-&gt;get('longtitle');
if (empty($title)) {
$title = $pressRelease-&gt;get('pagetitle');
}

//Make our date pretty
$date = strtotime($pressRelease-&gt;get('publishedon'));
$prettydate = date('F j, Y', $date);

//See if the introtext is blank and add a nonbreaking space
$introtext = $pressRelease-&gt;get('introtext');
if (!empty($introtext)) {
$introtext = $introtext . ' ';
}

//put the pieces all in place, including the link
$output .= '
<strong>'
. $title . ' - ' . $prettydate . '</strong>
'
. $introtext . '<a href="' . $pressRelease-&gt;get('uri') . '" class="readMore">Read More</a>

'
;
}

return $output;

It is fast and elegant. So lets look at each step of the process to understand what happens.

1
2
3
4
5
//clear the output
$output = '';

//the Parent ID of where your press releases are
$ids = $modx-&gt;getChildIds(53);

This ensures we have a clean and empty output before using getChildIds. As it is written here, it will get an array of IDs that reside under document number 53. As there are no conditions, it will grab everything no matter how deep it is in the the document tree. There is no sorting done here.

1
2
3
4
5
6
7
8
9
10
11
12
13
//Start defining your criteria
$criteria = $modx-&gt;newQuery('modResource');

$criteria-&gt;where(array(
'id:IN' =&gt; $ids,
'published' =&gt; '1',
'template' =&gt; '7'
));

$criteria-&gt;sortby('publishedon', 'DESC');

//Get your array of objects using getCollection
$pressReleases = $modx-&gt;getCollection('modResource', $criteria);

This is where we get what we want! However, there are still a few things we need to do. First, set up a new query in the $criteria. Next we are going to ad a few conditions into it. We only want our array to have objects that meet three conditions:

  • The id is IN our array we have in the previous step.
  • That the document is published
  • Finally that it is using template number 7, The template for a press release

Finally, we want all this sorted by the “published on” date in descending order. This will show the most recent first. Once our criteria is set up we do the getCollection call. It is important to remember that what we have now is an array of objects sorted by the criteria we set up. If you need to turn it into a regular array, you will need to use the “toArray()” command on each object.

An important word of caution here, if you need your query to exclude things like deleted, hidden from menu or other parameters you have to tell it. This way will grab everything meeting your parameters, ignoring the rest.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
foreach ($pressReleases as $pressRelease) {

//check to see if we have a longtitle
$title = $pressRelease-&gt;get('longtitle');
if (empty($title)) {
$title = $pressRelease-&gt;get('pagetitle');
}

//Make our date pretty
$date = strtotime($pressRelease-&gt;get('publishedon'));
$prettydate = date('F j, Y', $date);

//See if the introtext is blank and add a nonbreaking space
$introtext = $pressRelease-&gt;get('introtext');
if (!empty($introtext)) {
$introtext = $introtext . ' ';
}

//put the pieces all in place, including the link
$output .= '
<strong>'
. $title . ' - ' . $prettydate . '</strong>
'
. $introtext . '<a href="' . $pressRelease-&gt;get('uri') . '" class="readMore">Read More</a>

'
;
}
return $output;

This is where we walk through the array. It uses some basic PHP.

As a practice, we use the longtitle field as the headline of the page or a longer more SEO friendly title. The pagetitle field is  used  primarily in the manager to make clear what the page is. But it is important to always have a fallback just in case the longtitle is not set for some reason. That is what we check first. We get the longtitle from the object. If that is empty, then we grab the pagetitle.

Next we pretty up the date. Grabbing the date from the object and using the strtotime command, follow that up with the PHP date function to display it in a more friendly format.

Then lets see if we have some introductory text. If there is, add a non breaking space after it. This will keep our read more link from breaking strangely if the copy gets close to the edge.

Lastly, in each loop lets build our HTML from each piece we have created. Here, I am getting the uri from the object in the link. In most cases this will work, but if you need to create a full http/https link you can always add another step and use MODX’s makeURL function.

After we have stepped through each array entry, you simply return your output variable to the page.

Hopefully, this is just a starting point for you to jump off from when exploring more ideas of how to manipulate content in differing ways. You can modify this technique and add additional conditions to perhaps grab all the press releases for a year, or building a blog style Previous and next function for your documents. You can see a front end example of this here . A variation of this code is what runs the Arketi Press release overview page, with additional sorting by year built in. This snippet is called uncached, and just look at the speed!

The best advantage of MODX is that it lets you choose, build and manipulate your content in the way that works best for your site and structure. Can you use the basic getResourses way? Sure. Build your own custom snippet that’s fast? Sure! You can even do something else entirely.

Resources

Bob’s Guide – Understanding MODX Revolution Objects and xPDO

Bob Ray wrote the book on MODX. Literally. It’s an invaluable Resource.

Documentation for getCollection is here.

Do you have any unique ways of manipulating your MODX? Leave a note and let us know!

By Charles Askew – February 17, 2015

--

Email Charles Askew | Read more posts by Charles Askew

Posted in : Website Development and Design

2 Responses to “MODX : Using getCollection or “Getting stuff fast, really fast.””

  1. YJ Tso Says:

    Great post! It’s so helpful to show these techniques to those who may not know about them :D

    One thing to add, is that with MODX it’s so easy to separate content from logic etc by using `$modx->getChunk() or parseChunk()`

    So in your example above, you could setup some options at the top, for customizability:

    1
    2
    $tpl = $modx->getOption('tpl', $scriptProperties, 'tplPressReleaseLine');
    $outputSeparator = $modx->getOption('outputSeparator', $scriptProperties, "n");

    Then on line 41 at the end of the foreach block, you could have this:

    1
    2
    3
    4
    5
    6
    $output[] = $modx->getChunk($tpl, array(
      'title' => $title,
      'prettydate' => $prettydate,
      'introtext' => $introtext,
      'uri' => $pressRelease->get('uri'),
    ));

    And then after the foreach loop when you return:

    1
    return implode($outputSeparator, $output);

    In your TPL chunk you would have:

    1
    2
    <h3>[[+title]] - [[+prettydate]]</h3>
    <p>[[+introtext]]<a href="[[+uri]]" class="readMore">Read&nbsp;More</a><p>

    Another advantage of this besides separation of concerns is that you can re-use the Snippet with different output for different views. You can include all “standard” Resource fields if you go like this on line 18 before you call getChunk:

    1
    2
    3
    4
    5
    6
    $fields = array();
    $fields = $pressRelease->toArray();
    $fields['introtext'] = $introtext; //override with processed value
    $fields['title'] = $title;
    $fields['prettydate'] = $prettydate;
    // uri field is available as part of $fields by toArray()

    Then when you do call getChunk it’s just this:

    1
    $output[] = $modx->getChunk($tpl, $fields);

    There’s always many, many ways to do it, as you so accurately say in your article. Thanks again for this post!!!

  2. ????? ???????? Says:

    > [[+longtitle:notempty=`[[+longtitle]]`:default=`[[+pagetitle]]`]]

    This should be reduced to

    [[+longtitle:default=`[[+pagetitle]]`]]