Administrators are presented with a special marker when content is new or has been updated in the Administration section of their site at webSite.com/admin/content/node. Additionally, in node lists, the module tracker informs any logged-in user if he or she hasn't read a particular (recently created) node (using the marker new), or if a node he/she's read already was modified (using the marker updated). You, the themer, may want everyone, including “anonymous users”, to be informed of updates to nodes right inside their content. This information may specify who last edited the node and when. Note that the last editor of a content may not be the creator of that content, and I'll take this into account in my “solution”. In the following theming tweak, you'll add Last edited by name some time ago information to your nodes' content.
Here is what you'll try to achieve:
Edit the file template.php to pass an additional variable to the node template, a variable we'll call $last_edit...
print that variable in our node.tpl.php file, and...
style this added markup as needed in style.css.
Before you apply this solution to your theme, we will review how Drupal deals with node editing and node revisions. Read carefully.
If the editor of the node doesn't edit the Authored by field under Authoring information, the recorded author of the node remains unchanged. What that means is that the variables $name and $uid in node.tpl.php will output the same HTML. However, if the editor is not the person who authored the node, the revision_uid (user ID) of the current revision does change to show who edited the node. In node.tpl.php, the variable $revision_uid always tells us who was the last person to edit the current version of a node.
If the editor changes the Authored by field under Authoring information, the variables $name and $uid in node.tpl.php will change to reflect whatever user the editor has picked as new author. However, still in node.tpl.php, the variable $revision_uid will provide us with the user ID of the editor.
No one with permission to edit a node can effectively edit it without a record of his action being saved to the Drupal database, a record of his action under his name. The info about any node version in the table {node_revision} will tell us when and by whom that version was last edited.
What has been said previously still applies. If the Authored by field isn't edited, the author of the new revision and the author of the old revision will be the same person, regardless of who created the new revision. The variable $revision_uid will provide us with the user ID of the creator of the new revision.
If the editor changes the Authored by field under Authoring information when creating a new revision, the info about the author of the node will reflect that change.
What follows is a partial list of the variables available to node.tpl.php.
Available variables:
* - $page: Flag for the full page state.
* - $name: Themed username of node author output from theme_username().
* - $uid: User ID of the node author.
* - $vid: Current version ID of the node, e.g. the version to output.
* - $revision_uid: User ID of the last editor of the node version with $vid.
* - $created: Time the node was published formatted in Unix timestamp.
* - $changed: Time the node was last edited formatted in Unix timestamp.
You can find an exhaustive list of the variables available to node.tpl.php if you inspect a node's content using the Themer Info widget that comes with the Devel module. Look under Template Variables:
You will use a prepocess function to pass a new, e.g. additional, variable to your node template, ie: $last_edit. Hence, you will need to add a phptemplate_preprocess_node() function if it has not already been defined to your template.php file. Open your theme template.php file in a text editor, and add the following code (please do read the comments):
/** * Override or insert PHPTemplate variables into the node template. */ function phptemplate_preprocess_node(&$vars) { /* * If the node is shown on its dedicated page and * the node was edited after its creation. */ if ($vars['page'] && $vars['created'] != $vars['changed']) { $time_ago = format_interval(time() - $vars['changed'], 1); /* * If the last person who edited the node * is NOT the author who created the node. */ if ($vars['uid'] != $vars['revision_uid']) { // Let's get the THEMED name of the last editor. $user = user_load(array('uid' => $vars['revision_uid'])); $edited_by = theme('username', $user); } /* * If the last person who edited the node * is also the author who created the node, * we already have the THEMED name of that person. */ else { $edited_by = $vars['name']; } /* Adding the variable. */ $vars['last_edit'] = t('Last edited by !name about @time ago.', array('!name' => $edited_by, '@time' => $time_ago)); } }
After that, you edit your node.tpl.php file to print your new variable. Take note that the variable will be undefined if we're on a node list page, or if the node wasn't edited since its creation. So we won't add a div unless our variable is defined.
<?php if ($last_edit): ?> <div class="last-edit clear-block"> <small><?php print $last_edit; ?></small> </div> <?php endif; ?>
You can pick a special color for that added text, and increase the white space above and below it, with this CSS rule, added to the style.css stylesheet of your theme:
/** * Last edit rules */ .last-edit { color: #ca481c; margin: 1em 0pt; }
Because it makes use of a preprocess function, this solution will work in Drupal 6 only. There's an equivalent method for Drupal 5 themes, and if someone asks for it I will provide it.
Question 1. Why use the function theme('username', ...)? Why aren't we just outputing the name of the editor as is?
You could. When using the function theme('username', $user), the name of the user becomes a link to his profile page under certain conditions. It's very likely you may not like that. If you don't, just output the name like so (this is a snippet only):
/* * If the last person who edited the node * is NOT the author who created the node. */ if ($vars['uid'] != $vars['revision_uid']) { $user = user_load(array('uid' => $vars['revision_uid'])); } /* * If the last person who edited the node * is also the author who created the node, * we already have the THEMED name of that person. */ else { $user = user_load(array('uid' => $vars['uid'])); } /* Reading the name property of the user object */ $edited_by = $user->name; /* Adding the variable. */ $vars['last_edit'] = t('Last edited by @name about @time ago.', array('@name' => $edited_by, '@time' => $time_ago));
Note that I am using @name instead of !name in the translation function now. That's because I want the user name to be escaped properly and sanitized before being output to screen. Always do this for user names. The ! prefix used for a placeholder means that the variable it stands for should be used as is.
Question 2. Are variables publicized as being available in a template are the same ones we can read in the parameter $vars passed to a preprocess function, right?
Riiight.
Question 3. Some of these variables we're using don't seem to be listed at the beginning of the file modules/node/node.tpl.php...
True. They are missing from the comment area, because they are less commonly used. That's why the Devel module is tremendously useful to themers in Drupal 6: as a themer, you can use the Themer info widget to get an exhaustive list of the available variables for any template.
Question 4. You say that the variable $last_edit is undefined if we're on a page with a list of nodes, or if the node wasn't edited after its creation. Why is that?
Because of this condition in the preprocess function:
if ($vars['page'] && $vars['created'] != $vars['changed']) {
We are defining the new variable only when we pass through this condition.
$vars['page'] becomes $page in the node template and it's a TRUE/FALSE flag. It is TRUE when the node is shown on its dedicated page at webSite.com/node/x, and FALSE otherwise. You could change this to say if we're not showing the node in teaser view, and in most cases this would have the same effect, but take note that it is possible to show a list of nodes in full view, with the module Views for example.
Changing $vars['page'] to !$vars['teaser'] — and changing the != sign to a 'greater than' sign — will give your script the same behavior in most situations:
if (!$vars['teaser'] && $vars['created'] < $vars['changed']) {