Tips &amp; Tricks - MODX Community Forums <![CDATA[HowTo: Add Tagger Column to Collections List]]> addon. I also used the Tagger ( addon for it’s relative ease in setup and usage. One thing I wanted to do was add a column in the Collections product list that showed the tags that were assigned to each product. It turns out, this was pretty easy.

Step 1 - Add Column
Go to Extras -> Collection Views and open your collection. Click the Add Column button and enter your label (I used “Categories”). For the Name, I just entered an unused field (which for this setup, happened to be “published”). Collections evidently only allows you to use each field once in the columns list.

In the Snippet Renderer field, add the name of your snippet - I used “collections_getCategories”, but this can be anything.

Step 2 - Create Snippet Renderer
Create your snippet using the name you entered in the Snippet Renderer field and add the following code:
$row = $modx->getOption('row', $scriptProperties, '');
$tags = $modx->runSnippet('TaggerGetTags', array( 
'rowTpl' => 'collections_taggerRowTpl',
'resources' => $row['id']
) );

return $tags;

Save your snippet.

Step 3: Create the rowTpl Chunk
Create a chunk and name it “collections_taggerRowTpl”. Place this in the chunk:
[[+tag]]<br />

Save your chunk and that should be it! Hope this helps.]]> Sun, 24 Mar 2019 07:29:47 +0000
<![CDATA[New in 2.2.1: Session-less Contexts]]> read about it here.]]> Sat, 23 Mar 2019 02:25:53 +0000 <![CDATA[TV dropdown list: select COUNTRY => get list of CITIES]]>
MODX Revolution 2.2.10-pl (traditional)

I'm stuck with problem-

I have two TV for the template: COUNTRIES and CITIES.

How can I pull all cities names depending on COUNTRIES TV selection (dropdown list input type both)?

Another words- I choose country name and get all cities in there as a dropdown list in COUNTRIES TV.

Thank you for all the ideas and solutions!]]> Mon, 18 Mar 2019 07:39:29 +0000
<![CDATA[TIP: use MIGX to build your own content builder]]>

Using this technique, you can build your own content builder that functions very well. You can build your own layouts, fields, etc and use chunks to display them. I find it cleaner and leaner because I have specific needs, that I can build for. It's perfect. Thanks Bruno!]]> Sat, 09 Mar 2019 10:11:47 +0000
<![CDATA[TIP : staging or cloning MODX install on cPanel stuck : running setup solved]]>
I've been stuck recently after having clone my MODX install with cPanel.

I could log ine the manager.
The public part of the website was OK. But in the manager, there was a lot of things where'nt loaded an nothing was usable. I had some "undefined?action=" xhr requests...

I get this solved by re-run the setup process on my cloned install.

Hope it can help as re-running setup is always a good thing to do with MODX when encoutering weird things in the manager part smiley]]> Tue, 05 Mar 2019 07:00:11 +0000
<![CDATA[TIP : Easily add widget with css and/or js without chunk]]>
I'm practicing Modx for about 6 or 7 years, and don't ask me why but this morning I made something I was needing so many times... Adding a little html element with his dependencies. Thats not a big deal in reality using snippets and chunks. But this time, I decided not to use chunks.

