Using MODX Outside of MODX

Did you ever wish you could use some of MODX’s capabilities in a script running outside of MODX? Sometimes, it’s nice to be able to use $modx->getChunk() to get some content or $modx->runSnippet() to use a utility snippet. It’s also handy to be able to get and manipulate various MODX objects like Resources, Users, Templates, Chunks, and TVs in a script without having to create a snippet inside MODX to do it.

I end up writing a fair number of extras and utility scripts that can run both inside and outside MODX, so I’ve had to develop a fairly reliable method for instantiating the $modx object in a way that keeps things from falling apart. When I need MODX outside of MODX, I use some variation of the following code. You can put the code directly in your PHP file or use include to pull it in.

The Code

/* Assume these are false until we know otherwise */
$cliMode = false;
$outsideModx = false;

/* Set a user (set to an actual username) */
$myUserName = 'JoeBlow';

/* Instantiate MODX if necessary */
if (!isset($modx)) {
    $outsideModx = true;

    /* Set path to MODX core directory */
    if (!defined('MODX_CORE_PATH')) {
        /* be sure this has a trailing slash */
        define('MODX_CORE_PATH', 'path/to/modx/core/');
    }
    /* get the MODX class file */
    require_once MODX_CORE_PATH . 'model/modx/modx.class.php';

    /* instantiate the $modx object */
    $modx = new modX();
    if ((!$modx) || (!$modx instanceof modX)) {
        echo 'Could not create MODX class';
    }
    /* initialize MODX and set current context */
    $modx->initialize('web');
    // or $modx->initialize('mgr');

    /* load the error handler */
    $modx->getService('error', 'error.modError', '', '');

    /* Set up logging */
    $modx->setLogLevel(xPDO::LOG_LEVEL_INFO);

    /* Check for CLI mode and set log target */
    if (php_sapi_name() == 'cli') {
        $cliMode = true;
        $modx->setLogTarget('ECHO');
    } else {
        $modx->setLogTarget('HTML');
    }

    /* Set $modx->resource, request, and $modx->user */

    /* Make sure there's a request */
    $modx->getRequest();

    /* Set $modx->resource to home page */
    $homeId = $modx->getOption('site_start');
    $homeResource = $modx->getObject('modResource', $homeId);

    if ($homeResource instanceof modResource) {
        $modx->resource = $homeResource;
    } else {
        die('No Resource');
    }

    /* set $modx->user */
    $myUser = $modx->getObject('modUser', array('username' => $myUserName));
    if ($myUser instanceof modUser) {
        $modx->user = $myUser;
    } else {
        die('No User');
    }
}

Do I Really Need All That?

The comments in the code above are fairly self-explanatory, but they don’t explain why we’re doing what we’re doing and when it’s necessary.

Not all of the code is necessary in every case, although using all of it will very seldom cause any trouble. For a simple utility snippet, you often need only the first part of the code (up to and including the $modx->initialize()) line.

Initializing MODX

The first part of the code, checks to see whether the $modx object already exists. There’s no point in creating it if it’s there already. It’s theoretically possible that a variable called $modx already exists but it’s not the real MODX. The odds of that are remote enough that I don’t bother with it, but if you want to be super careful, you could use this instead:

if ( (! isset($modx)) || (! is_object($modx)))

You might be tempted to use $modx instanceof modX for the check, but since you haven’t included the MODX class file yet, it won’t work. We do it after initializing MODX just to make sure that it worked.

The choice of whether to initialize MODX in the ‘web’ or ‘mgr’ context depends on what your code does. Most of the time, it doesn’t matter, but if your code calls processors that check permissions or if your code checks permissions directly, MODX will use the Policy tied to the user’s user group for the specified context when doing the checks.

For security purposes, using ‘web’ is generally safer since the user is less likely to have permissions in that context that will let them cause trouble.

$insideModx and $cliMode

