Stand With Ukraine. Stop Putin. Stop War.

Have you ever had a client asking for showing a list of related articles or news items? Chances are you've applied a technique to show a list of all articles in a Template Variable, allowing the client to handpick the ones that are related. This is a great technique and I have written about it in the MODX Documentation, but the admin or editor still has to manually pick what is related. Surely there's an automated way as well?

Back in fall 2011 I was contacted by Vierkante Meter, a Dutch web agency focusing on accessible websites, with exactly that request: a way to automatically show related articles. Some time later getRelated was born as the answer to their questions as well as that of many other developers. I've even deployed it on my own site! Just look a the "Related Articles" block to the bottom right of this post (not visible on mobile for now).

getRelated is very powerful, but, if I can say so myself, still very easy to use. It can be installed via the MODX Package Manager and from there you just need to call the snippet in your template - and it's there! But of course, the power is in the details..

What makes getRelated awesome

(More information about the aspects mentioned below can of course be found in the getRelated Documentation.)

#1: Configurable algorithm.

getRelated checks out the resource it is called on (or the resource you specify with &resource=`ID`), and identifies unique words in the fields you specified, and it uses those to find matching resources. To come up with the order in which they are returned, it specifies a value for every field. A value of 5 means that every matching word in that field is rewarded with 5 points added to the total. At the end of the processing cycle it sorts the results by the amount of points rewarded.

By default it only looks at the pagetitle and introtext, but by simply specifying the &fields property you can tell it what fields to use and how valuable they are. According to the docs:

Comma separated list of fieldname:weight to use in the comparison. Prefix TVs with "tv.". Don't use the content unless you want to kill performance. Example of use: pagetitle:3,tv.MyTags:7,tv.MySubjects:15,introtext:2

That's a lot of information in only a few lines, but it tells you how to define the value of each field, and that you can even use TVs for them. To show how that works, here's the &fields property used on my site:

&fields=`pagetitle:6,longtitle:4,introtext:2,tv.mh.categories:12`

The most value is assigned to the "mh.categories" template variable: it's what I use to categorize my posts in 2 or 3 categories each, such as front end development or ExtJS. The "12" means that every category is worth 12 points when it matches on a different resource. So if another article has one category in common it scored 12 points. Every matching word in the pagetitle is worth 6 points, longtitle gets 4 points per matched word and the introtext gives 2 points. By defining all of that in the &fields property you can pretty much define your own algorithm for finding related pages automatically. You may use both categories and tags, so you could give categories a higher value compared to the tags to get the most accurate results.

#2: Completely configurable output

Besides the ability to specify, you are able of completely configuring how your related resource is shown. The default is a h3 tag and an unordered list with the top 3 related resources. But using the &tplOuter and &tplRow property you can change it to your hearts content. 

As performance is a big priority with a tool like this, it only sets placeholders for the fields you specified, and as of the 1.1 release (for MODX 2.1+) it also allows you to use TVs in the output. Just specify the resource fields (ie pagetitle, introtext) in the &returnFields property and the TV names in &returnTVs. Again, for speed it only gets the TVs for the top ranking results, so no performance is lost. 

For example, this is a screenshot from a current project (a jewellery webshop) of mine, which uses getRelated with returnTVs to show related articles. 

And the getRelated snippet call:

[[getRelated? 
    &limit=`15` 
    &fields=`tv.product.tagline:9, tv.product.colors:4, tv.product.materials:6, tv.product.stones:6` 
    &returnTVs=`product.images,product.articlenr`
    &tplRow=`getrelated.row`
    &tplOuter=`getrelated.outer`]]

The match is completely defined on TVs used for products: the tagline, colors, materials and stones. Here's the getrelated.row chunk:

<li class="related[[+idx]]">
    <a href="[[~[[+id]]]]" title="[[+longtitle:default=`[[+pagetitle]]`]]">
        [[+product.images:getFirstImage=`product.firstimage`]]
    </a>
</li>

The getFirstImage custom snippet is used to get the first image: the product.images TV uses MIGX to allow unlimited amount of images. The custom snippet uses the following chunk to show the image (product.firstname chunk):

