Include, and style, a Drupal 6 teaser on a node's full view

In the Drupal content management system, a "node teaser" is small bit of content used to encourage you to "read more" of the post. Drupal can set the teaser to the entire length of the post (typically used for blogs where you don't need extra click-through), or can automatically generate the teaser to a specific character length. In the past, you could also manually generate teasers by including <--break--> in the node's body. In Drupal 6, manual teaser definition has been improved with JavaScript wizardry, along with a new checkbox: "Show summary in full view".

But there's a small problem with the use of the word "summary". Generally, when a Drupal teaser is included in the node's full view, it's because it's the introduction of the node itself, not necessarily a teaser or summary of the entire body. Over at gamegrene.com, a node's teaser is, in fact, a summary of the node, and is also displayed on the full view itself. It's not the first paragraph of the article but, rather, is styled differently to provide an overview of what you'll be reading. IBM uses the same model at their developerWorks.

If you placed a "summary" at the beginning of the node's body, unstyled, readability would tend to suffer - you'd have the summary (node teaser), and then, theoretically, the introduction (node body), with no clear indication that two different types of content, with two different purposes, are being served.

As I've been working on moving Gamegrene to Drupal 6 (in time for Dungeon and Dragons 4th Edition, coming June 7th), I had to solve the problem of: how do I theme the teaser differently than the body inside node.tpl.php? By the time the template gets the node data, only $body and $content exist; $content only contains the teaser (for list views) or body (for full views). The teaser never exists in a node's full view as its own variable.

To solve this and get the same view as seen on IBM's developerWorks, I used themename_preprocess_node() to detect if a teaser has been manually set and that the "Show summary in full view" checkbox has NOT been enabled. When that checkbox is checked, Drupal automatically adds the teaser to the node's $body (or $content) - it treats the teaser as the introduction to the post, not an actual summary of what you're reading:

function phptemplate_preprocess_node(&$variables) {
  // we like to display teasers on the node view pages in a different style,
  // but only if they were NOT set to "show summary on full view" (which seems
  // backward, but the implication with that checkbox is that the teaser is
  // PART of the node's body, instead of an actual summary of the entire
  // node's body). if a node's unbuilt body starts with <!--break-->, then
  // a teaser has been manually set, and "show summary" is not checked.
  if ($variables['page'] == TRUE) { // only do this on full page views.
    $node = node_load($variables['nid']); // we reload the node because
    // by the time it gets here <!--break--> has already been filtered out.
    // this if logic stolen from node.module's node_teaser_include_verify().
    if (strpos($node->body, '<!--break-->') === 0) {
      $variables['style_teaser_differently'] = TRUE;
      $variables['teaser'] = check_markup($node->teaser, $node->format, FALSE);
    }
  }
}

Note that the extra node_load() is nothing to worry about - since the node has already been loaded earlier in this execution, node_load() will happily return a cached version, saving us any performance concerns.

Now, it's just a matter of displaying it in node.tpl.php:


  <div class="node-summary"></div>

Comments and concerns? Note that, for my particular needs, I wanted this entirely in a theme - I'm not changing data or its structure, merely its display, so doing this sort of stuff in hook_nodeapi() with a module's overhead would be a little much.

Tags:

Comments

Thanks for putting this out there. I was almost ready to bail from using preprocess for a project I'm working on because of problems I was having accessing node information. I could see that the node information was available in $variables, but when I tried to access it by calling out the array keys it just threw errors about not liking that.

I feel silly thinking about it now, but at the time I didn't even think of doing a node_load, because I figured I was just doing something wrong and that *certainly* I would already have access to the node object/information within the preprocess function. :p

Looks quite reasonable to me. Preprocess functions are an immensely useful feature in D6 (and in D5 if you use Zen theme).

We got too cute with that teaser splitter thing in D6. Thats my .02, and is confirmed by usability testing at UMN.

Yes, I heartily agree.

I'm getting some really strange behavior with my template_preprocess functions. Doing this:
$node = node_load($variables['nid']);
...results in absolutely nothing, even when I print_r it.

This kind of statement:
$node = node_load($variables['node']['nid']);
...results in this error:
Cannot use object of type stdClass as array

So of all things, this works (e.g. the node actually loads):
$node = node_load($variables['node']->nid);

Am I the only one experiencing this behavior - doing node_load on $variables['nid'] actually works for others? (Drupal 6.2, PHP 5.2.3)

$variables['nid'] would only ever exist inside of template_preprocess_node(). If you're inside template_preprocess_page() and you're viewing a node, it'd be in $variables['node']->nid.

Is phptemplate_preprocess_node() should be placed in template.php of my theme?

I've found a solution of my problem: cache should be cleared on every change of template.php.

Forgot to say that better way is use this code:

$variables['node_teaser'] = check_markup($node->teaser, $node->format, FALSE);

instead of:

$variables['teaser'] = check_markup($node->teaser, $node->format, FALSE);

because variable $teaser already exists and is TRUE for teaser-view and is FALSE for full text mode.
Thanks a lot for your article.

$node = node_load($variables['node']['nid']);
makes me error like this: Cannot use object of type stdClass as array

How to fix it?

Using nodeapi hook worked for me. At some point between $op 'view' and 'alter' the $teaser is removed if teaser_include is checked. It's easy to put it back :

function yourmodulename_nodeapi(&$node, $op, $teaser, $page) {
if ($page == true && $node->type == 'blog' && $op == 'view') {
$node->content_teaser = $node->teaser;
}
}

In my node.tpl.php you print $content_teaser

barful thank you very much. It worked for me instantly!

Add new comment