SkillAgentSearch skills...

VersionX

Resource & Element Versioning Extra for MODX Revolution (supports 2.2 and up). Extends the core in a future-proof manner to keep copies of every change to resources, templates, template variables, chunks, snippets and plugins.

Install / Use

/learn @modmore/VersionX
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

VersionX 3

If you're looking for the previous version of VersionX, see the v2 branch.

VersionX is a versioning system for the MODX content management system. It keeps track of changes to your resources, templates, template variables, chunks, snippets, plugins, and now in v3 custom objects too! You can view historic changes and revert changes from a simple dashboard.

VersionX Screenshot

v3.0 is a complete rewrite and is not compatible with v2. There is, however, a migration utility included that will assist with moving your old data to the new tables.

Funding Goal Reached

VersionX 3.0 was made possible by community funding. Special thanks to:

  • <a href="https://jens-wittmann.de" target="_blank" rel="noopener">Jens Wittmann</a>
  • <a href="https://www.quadro-system.de/" target="_blank" rel="noopener"><img src="https://assets.modmore.com/modxpo2022/sp/quadro.svg" alt="QUADRO" style="width: 250px;"></a>
  • <a href="https://www.webaix.de/" target="_blank" rel="noopener"><img src="https://assets.modmore.com/modxpo2022/sp/webaix-logo-2021.svg" alt="webaix." style="width: 250px;"></a>
  • <a href="https://www.visions.ch/" target="_blank" rel="noopener"><img src="https://assets.modmore.com/modxpo2022/sp/logo_visions.svg" alt="Visions" style="width: 250px;"></a>
  • <a href="https://www.lux-medien.com/" target="_blank" rel="noopener"><img src="https://assets.modmore.com/modxpo2022/sp/logo-lux-tiny-2019.svg" alt="LUX Medien" style="width: 250px;"></a>
  • <a href="https://sepiariver.com/" target="_blank" rel="noopener">Sepia River Studios</a>
  • Joshua Lückers

Requirements

  • MODX 2.6.5+
  • PHP 7.4+

Installation

VersionX can be installed from either the modmore package provider, or the MODX package provider.

New UI

The UI in VersionX 3.0 has been overhauled and simplified.

Manager Page

The VersionX manager page is availble at Extras -> VersionX in the MODX manager. Here you'll find the main objects grid that lists all objects that have at least one version stored. They are sorted by the latest update, and can be filtered by the package they belong to, the type of object (Resource, Template, Chunk, Snippet, TV, Plugin, or custom), the user who made the update and the date.

By default, only core object types are displayed. If you would like to include custom objects, please refer to the sections Object Types and Versioning Custom Objects below.

To view the stored versions for an object, right-click on it and select View Details. A window will open with a list of deltas for that object. Each delta represents a grouping of all the fields that changed at a particular point in time. Inside each delta you'll see a list of rendereded diffs for each field name showing the before and after values.]

Versions Tab

On each Resource and Element manager page, you'll see an extra "Versions" tab that's been added by VersionX. Switching to this tab will display the same list of deltas as when opening the detail window on the VersionX manager page.

Reverting Changes

Reverting changes is performed either on the versions tab of the manager Resource/Element form, or via the main VersionX manager page.

Look through the list of deltas, and find the one you want to revert to. There are three buttons available for reverting.

  • Undo: On the right-hand side of every diff, you'll see undo buttons for each field listed. Clicking undo will revert the change for that field only, ignoring all the other fields within that delta.
  • Revert these changes: In the top-right corner of each delta, you'll see the Revert these changes button. This will revert all fields within that delta, but no others.
  • Revert all fields to this point in time: This button sits between deltas, and reverts ALL fields regardless of which delta they are in, to that point in time. (This point in time refers to the "end time" of the delta just below it).

Fields

Different field types in v3 allow for unique behavior when creating, reverting, or rendering deltas. In addition to the standard Text field, the Properties field is now available.

Properties fields are defined for an object in the type class (see Object Types section below) and are typically used for fields that contain more than one value, such as a serialized value. The properties field breaks the value apart recursively and versions each item as its own field when stored in a delta. This provides more granular control over what can be reverted, compared to a normal Text field where all values must be reverted at once. An example of the Properties field being defined for a Resource can be found here.