<img src="[[+image:phpthumbof=`w=120&h=120`]]" width="120" height="120" />

#3: Excited client!

Mark has developed a MODX snippet named getRelated for us.The snippet works really well and came with even more features than we asked for. Mark also provided comprehensive documentation.

We got to know Mark as a friendly guy, always prepared to answer a question or help out with a problem. We are very happy with his work and would hire him again without a doubt.

Michèlle van Vlerken-Thonen, January 20th, 2012.

#4, #5, #6 etc: More possibilities!

Use the &parents, &includeHidden, &hideContainers, &contexts, &exclude and more properties to decide which resources to include or not. 

Spotted in the wild!

We've just hit 650 downloads (well, okay: 647, but close enough!) of getRelated so far, I am very interested in seeing how people have been using it! Feel free to leave a link in the comments to show how you're applying it... I may feature the most impressive uses here as well!

Sepia River MODX

Hey Mark! I just used the getRelated snippet along with your getPagetitle snippet from the post on caching :) You can see it on my blog, but also I made a tutorial post about it, with ample (many, numerous) links back to you :) Thanks for some great snippets!!
P.S. how about putting getPagetitle in the repo?

Mark Hamstra

Thanks for your blog (for others interested in his take, you can find it here: http://www.sepiariver.ca/blog/modx-web/related-posts-plugin-for-modx)

I'll add your blog to the list of getRelated spotted in the wild, too :)

As you said in another comment somewhere, getPagetitle is pretty similar to getResourceField, so I don't see the real value of creating a transport package out of it when there's already an extra with many more features.

Sepia River MODX

Right...you can use any snippet as an output modifier. I forget how to add the snippet properties but I'm sure I can find it. Once I actually used getPagetitle though, I loved how quick and easy it was :)

You're really producing a lot of amazing work, Mark. I'm sure you've heard it already, but #justsayin

Sepia River MODX

P.S. Your category links seem to be broken. This URL for example: http://www.markhamstra.com/modx-blog/category/Front-end+Development/ returned 404.

Mark Hamstra

Well, you can also just use the snippet as a snippet, hehe.

Congrats on creating your first snippet with xPDO by the way! :)

And thanks :) Just doing my bit to make the life of other MODX devs easier ;)

Sepia River MODX

Can getResourceField query the parent resource from inside the tpl for getRelated?!? So, (I don't know the proper terminology) but getRelated sets the "context" in which getResourceField will look for the parent ID to grab a field from?
This sounds confusing but do you know what I'm asking? I'm surprised if this is how it can work!!

Mark Hamstra

Make sure to include the parent field in the &returnFields property, and then just use this in your template:

[[getResourceField? &id=`[[+parent]]` &field=`pagetitle`]]

Sepia River MODX

Awesome, Mark!! Pizza's on me!

Shaun Morrison

Hi Mark

Can't believe I missed this plugin until now – it's great!

I only have one question: I have a getRelated call that includes
&fields=`tv.categories:9,parent:8,longtitle:6,pagetitle:5`
tv.categories is a series of checkboxes to tell you which categories that resource belongs to. [[*categories]] outputs the ID of the category resources that have been checked. Unless exactly the same categories have been checked then getRelated doesn't seem to see two resources as related even though they may have one or two categories in common.

e.g. 'Page 1' may have category IDs of '12,17,21' and Page 2 may have '12,17,34', but because there is a difference in the last ID getRelated doesn't see it as related at all. Behaves like it treats it as one long string rather than an array with three values. Am I doing something wrong?

Many thanks,
Shaun

Shaun Morrison

Gosh, sometimes I'm really silly. Forgot to set the 'categories' TV output to delimeter ',' – what a moron.

getResources actually works perfectly (however the person implementing it clearly needs more sleep).

Thanks again!

Shaun Morrison

Obviously I meant getRelated works perfectly!

Comments are closed :(

While I would prefer to keep comments open indefinitely, the amount of spam that old articles attract is becoming a strain to keep up with and I can't always answer questions about ancient blog postings. If you have valuable feedback or important questions, please feel free to get in touch.