Updating Manager Pages in a Plugin VII

Creating the Staged Resource only when appropriate

This is the seventh in a series of articles dealing with issues created by operations performed in plugins that work on the Create/Edit Resource Panel in the MODX Manager. In the previous article, we saw how to inject the final JavaScript to display the buttons and delete a staged resource. In this one, we'll look at the code that actually creates the Staged Resource.

MODX logo

Creating a Staged Resource

The first question in creating a Staged Resource is how to know when to do it. Luckily, that's a pretty easy one to answer. We do it whenever a resource is saved with the Stage Date TV filled and the Staged Resource ID TV empty. Any resource that has the Staged Resource TV filled already has a Staged Resource. Any resource with the Stage Date TV empty, doesn't need one. All we have to is check those two TV values in a plugin attached to the OnDocFormSave event (actually, we'll use our existing plugin and just fill in the code for that event that we placed there earlier with the "For future use" comment). We'll use the resource/duplicate processor to create the Staged Resource.

That code looks like this:

case 'OnDocFormSave':
    /* Create staged Resource if Stage Date TV is set */
    /* @var $oldTv modTemplateVar */
    /* @var $resource modResource */

    /* Don't execute for new resources */
    if ($mode != modSystemEvent::MODE_UPD) {
        return '';

    /* Get the value of the 'StageID' TV */
    $stageId = $resource->getTVValue('StageID');
    $key = $resource->get('context_key');

    /* Code from Mat Dave Jones to allow
       context-specific staging */

    /* Find the ID of the Staged Resources folder */
    /* Check if a Context Setting exists */
    $stageFolder = $modx->getObject('modContextSetting',
            'context_key' => $key,
            'key' => 'stagecoach_resource_id'

    /* If so use that, otherwise use system setting */
    $stageFolder = (empty($stageFolder))
        ? $modx->getOption('stagecoach_resource_id', null, 0)
        : $stageFolder->get('value');

    /* check if Context Setting exists */
    $archiveFolder = $modx->getObject('modContextSetting',
            'context_key' => $key,
            'key' => 'stagecoach_archive_id'

    /* if so use that otherwise use system setting */
    $archiveFolder = (empty($archiveFolder))
        ? $modx->getOption('stagecoach_archive_id', null, 0)
        : $archiveFolder->get('value');
    /* ************ */

    /* Don't execute on staged or archived Resources */
    $thisParent = $modx->resource->get('parent');
    if ($thisParent && (($thisParent == $stageFolder) || ($thisParent == $archiveFolder))) {
        return '';

    /* don't execute on the folders themselves */
    $thisId = $modx->resource->get('id');
    if ($thisId && (($thisId == $stageFolder) || ($thisId == $archiveFolder))) {
        return '';

    /* get the Stage Date TV value */

    $date = $resource->getTVValue('StageDate');
    if (empty($date)) {
        return '';

    /* Append stage date to staged Resource pagetitle */
    $pt = $resource->get('pagetitle') . '-' . $date;

    if (!empty($stageId)) { /* If set, user is just updating the date */
        $res = $modx->getObject('modResource', $stageId);
        if ($res) { /* update pagetitle to new date */
            $res->set('pagetitle', $pt);
        return '';

    /* make sure staged Resource doesn't already exist - return if it does */
    $res = $modx->getObject('modResource', array('pagetitle' => $pt));
    if ($res) {
        return '';

    /* set params for duplicate() */
    $params = array(
        'newName' => $pt,
        'publishMode' => 'unpublish',
        'parent' => $stageFolder,
        'duplicateChildren' => false,

    /* duplicate and save the staged Resource */
    $stagedResource = $resource->duplicate($params);

    /* unset the TVs in the staged Resource */
    $stagedResource->setTVValue('stageID', '');
    $stagedResource->setTVValue('stageDate', '');

    /* set the stageID TV in the original (current) Resource */
    $newId = $stagedResource->get('id');
    $resource->setTVValue('stageID', $newId);


The comments make this code fairly self-explanatory. After some sanity checks, if the Stage Date is not empty, the Staged Resource ID is empty, and the Staged Resource doesn't already exist, we create it with the resource/duplicate processor, using the value of the Stage Date TV as a suffix on the pagetitle. Finally, we get the new Staged Resource and its ID and place that ID in the Staged Resource TV for the original (current) resource.

If the Staged Resource already exists, the user may be updating the stage date, so we make that change to the pagetitle of the Staged Resource. We could check the two dates to make sure they are different before making the change, but it's almost as fast, and more reliable, to just make the change and save the Staged Resource.

Coming Up

We have three working buttons, and they're shown on the appropriate pages. The Delete Draft button works, and we now have code that creates a Staged Resource. We still have a problem with the creation process, though. The Staged Resource TV is set in memory, but it's still blank on the screen. There's no way to set it on the screen in PHP, and we can't use JavaScript here because the JavaScript would be created at a time when we don't know (and can't discover) the ID of the Staged Resource.

The problem is that if the user does some more editing of the current page and saves it, the blank value of the Staged Resource TV ID will overwrite the one we just put there. This will orphan the Staged Resource, since no TV points to it.

The solution is to immediately reload the page, which will make the Staged Resource ID appear in the TV. Unfortunately, no one has ever figured out a way to make this happen in PHP, and MOX no longer reloads the Create/Edit Resource page when you save a resource. As a result, we have to use some tricky JavaScript to reload the page. We'll see how to do that in the next article.

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.