I needed to use the autoComplete plugin ( to search and suggest topics from Modx's forum extension, aka Discuss.
I had to insert some html code, the link to the .css, the link to .js & some js script, has explained in the doc.

What I did :

I created a snippet (insertCode), which does nothing than output what's in input that's the most important part !

$output = $modx->getOption('code', $scriptProperties, 'Please insert something in &code=``');

return $output;

I created my input form in basic html :
<form id="matchSearch">
        <input type="text" placeholder="keyword" name="title" id="title" value="" />

And then I needed to call the css stylesheet. Thanks to my snippet insertCode, and the output modifier, I've been able to put this css to the head of the document !
&code=`<link rel="stylesheet" href="assets/lib/jqautoComplete/" />

And then the js file by the same method, whith some script as required !
&code=`<script src="assets/lib/jqautoComplete/"></script>
var xhr;
    minChars: 2,
    source: function(input, response){
        try { xhr.abort(); } catch(e){}
        xhr = $.getJSON('/assets/ajax/matchDiscussion.php', { title: input }, // matchDiscussion.php is an custom ajax requets / not part of Discuss
            if (data.length == '') {
                item = [{message:"Aucun résultat..."}];
    renderItem: function (item, search){
        var output = '';
        if (item.title) {
            return '<div class="autocomplete-suggestion" data-url="'+item.url+'" data-val="'+search+'"><a title="Last post on ''" href="'+item.url+'#forum-content">'+item.title+'</a> <span class="smaller grey">''</span></div>';
        else if (item.message) {
            output = '<div><span class="smaller grey" ><i class="fa fa-warning"></i> Nothing : <a href="target-to-create-link">Create a topic ?</a></span></div>';
            return output;
    onSelect: function(e, input, item) {
        var url = $(this)'url')+'#forum-content'; // get selected value
        if (url) { // require a URL
              window.location = url; // redirect
        return false;

The whole code to insert (which can be inserted in only one chunk ;-) :
<form id="matchSearch">
        <input type="text" placeholder="keyword" name="title" id="title" value="" />

&code=`<link rel="stylesheet" href="assets/lib/jqautoComplete/" />

&code=`<script src="assets/lib/jqautoComplete/"></script>
var xhr;
    minChars: 2,
    source: function(input, response){
        try { xhr.abort(); } catch(e){}
        xhr = $.getJSON('/assets/ajax/matchDiscussion.php', { title: input }, // matchDiscussion.php is an custom ajax requets / not part of Discuss
            if (data.length == '') {
                item = [{message:"Aucun résultat..."}];
    renderItem: function (item, search){
        var output = '';
        if (item.title) {
            return '<div class="autocomplete-suggestion" data-url="'+item.url+'" data-val="'+search+'"><a title="Last post on ''" href="'+item.url+'#forum-content">'+item.title+'</a> <span class="smaller grey">''</span></div>';
        else if (item.message) {
            output = '<div><span class="smaller grey" ><i class="fa fa-warning"></i> Nothing : <a href="target-to-create-link">Create a topic ?</a></span></div>';
            return output;
    onSelect: function(e, input, item) {
        var url = $(this)'url')+'#forum-content'; // get selected value
        if (url) { // require a URL
              window.location = url; // redirect
        return false;

What do you thing about that ? Do you already use this method ? Is it a good pratice ? Let me know...

Thanks for your returns, and I hope it can help !

]]> Tue, 05 Mar 2019 12:06:51 +0000
<![CDATA[Multi-Site, Single Core/Manager Setup]]> I'm posting this here in the hopes that it might save someone else some time, and also in the hopes that someone might point out any potential problems--or even a better way to do it--in our setup before we get too far down the road.

Perhaps MODX can evolve over time to better support something like this out of the box--although I've got say, it's amazing how well this is all working as is.
Our goal was to set up a multiple sites with a single MODX core and manager to control them all. After research and whole lot of trial and error, here's how we set things up on our Unix server using MODX 2.3.1 (this would probably look different under IIS):


We put the majority of MODX's assets outside any folder accessible on the web. The core, connectors, and manager folders are just the folders from the MODX install.

  • core/
  • connectors/
  • assets/
  • elements/
  • manager/
  • sites/

Delving into the assets folder, we pre-created the components folder that MODX will use when installing extras, and also created a common folder for assets shared between different sites.

  • components/
  • common/

We decided that we would do all of our custom snippets, chunks, plugins, and templates as static resources, and this collection of folders serves as a repository for the files.

  • snippets/
  • chunks/
  • plugins/
  • templates/

Each site gets it's own folder in the sites folder. Nothing outside of each site folder is web-accessible, i.e., the sites folder itself is not web-accessible.

  • site1/
  • site2/
  • site3/
  • etcetera/

We created a site template folder which we are able to duplicate for each new site that gets implemented. From there, one only needs to edit the MODX context setting to establish the new site (see step 2).

  • .htaccess <-- from MODX root install folder, support for Friendly URLS
  • config.core.php <-- from MODX root install folder
  • index.php <-- from MODX root install folder
  • assets/ <-- new folder
  • assets/components/ <-- symlink to /path/to/www/assets/components/
  • assets/common/ <-- symlink to /path/to/www/assets/common/
  • connectors/ <-- symlink to /path/to/www/connectors/
  • manager/ <-- symlink to /path/to/www/manager/


In order to make all of this work properly, you do have to edit some of the files--fewer than you might think, though...

Since we moved the core, the path relative to a site's root is different (note: the config.core.php files in manager and connecters do not need editing). This will be the same for each site, so you only have to edit it once. The corrected line should read:
define('MODX_CORE_PATH', dirname(dirname(dirname(__FILE__))) . '/core/');

The main index.php file for each site will have to be modified to initialize MODX into the correct context. Look for the line that reads:

and change "web" to a unique code for each site. You will be entering these codes into the manager later, so take note of what you use. For example:

This one was a little trickier. We have to find a way to tell the config file the path of the site that it's being called from every time it runs. We solved this by creating a variable based on PHP's $_SERVER["SCRIPT_FILENAME"]. Note: we couldn't use __FILE__ as that automatically resolves symlinks and breaks our URLs.

First: get an array of folder names leading to the path that the script is being called from (which is always going to be somewhere within a website's folder). Add this line near the top of the config file:

Second: since we know the path to the <website> folder, we can just explicitly reference it in our path array by grabbing the Nth item of the array, i.e., the name of any particular website will always be the Nth item of the array. In the case of our examples here it's the 5th (1.path,, 3.www, 4.sites, 5.<website>), so for example: $FOLDERS[5]. Note: There might be a better way to programmatically get the right folder name, but for us it would have been overkill.

Third: we have to inject that folder name variable into a few lines in the config file to fix our paths. Note: URLs do not need to be fixed; just treat them as if it were a standard, default MODX install.
$modx_manager_path= '/var/www/sites/'.$FOLDERS[5].'/manager/';
$modx_base_path= '/var/www/sites/'.$FOLDERS[5].'/';
$modx_assets_path= '/var/www/sites/'.$FOLDERS[5].'/assets/';

The built-in minify script (using Google Minify) will break on anything in a symlinked folder unless we specify the symlinks.
// change this line:
$min_symlinks = array();

// to this:
$min_symlinks = array(


In MODX, create a new context for each site. The context key should be the same ones you used in the index files. For each site you will need to have at least the following 4 settings:

  • base_url <-- the base relative URL for the site, usually just /
  • http_host <--
  • site_url <-- (method + http_host + base_url)
  • site_start <-- the index of the start page/resource for this site in MODX


To use the common elements path that we set up at the beginning, we'll need to create a new media source.

  1. On the Media Sources screen, create a new file system media source.
  2. Right click on the new media source, and select "Update Media Source"
  3. Change the basePath field to '/path/to/www/elements/' (trailing slash is important!)
  4. Change basePathRelative to 'No' and save

Now when you create a snippet/chunk/template/plugin and mark it as static, you can select the "Elements" media source, and browse the files in the elements folder. Just don't try to put any user-facing files there as it will break (that's what assets/common/ is for).


  • Under this setup, you can get to the manager from any of your sites, e.g.,,, etc.
  • Setting things up this way isn't totally without it's hiccups, though. The biggest issue on a day-to-day basis is using MODX's file browser: while you can still see and manage all the sites through the one manager, the file links and file browser will all be pointed to the site you used to log in--resources that live in the components or common folders will be fine, but site-specific stuff will change. For coders/devs this is probably a non-issue, but for clients and non-techy-users this could inadvertently lead to pain and confusion. For those users (and we are going to have to face this problem ourselves eventually), it's probably best to lock accounts down to one context (hiding others) and give them different logins for different sites--treat them like separate managers.
  • Our plan right now is to replicate this across Dev, Staging, and Production servers. For added security, the production server would be stripped of the manager folder. We haven't tested the replication process yet, but I'll update here on how difficult/easy that ends up being and how we go about automating that process.
  • Of course, the idea behind all of this is to have a single common set of files to maintain across several sites. Updating MODX should be as easy as uploading files into the right place (taking care not to blow away our special changes), and then running the setup from any one of the sites, although we haven't tested that yet to see if any problems are encountered by the setup program.
]]> Mon, 25 Feb 2019 06:24:03 +0000
<![CDATA[Getresources to php array or json string in a seperate file]]> Tue, 19 Feb 2019 08:37:00 +0000 <![CDATA[Change db password]]>
ThanX!]]> Tue, 19 Feb 2019 11:32:33 +0000
<![CDATA[Small snippet (widget): Instagram Latest Posts]]>
Not sure if it's actual for anybody but here it is: snippet "Instagram Latest Posts".

This snippet allows us to get the latest posts from any Instagram user. Access tokens are not required.

N.B.! Please take into account, 20 latest posts can be returned only as it's limited by Instagram.

UPDATE: Please use Github to get the updated code.]]> Mon, 28 Jan 2019 12:43:36 +0000
The purpose of this tutorial is to take a form submitted on the front end by a user and have the values of the fields be placed into a templated PDF that we've been supplied with. In my particular use case the client is a job recruitment agency who require that all candidates fill out a designed lengthy form manually. Making this process available digitally undoubtedly speeds up a lot of their admin work and saves candidates the hassle of coming down to their office to fill out a form.


You NEED to have pdftk installed on your server. The php pdftk parser that we use is just a front face for the command line tool. If you're working locally on XAMPP then installing pdftk pro (below) will be sufficient as pdftk pro is just a GUI for the processor.

You will also need pdftk pro (small premium of like £3 / $5)

Next you'll need to download php pdftk from here:

Install php pdftk somewhere accessible on your server such as the 'core/components/php-pdftk/'

Next you'll need to prepare your blank pdf template form to be filled out. You'll need Adobe Acrobat Pro so you can go to 'tools->prepare form'. For the most part it's quite clever and will setup the majority if not all of the form fields for you including correct letter spacing and such for big spaced out fields as is common with NI numbers. However it's not that great at setting up radio buttons and checkboxes for you so you may need to go in and edit these manually. Take note of the field names as you'll need to know these to map the data correctly in the hook we create next.

Once you've setup your pdf form you'll need to use pdftk to resave out your pdf. Make sure you click 'advanced' on ( so that it can pick up the form fields correctly.

Next create a snippet called 'formit2pdf' and insert this code, replacing the path to your autoload.php file and your template pdf file (the one you just saved out using pdftk pro ^). In the array you'll also need to map out the value of the pdf form to the value of the front end web form.


// Stuck? This code originated from the MODX Community Forums:

require_once('/path/to/php-pdftk/vendor/autoload.php'); // Server path to php-pdftk 

use mikehaertl\pdftk\Pdf;

// Fill form with data array
$pdf = new Pdf($modx->getOption('core_path') . 'components/php-pdftk/yourForm.pdf'); // Path to your blank template PDF
	// This is where you need to map PDF fields to Web Fields
    'First Name' => $hook->getValue('first-name'),
    'Last Name' => $hook->getValue('last-name')

// Grab the temp PDF file that we just dynamically created
$attachment = $pdf->getTmpFile();

// Add the PDF as an email attachment
$modx->getService('mail', 'mail.modPHPMailer');

return true;

Next include the formit2pdf we just created as a hook in your formit. You can also go ahead and setup a redirect to a thank you page if needed.

	&hooks=`formit2pdf, email, redirect`
	&emailSubject=`New application`

Setup your web form to match the values we used in the hook (first-name + last-name)

<input type="text" name="first-name" placeholder="first-name" value="[[!+fi.first-name]]">
<input type="text" name="last-name" placeholder="last-name" value="[[!+fi.last-name]]">

Finally setup an emailTpl called 'myEmailTpl'

Congratulations, you have a new application from: <strong>[[+first-name]] [[+last-name]]</strong>.
We've processed their form submission and attached it to this email for you.

If you've setup everything correctly then when your users submit a form you'll receive an email with the filled out pdf as an attachment.

]]> Sat, 19 Jan 2019 09:45:02 +0000
<![CDATA[MODX ACL Security Tutorial (REVO)]]>
Let me know what you guys think, if it's clear enough and or if there's anything that can be improved.

Thanks.]]> Wed, 10 Oct 2018 02:57:04 +0000
<![CDATA[myCalendar jqueryui date returned is not country formatted]]> I have installed myCalendar but I have a problem with the language.
1) I do not know how to set it up in French, so it display in my language
2) This imply that the date selected with the date picker return in some case a wrong date, for example 9/8/2018 (9 of August) create a date 8/9/2018 "8 of September)
How can I setup the language ?
Thank you in advance.
Patrice]]> Fri, 31 Aug 2018 09:36:42 +0000
<![CDATA[Migration / import from other systems like phpwcms and PostNuke]]>
This is probably not a complete list - please post a reply with any links that are missing. I will then edit them into the top post.

Any system
WebusersImport - Manager module allowing you to import webusers from a CSV file.

phpwcms to modx migration - a simple sql script to import posts from phpwcms into modx db for given category

[Utility] Migrating stories and links from PostNuke - command-line PHP scripts for import

Xoops News
Migrate XOOPS News to ModX - PHP script to import from an XOOPS DB]]> Fri, 13 Jul 2018 09:48:12 +0000
<![CDATA[Edit resource link on resource when logged in...]]> I have the pleasure to again use Modx which i always liked

