Displaying Hidden Resource Fields

Show hidden resource fields like editedon, editedby, and createdby on the Create/Edit Resource panel


There are several resource fields that are not shown on the Create/Edit Resource panel.

At this writing, the Manager does not show the id, context_key, editedon, createdon, createdby, editedby, or publishedby fields on the Create/Edit Resource panel. The id and context_key fields can be seen in the Resource tree, but if you have a lot of resources, it can be a pain to find them. The other fields are only visible in the database. You might want to see some of these fields when editing a resource. In this article, we'll look at how to display them.


MODX logo


The Method

It's possible to use JavaScript to create, format, and insert the fields anywhere on the Create/Edit Resource panel, but it's extremely difficult and error-prone. The Create/Edit Resource panel is mostly created on the fly by ExtJS/modExt and many of the fields have IDs that are generated automatically and can change over time. I spent some time trying to make this work and got nowhere with it, though I think it's probably doable. Luckily, there's an easier way.

If you create a plugin attached to the OnDocFormRender event, put some HTML in a string, and send it to the modx->event->output() function, MODX will place the HTML at the bottom of the top section on the main tab of the Create/Edit Resource panel (just above the Content section). In the code below, you can see that we've done that at the end of the code, just above the return statement.


If you have code that also uses this technique (e.g., the plugins in the ClassExtender package), the code below will place the elements above or below the ones inserted by that extra, depending on the Priority of the two plugins, set on the System Events tab next to any attached events. Plugins with lower Priority numbers will execute first.


This code will display all the fields you might want to see. If there are some fields you don't want displayed, just comment out or delete the line in the $fields array near the top of the code. Be sure each line in the array ends in a comma. The Tpl used to display each field sets the input section for each field to readonly, because editing these fields directly is a recipe for disaster. That's why MODX doesn't show them. In the code, the attribute is readonly="readonly". If you use just readonly, as is often done, it will work, but the code will not be valid XHTML. To make the fields editable, you need to remove the entire attribute, though it's a terrible idea and I'm not sure MODX would save them correctly.


The Fields

Here's a quick rundown of the most useful hidden resource fields and what is stored in each one.

  • id — ID of the resource
  • context_key — Name of the resource's context (e.g., web)
  • editedon — The date and time of the last update for the resource
  • createdon — The date and time the resource was created
  • createdby — ID of the user who created the resource
  • editedby — ID of the last user to edit the resource
  • publishedby — ID of the user who published the resource

There are actually a number of other fields. It's easy to add them to the display, just add a new line for each one to the array near the top of the plugin code below.


The Code

Because the user fields hold user IDs rather than names, we have to get the information from the user with that ID. Our code will have an option to use the username field for this or the fullname field. We'll also make it possible to format the display of the date fields.

Here's the code of the plugin. I called it ExtraDocFields, but you can use any name you like (note that ClassExtender uses ExtraResourceFields, so don't use that). Just paste the code into a new plugin. On the System Events tab, put a check next to OnDocFormRender, and click on the "Save" button.

$output = '';
$value = '';
$dateFormat = "%b %d, %Y";
$fullName = true;

$fields = array(
     'Resource ID,id,integer',
     'Context,context_key,default',
     'Last Edited On,editedon,date',
     'Created On,createdon,date',
     'Created By,createdby,user',
     'Edited By,editedby,user',
     'Published By,publishedby,user',

);

/* Don't execute for new documents.
   The fields would be bogus except for context_key */

if ($mode == modSystemEvent::MODE_NEW) {
    return '';
}


foreach($fields as $field) {
  $parts = explode(',', $field);
  if (count($parts) != 3) {
    $caption = 'Error: ';
    $value = 'Malformed array member';
    $output .= '<div class="x-form-item x-tab-item"><label  class="x-form-item-label" style="color:red">' . $caption . ' <span>' . $value . '</span></label></div>';
  } else {

    $caption = $parts[0];
    $fieldName = $parts[1];
    $type = $parts[2];
    $value = $resource->get($fieldName);

    switch ($type) {
      case 'date':
        $value = strftime($dateFormat, strtotime($value));
        break;

      case 'user':
        if ($fullName) {
          $profile = $modx->getObject('modUserProfile', array('internalKey' => $value));
          if ($profile) {
              $value = $profile->get('fullname');
          }
        } else {
          $userObject = $modx->getObject('modUser', $value);
          if ($userObject) {
              $value = $userObject->get('username');
          }
        }
        break;

      case 'integer':
      default:
        /* Value used as is */
        break;
    }
   $fieldTpl = <<< TPL
    <div class="x-form-item x-tab-item">
        <label for="modx-resource-{$fieldName}" class="x-form-item-label">{$caption}</label>
        <div class="x-form-element" id = "x-form-el-modx-resource-'{$fieldName}" style="padding-left:0;">
             <input type = "text" size="30" readonly="readonly" autocomplete = on" msgtarget="under" id="modx-resource-{$fieldName} name="{$fieldName}"
                 class="x-form-text x-form-field" title="" style = "width: 973px;" value="{$value}">
             <div class="x-form-clear-left"></div>
         </div >
     </div>
TPL;
    $output .= $fieldTpl;

  }

}
// $modx->log(modX::LOG_LEVEL_ERROR, 'Output: ' . $output);

