Modifying of the document creation date within template variable in MODx Evolution

On my MODx sites I often want to have ability of changing the document creation date ("createdon" property). Yes, I know I can do it with the standard DocManager module, but if it is your regulary performed action, it is more than not handy. I wanted the solution which would allow me to set the date like it would regular template variable, but when being saved, it would affected the actual createdon date stored in the documents table.

The reasons of changing the createdon date may be various. One of the sites I worked on was used this property for displaying articles in chronological order and often the date has been needed to adjust (to make the article date looks like it was published earlier). You may ask: why not just use standard template variable and sort the articles based on it? Well, there were few things.

First, the site was already live for a long time with this scheme. If just to add the template variable, it would be empty for already existing content so the articles order is break. Second, the site was using many of custom database queries. I didn't want to change anything in the structure and miss something. Third, the values of template variables are stored in database as text. This means that if the displayed date format will be changed in MODx settings, the sort order based on this template variable will break because one part of resources was saved with one date format, and future resources will be saved with another date format.

And never mind. I just like the result to which I came and it becomes extremely helpful for me. Maybe you also find it useful.

Writing the plugin

First you need to have template variable with type of Date which will be used for setting the createdon property, so create it and assign to any templates you want.

Now create a new plugin (I called it "CreatedOnTV") and paste following code:

$e =& $modx->event;
$tvid = (int) $e->params['tvid'];  // ID of template variable
$contentid = $e->params['id'];     // ID of edited document

if ($e->name == 'OnDocFormSave')
{
    // Get the template variable value.
    $tvvalue = isset($_POST['tv'.$tvid]) ? trim($_POST['tv'.$tvid]) : null;

    // Convert template variable value to timestamp.
    $timestamp = strtotime($tvvalue);

    // If correct timestamp is received, update the document creation date 
    // in database.
    if ($timestamp) {
        $query = 'UPDATE '.$modx->getFullTableName('site_content')
               . ' SET `createdon` = '.$timestamp.' WHERE `id` = '.$contentid;

        $result = $modx->db->query($query);

        if (!$result) {
            $modx->logEvent(5, 3,
                'Unable to modify creation date for document '.$contentid,
                'CreatedOnTV'
            );
        }
    }
}

Go to plugin Configuration tab and paste this code to "Plugin configuration" text box:

&tvid=Template var ID;int;

Press the "Update parameter display" button. New text box with label "Template var ID" will appear right bellow. Type the identifier of the date template variable you created. In my case this identifier was 2, so the configuration looks like on this picture:

Plugin configuration

Then go to plugin "System Events" tab and mark the OnDocFormSave checkbox. Save the plugin.

Well done! Try to edit any document. Set any date in your new template variable and save changes. If everything is alright, the new date should be assigned to a document.

How it works?

The plugin gets a reference of MODx Event object and collects the variables: identifier of the createdon template variable which should be specified in plugin configuration, and identifier of currently edited resource. No matter is it already existing document or just created: at this stage the new document is surely saved in database and its identifier is known.

After the plugin checks it is called on expected event, it gets the value of template variable passed throw document form and tries to convert the date in string format to Unix timestamp. The input date may be in various formats based on MODx settings. The PHP strtotime function takes care about it and receives correct timestamp from any of these formats.

At last, if the value of template variable is received and it was successfully converted to timestamp, the plugin makes database query for updating resource record with the new createdon date.

One more thing

Well, as we see, the plugin works exactly as it should, but there is one more detail. I want the createdon date in template variable being displayed even if it was not saved before. At this time if you create document, save it without setting date and open to edit again, the template variable box is empty and you can't see the creation date quickly.

I don't like this behaviour. To fix it, I made the plugin to extend document editing form with a bit of JavaScript which sets default value to template variable field.

Append the following code to our plugin:

if ($e->name == 'OnDocFormRender')
{
    if (!$contentid) {
        // If the document is new, no further actions are necessary.
        return;
    }

    // Get the document creation date saved in content table.
    $res = $modx->db->select(
        'createdon',
        $modx->getFullTableName('site_content'),
        'id='.$contentid
    );

    if ($modx->db->getRecordCount($res)) {
        $createdon = $modx->db->getValue($res);
    }
    else {
        // Stop here if we can't receive the creation date for any reason.
        return;
    }

    // Select date displaying format based on MODx settings.
    switch ($modx->config['datetime_format']) {
        case 'mm/dd/YYYY':
            $date_format = 'm/d/Y';
            break;
        case 'YYYY/mm/dd':
            $date_format = 'Y/m/d';
            break;
        default:
            $date_format = 'd-m-Y';
    }

    $tvvalue = date("$date_format H:i:s", $createdon);

    // Prepare and print the javascript code.
    $output = '
        <script type="text/javascript">
            var tvfield = document.getElementById("tv'.$tvid.'");
            if (tvfield) {
                var tvvalue = tvfield.value;
                if (!tvvalue)
                    tvfield.value = "'.$tvvalue.'";
            }
        </script>
    ';

    $e->output($output."\n");
}

After that, mark the OnDocFormRender event at "System Events" tab. You have to have two events checked: OnDocFormRender and OnDocFormSave.

Save the plugin and try to open any documents for editing. You should see that template variable is always filling with the document creation date.

The new part of code executes when the document editing form is rendered. It checks if the active document is already existing document in database and sends query to receive its createdon date.

If previously we could not worry about the date formats, now we should to convert it to be displayed regards to MODx settings. The right format is selects within switch statement and conversion goes right after that.

The final part contains JavaScript code which is printed with output method of Event object. This code just checks if the template variable box is not filled (if so, then template variable was not ever saved) and fills it with actual createdon date already in system format.

Browse on GitHub

By on
If you want to repost this article, please keep the source hyperlink