A tiny and very simple snippet which i found quite convenient when you have a lot of resources and need to make some editing, instead of going thru the manager and browse the whole resources site tree each time

if ($modx->user->isMember('Administrator')) {

$edit_link = '<a href="/manager/?a=resource/update&id=[[*id]]">edit</a>';
  return $edit_link;

then you insert [[!edit_link]] (name of your snippet) into e.g. bottom of the pages or below footer links...

Here the "edit" link will only show up when you are logged in as an admin (easy to adjust using other groups, user's own resources, etc

Hope this is helpful to the non experts like myself]]> Sat, 07 Jul 2018 05:07:34 +0000
<![CDATA[Refresh a resource when save]]> I would like to refresh the resource page when I save it. Is this possible ? Thanks for you answer !]]> Wed, 23 May 2018 04:21:38 +0000 <![CDATA[Include fully parsed resource inside snippet in another resource]]> . The key is the included sitemap.xsl. Part of the xsl is a html template. At the moment the xsl is a MODX resource with the pasted output from another completed page into the template part. To keep it in sync I would like to get the template/page from a snippet, but how?

A few other options are to add conditional chunks with the surrounding xsl at the top and bottom of my normal template. Or add substitution filters to Apache/Nginx. Or add a MODX plugin. But doing it in a snippet would do best for my learning.