$modx->event->output($output);
return '';

The code starts by initializing the $output variable to an empty string, and setting the $dateFormat and $fullName options. The $dateFormat string will be sent to the PHP strftime() function. You can see the format string options in the table on the PHP strftime() manual page. Both the date and the time can be displayed in a wide variety of formats. If the $fullName variable is set to false, the username will be used.

Next, we create an array with the fields to show. Each field has three elements, separated by commas. The first one is the caption to be shown for the field, the second one is the field name in the database, the third is the type of field it is. Valid types are date, user, integer, and default. Default fields will be shown exactly as they are retrieved from the DB.

Once we have the $fields array, we loop through it, adding the appropriate stuff to the $output variable as we go. The explode() function returns a PHP array containing the three members of the array element. If any element doesn't have exactly three parts, we add an error message to the output. If the array element is valid, we use the three member of the $parts array to set the $caption, $fieldName, and $type variables. Then, we get the value of the field from the $resource object which is set automatically by MODX when the plugin is called. The value goes in the $value variable, but it may be modified in the switch statement below.

Each section of the switch statement handles a different type of field.

For date fields, MODX returns a human-readable date/time, which is probably not in the format you want, so we convert it to a timestamp with strtotime(), and then call strftime() using our own date format to make it display in our preferred form.

The user date fields are a little trickier because the username is in the modUser object and the full name is in the modUserProfile object. Depending on the value of the $fullName variable, we get the appropriate object. Notice that the user object is retrieved directly with the user ID. The user profile object, though, is retrieved by looking for that value in the internalKey field. If you get a profile using the user's ID, it will usually work, but not always. In the profile table, the user's ID is held in the internalKey field and the id field is arbitrary. Since users and their profiles are almost always created at the same time, the two are often the same, but over time, they can diverge.

Integer and default fields are not modified. They're used just as they come from the DB. The 'integer' and 'default' cases in the switch statement are not actually necessary, but they make the code easier to understand.

Finally, we use our Tpl to create the output for the field being processed and add it to the $output variable. Notice that this happens inside the loop, but after the switch statement when the $value is in the form we want.

The Tpl is in heredoc syntax. I find it much easier to use this form with complex HTML strings. In that syntax, all single and double quotes are preserved as is, and any variable names are replaced with the values of those variables. Another way to go would have been to create an actual Tpl chunk in the Manager with placeholders for the variables, but that would have meant creating an extra array of elements with the placeholder name as the key and the placeholder value as the value. Doing it as we have avoids the overhead of calling $modx->getChunk() and having MODX parse the chunk and replace all the placeholders each time through the loop.

Finally, we call $modx->event->output() with our string of HTML ($output) as the argument.


Styling the Display

The current code mimics the format of the standard fields of the Create/Edit Resource panel, but it pushes the content section down (depending on how many of the fields you show). On some displays, it could be off the screen. It's certainly possible to reformat the display. The values could be shown on the same line as the captions. In fact, the captions and values could all be shown on the same line. The easiest and safest way to reformat the extra field displays would be to add or modify inline styles for the elements to the Tpl code without changing the existing MODX classes. You could, for example, add something like style="display:inline; margin:5px 15px;" in the Tpl code to make the everything appear on the same line. Any inline styles you add this way will override the MODX CSS.


Moving the Hidden Field Display

In the Tpl chunk used to display the fields, I've used the MODX standard IDs for each field. I haven't tested it, but I think it might be possible to move the fields around with Form Customization. If that works, the extra fields could go on the Settings tab, or on another existing tab. In theory, you could create another tab and put them there. Doing this is beyond the scope of this article, but feel free to attempt it.


Coming Up

In the next series of articles, we'll look at some methods for scraping, parsing, and using the GitHub API to get information.


Looking for high-quality, MODX-friendly hosting? As of May 2016, Bob's Guides is hosted at Hosting.com (formerly A2 Hosting). (More information in the box below.)



Comments (0)


Please login to comment.

  (Login)