Resolvers II - Connecting Resources

Using resolvers in a transport package to connect resources to other MODX objects. For example, attaching them to the site's default template or setting their parent field.

By Bob Ray  |  June 10, 2025  |  1 min read
Resolvers II - Connecting Resources

Overview

In my previous article, I wrote about using resolvers in a transport package to transfer files. In this one, we'll see examples of using code in a resolver to connect resources to other MODX objects.

Connecting Resources to the Default Template

Before we get to the new code in the "install" section of our resolver, we need to make a change in the code at the top of the file:

<?php
/**
 * Resolver for Example extra
 *
 * Copyright 2025 yourname <Your email or website URL>
 * Created on 01-11-2025
 *
 * {License would go here}

 * @package example
 * @subpackage build
 */

/* @var $object xPDOObject */
/* @var $modx modX */
/* @var array $options */
/** @var modTransportPackage $transport */

/* Set up $modx variable for use later */
if ($transport) {
    $modx =& $transport->xpdo;
} else {
    $modx =& $object->xpdo;
}

$prefix = $modx->getVersionData()['version'] >= 3
    ? 'MODX\Revolution\\'
    : "";

The new code is at the bottom of the code above. It sets up the $prefix variable, which will allow the resolver's code to execute in both MODX 2 and MODX 3. MODX 3 uses namespaces, which means that the class names of most common MODX objects have to be prefixed with MODX\Revolution\. If your code will run only in MODX 2 or only in MODX 3, you can skip the prefix and just code in the namespace for MODX 3 or leave it out for MODX 2, but it's simple enough to use a dynamic prefix like the one above that I always use it. If you use the MyComponent extra, it will handle the prefix automatically.

One common use for a resolver is to connect your resources to the site's default template. You can't do this during the build phase of your package, because at that point, you can't know the ID of the default template in the site where your Extra will be installed. It has to be done in a resolver, with code like this in the "Install" part of the resolver:

case xPDOTransport::ACTION_INSTALL:
    $pagetitle = 'MyResource';
    $defaultTemplateId = $modx->getOption('default_template', null, '', true);

    if (empty($defaultTemplateId)) {
        $modx->log(modX:LOG_LEVEL_ERROR, 'No default template set');
    } else {
        $doc = $modx->getObject($prefix . 'modResource', array('pagetitle' => $pagetitle));
        if ($doc) {
             $doc->set('template', $defaultTemplateId);
             $doc->save();
        } else {
            $modx->log(modX:LOG_LEVEL_ERROR, 'Could not find resource with pagetitle: ' . $pagetitle);
        }
    }

    break;

Notice the use of the $prefix variable above. It will be an empty string in MODX 2, but in MODX 3, it will be MODX\Revolution\

The two error checks are unlikely to ever find a problem, since you've installed the resource and it would be quite rare for the site to have an empty default_template System Setting. Still, it's a good idea to check rather than risk having your resolver (and often your whole install) crash and display nothing.

If you have more than one resource that needs this treatment, you can just put them in a foreach loop like this:

case xPDOTransport::ACTION_INSTALL:
    $pagetitles = array (
        'MyResource1',
        'MyResource2',
        /* ... */
    );
    $defaultTemplateId = $modx->getOption('default_template', null, '', true);

    if (empty($defaultTemplateId)) {
        $modx->log(modX:LOG_LEVEL_ERROR, 'No default template set');
    } else {
        foreach ($pagetitles as $pagetitle) {

            $doc = $modx->getObject($prefix . 'modResource', array('pagetitle' => $pagetitle));
            if ($doc) {
                 $doc->set('template', $defaultTemplateId);
                 $doc->save();
            } else {
                $modx->log(modX:LOG_LEVEL_ERROR, 'Could not find resource with pagetitle: ' . $pagetitle);
            }
        }
    }

    break;

Setting Parents

Resolvers can also be used to set the parent (or any other field) of the resource. Here's an example showing how to set the parent field:

case xPDOTransport::ACTION_INSTALL:
    $pagetitles = array (
        'Child1',
        'Child2',
        /* ... */
    );

    $parentPagetitle = 'MyParentFolder';

    $parentObj = $modx->getObject($prefix . 'modResource',
        array('pagetitle' => $parentPagetitle);

    if (empty($parentObj)) {
        $modx->log(modX::LOG_LEVEL_ERROR,
            'Could not find parent with pagetitle: ' .
            $parentPagetitle);
    } else {
        $parentId = $parentObj->get('id');
        foreach ($pagetitles as $pagetitle) {

            $doc = $modx->getObject($prefix . 'modResource',
                array('pagetitle' => $pagetitle));

            if ($doc) {
                 $doc->set('parent', $parentId);
                 $doc->save();
            } else {
                $modx->log(modX::LOG_LEVEL_ERROR,
                    'Could not find resource with pagetitle: ' .
                    $pagetitle);
            }
        }
    }

    break;

In the code above, we get the parent object by pagetitle and extract its ID. Then we loop through the children and set that ID in the id field of each resource. Notice that we've used the $prefix variable again (twice) so be sure that you either include the code that sets that variable at the top, or remove it from the "install" section.

It's possible to set the parent-child relationship without a resolver by adding the child pages as related objects to the parent in the build file, but I find it much easier and less error-prone to do it in a resolver like the one above.

Coming Up

In my next article, we'll start looking at using resolvers to change strings in your package during upgrades.


Bob Ray is the author of the MODX: The Official Guide and dozens of MODX Extras including QuickEmail, NewsPublisher, SiteCheck, GoRevo, Personalize, EZfaq, MyComponent and many more. His website is Bob’s Guides. It not only includes a plethora of MODX tutorials but there are some really great bread recipes there, as well.