With this tool I would have an alternative to loading data with json into a page. Instead, load a page around data.]]> Sat, 28 Apr 2018 07:08:00 +0000
<![CDATA[Filter out results of a MIGX list using getImageList?]]>

I have a simple MIGX TV list of optional titles for each person. I'm using [[!getImageList]] to call the info from my TV. The field is called "GroupPosTitle". I only want to show the titles with "Diversity" in them. How would I add logic to show only those relevant options? Here is my code:

I was thinking using the &where property but I'm not sure how. Something like this:

I also tried this which resulted in no results:

Thanks in advance]]> Thu, 12 Apr 2018 07:04:37 +0000
<![CDATA[Modx blog problems]]>

and it’s working reasonably well, but there are just a few little niggles that I can’t seem to resolve.

1: In the RSS feed I can’t figure out how to get the Read More link into the feed.

The code looks like this
		<description><![CDATA[ [+blog-summary+] ]]></description>

	<guid isPermaLink="false">[(site_url)][~[+id+]~]</guid>


2: Also I can’t remember how to get the pub date into the post template.

It’s been a while since I built this, so any gentle reminders would be appreciated.


]]> Wed, 07 Mar 2018 11:08:04 +0000
<![CDATA[(Tutorial) Making member-only pages in Revolution [WIP]]]>

I’ve started making a tutorial, it’s still a work in progress but I’d love to hear feedback and see it becoming a valuable resource to the community. I’ve also linked the tutorial to this topic to encourage everyone visiting to report feedback back here.]]> Tue, 27 Feb 2018 12:35:01 +0000