An Image field is also planned that would allow rendering of the before and after images within the diff.

Object Types

Objects may be expected to behave differently from one another. We expect when saving a resource, it should also remember the TV values on that resource, whereas when saving a chunk, we don't need to worry about that.

To handle these different behaviours, VersionX uses configuration classes that extend the \modmore\VersionX\Types\Type class.

Here's the object Type class for versioning chunks (modChunk):

<?php

namespace modmore\VersionX\Types;

class Chunk extends Type
{
    // The class to be versioned
    protected string $class = \modChunk::class;
    
    // The id of the HTML element where the "Versions" tab will be added.
    protected string $tabId = 'modx-chunk-tabs';
    
    // The id of the ExtJS panel where versions will be rendered
    protected string $panelId = 'modx-panel-chunk';
    
    // Package name. If you're versioning a custom object, change this from core.
    protected string $package = 'core';
    
    // The primary field name for this object (for a resource it might be pagetitle)
    protected string $nameField = 'name';
    
    // List the field names to appear at the top when displaying diffs.
    protected array $fieldOrder = [
        'name',
        'description',
        'content',
    ];
    
    // List field names that should not be versioned
    protected array $excludedFields = [
        'id',
        'snippet',
    ];
}

VersionX will check these values when performing actions.

Versioning Custom Objects

In addition to resources and elements, VersionX can work with custom objects. The only requirement is that it must be a derivative of xPDOObject.

Example custom Type class for a Commerce product:

<?php

namespace MyModuleNamespace;

use modmore\VersionX\Fields\Image;
use modmore\VersionX\Fields\Properties;
use modmore\VersionX\Types\Type;

class MyProduct extends Type {
    protected string $class = \comProduct::class;
    protected string $package = 'commerce';
    protected string $nameField = 'name';
    protected array $excludedFields = [
        'id',
    ];
    protected array $fieldOrder = [
        'name',
        'description',
        'pricing',
        'sku',
    ];
    protected array $fieldClassMap = [
        'properties' => Properties::class,
        'image' => Image::class,
    ];
    
    /**
     * Here we are loading the Commerce package via it's service class. This is required in order to have 
     * custom objects show up in the main VersionX objects grid.
     */
    public static function loadCustomPackage(\modX $modx): bool
    {
        // While we're using $modx->getService() here, depending on your package/objects you might use
        // $modx->loadClass(), or $modx->addPackage() instead.
        if (!$modx->getService('commerce', 'Commerce', MODX_CORE_PATH . 'components/commerce/model/commerce/')) {
            // Return false if it failed
            return false;
        }
        
        return true;
    }
}

Create versions of a custom object

Here's an example of how to create a delta of an object using the MyProduct type class above:

$path = $modx->getOption('versionx.core_path', null, MODX_CORE_PATH . 'components/versionx/');
require $path . 'vendor/autoload.php';

$versionX = new \modmore\VersionX\VersionX($modx);

$type = new \MyModuleNamespace\MyProduct($versionX);
$result = $versionX->deltas()->createDelta($id, $type);

Here we are getting the VersionX autoloader (so PHP knows where the VersionX classes are), then instantiating VersionX, instantiating our own custom type class, then calling createDelta() and passing our custom type class $type and the $id of the object we want to version.

You can see an example of this in the VersionX plugin, where we are creating a new delta of a resource when saved. The Object Type in this case is \modmore\VersionX\Types\Resource.

$type = new \modmore\VersionX\Types\Resource($versionX);
$result = $versionX->deltas()->createDelta($id, $type);

Now what happens if you want to include extra data in the delta that's not a field of your object? Saving TV values along with resources are an excellent example of this. In your extended custom type class, you can use the includeFieldsOnCreate() method to add extra data to the version. An [example of this](https://github.com/modmore/VersionX/blob/3.x/core/c

Related Skills

View on GitHub
GitHub Stars41
CategoryCustomer
Updated2mo ago
Forks20

Languages

PHP

Security Score

75/100

Audited on Jan 29, 2026

No findings