The script above sets the $outsideModx variable just in case we need to know later on in the script whether we’re running inside MODX or not. We also set the $cliMode variable. This indicates whether the script is running from the command line, or in a browser. We also set the MODX log target so $modx->log() messages will be formatted properly.

Inside MODX, $cliMode will always be false, which is why the check is inside the section that only runs outside of MODX (and why we set it to true above that section). but outside MODX, it will be true if the script is run from the command line or from inside a programming editor, but false if it is running in a browser. This is important to know because HTML will clutter up the output if you’re running in CLI mode, so when you print an error message, you might use code like this:

if ($cliMode) {
    echo "\nFile not found";
} else {
    echo '<br />File not found';
}

If you have lots of output, you’d probably use a function to print messages, possibly using nl2br() to convert newlines to break tags.

$error, $request, $resource, and $user

It’s difficult to know for sure when these will be necessary. You might be doing things in your script that will access various MODX objects directly or indirectly. If you call a processor, for example, with $modx->runProcessor(), the odds are good that the processor will fire an event or two. In many event invocations, $modx->resource or $modx->user get sent along for the ride. If they don’t exist, the program may crash.

You might think these settings are unnecessary if you’re not calling any processors or invoking any events, but remember that the code is running as if it’s in MODX. That means any of the site’s plugins might come into play. One of them could be checking $modx->user or $modx->resource. It could also be looking at the current request or throwing an error using the MODX error handler.

Every one of the four settings has crashed code of mine when a processor or plugin tried to access them and they weren’t set.

The code above sets $modx->resource to the page set in the site_start System Setting. If your code will be made public, this is a safe bet because every site has one. For private code, you might want to create a dummy resource so plugins won’t have a chance to mess with the home page (e.g., the DefaultResourceGroup plugin). If your code doesn’t use resources, you can remove that section. If you use resources, but don’t save them, you can probably remove that section, but be prepared to put it back if the code crashes.

You’ll have to modify the code above to change “JoeBlow” to the username of an actual user. For security purposes, it’s best not to set this to the admin Super User unless you need that user’s permissions to execute your code. If you will be distributing your code, you’ll have to make a decision about whether to use the admin (ID = 1), create a user, pick a random user, or advise people to set the username themselves. You might be tempted to use the (anonymous) user, but that’s not a real user and the getObject() call will fail. You *can* set the user to the (anonymous) user by replacing all the user code above with the simple call below, but be aware that the user’s
permissions may be limited.

$modx->getUser();

Note that if you’re running in CLI mode, permissions are not an issue. In CLI mode, MODX bypasses all permission checks on the assumption that if you have shell access, you’re a reputable character. If you’re running in MODX or in a browser, though, and you call any MODX processors, they will balk if the user doesn’t have the necessary permissions. In those cases, plugins may also do permission checks.

As with $modx->resource, if your code doesn’t involve users at all you can remove that section and if you don’t save any users, you can probably remove it.

Summing Up

In practice, I always call the error service. I set $modx->resource only if I’m modifying resources in the DB and $modx->user only if I’m modifying users in the DB. In fact, even when modifying users and resources, you usually don’t need to set these unless you’re calling a processor. Setting the request is very seldom necessary — I’ve only had to do it once.


For more information on how to use MODX to create a web site, see my web site Bob’s Guides, or better yet, buy my book: MODX: The Official Guide.

Looking for quality MODX Web Hosting? Look no further than Arvixe Web Hosting!

Tags: , , , , | Posted under cPanel/Linux Hosting, DotNet/Windows Hosting, MODX | RSS 2.0

Author Spotlight

Bob Ray

Bob Ray

I am the author of MODX: The Official Guide and over 30 MODX add-on components. I host Bob's Guides, a source of valuable information for MODX users, and I've been very active in the MODX Forums with over 14,000 posts.

Leave a Reply

Your email address will not be published. Required fields are marked *


8 + = 13

You may use these HTML tags and attributes: <a href="" title="" rel=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>