Managing Paths in MODX Extras I

Making sure MODX can find your files in both development and live environments

In the last article we wrapped up the "Understanding .htaccess" series. In this one, we'll look at how to handle paths when developing a MODX extra.

MODX logo

The Problem

If you've ever developed a MODX extra, you've run into this problem. If your extra has one or more class files, you need to load them (often at more than one point in your extra). Since you're working on the extra, you want to load the development version of your class. That means you're not going to get it from the standard install location: assets/components/my_extra/. Instead, you'll be loading them from wherever your development code is — the same place you keep your build files.

The worst option is to hard-code the path to a class file like this:

include 'c:/xampp/extras/assets/mycomponents/core/components/my_extra/model/myclass.class.php'

If you hard-code the path, you'll have remember to change it every time you build your extra (and change it back after doing the build). Otherwise, that local path will be part of the build and the class file will never be found.

The traditional solution, developed by someone on the MODX core team a long time ago, is to create a System Setting to hold the local development core path (and often the local development assets path), like this:

Setting Key: myExtra.core_path
Value: c:/xampp/extras/assets/mycomponents/my_extra/core/components/my_extra/

Setting Key: myExtra.assets_path
Value: c:/xampp/extras/assets/mycomponents/my_extra/assets/components/my_extra/

If you're using MyComponent to develop your extra, put those System Settings in the core namespace. That way, they'll automatically be excluded from the build. If you put them in your extra's namespace, they'll always be included in the build and your program will crash in production environments.

The settings are not included in the build stage of the project so you're the only one who will have them. In the code, if a setting exists, it gets used. If not, the code creates a path to the standard install location and uses that. This can take several forms, but they all do the same thing. Here's a somewhat inefficient example:

$setting = $modx->getOption('myExtra.core_path', null, '', true);
if (empty($setting)) {
    $extraCorePath = MODX_CORE_PATH . 'components/my_extra/';
} else {
    $extraCorePath = $setting;

include $extraCorePath . 'model/myclass.class.php';

In the code above, the first line attempts to get the value of the myExtra.core_path System Setting. The $setting variable will be empty if the setting doesn't exist. The rest of the code will create the standard path if the setting is empty, and will use the setting if it's not empty. Here's a more typical version of the code:

$extraCorePath = $modx->getOption('myExtra.core_path',null,
    MODX_CORE_PATH . 'components/orphans/');
include $extraCorePath . 'model/myclass.class.php';

This code does the same thing. It's a little more efficient, but less easy to read. It attempts to get the System Setting with $modx->getOption(), but it includes the standard core path as the default option in the third argument to getOption(). It uses that value if the setting is not found. The null is there because the default value must be the third argument, so we need to put something in the second argument. Normally, it would be the array to search, but if it's null, only System Settings will be searched.

Notice that the settings always end with a slash. It's a MODX convention that all paths and URLs end with a slash, so remember *not* to put a slash immediately after MODX constants like MODX_CORE_PATH and MODX_ASSETS_PATH or your path will end up with a double slash.


As we said earlier, there are a number of ways to do the same thing. Some people prefer to put the code all on one line:

include $modx->getOption('myExtra.core_path',null,
    MODX_CORE_PATH . 'components/my_extra/') . 'model/myclass.class.php';

You may also see this version that comes from the days when the MODX_CORE_PATH constant didn't exist:

include $modx->getOption('myExtra.core_path',null,
    $modx->getOption('core_path') . 'components/my_extra/') . 'model/myclass.class.php';

You could also use the PHP ternary operator, like this:

$setting = $modx->getOption('myExtra.core_path',null);
$extraCorePath =  empty($setting)
    ? MODX_CORE_PATH . 'components/my_extra/'
    : $setting;
include $extraCorePath . 'model/myclass.class.php';

It's a matter of personal preference which version you use. We've used loading the class file as an example, but the technique is often used for loading any file that you might want to work on change during development, such as JavaScript, CSS, and image files. For those, you'll usually want the assets path rather than the core path, but the technique is the same.


The disadvantages of this system are fairly minimal. It's reliable and secure, but it does include completely unnecessary code that will execute every time your extra runs. In a production environment, the code will always look for the System Setting and will never find it.

Another issue is that people are who unfamiliar with this MODX usage are probably going to be confused by code that persists in looking for a System Setting that's not there. In the next article, we'll see a whole other way to do this.

Coming Up

In the next article we'll see a different way of managing paths in extras that involves using the namespace object.

Looking for high-quality, MODX-friendly hosting? As of May 2016, Bob's Guides is hosted at A2 hosting. (More information in the box below.)

Comments (0)

Please login to comment.