The read more link in teaser hack

Unlike Wordpress, Drupal offers no way in core to put a read more link inline with the teaser. Out-of-the-box Drupal’s teaser customizing is very basic. You may either 1- insert in your posting an HTML comment à la Wordpress, <!--break-->, to tell Drupal where you want your teaser to end (in Wordpress, you’ll type the Quicktag <!--more--> instead), or 2- you leave it up to Drupal to make a teaser out of the n first words of the post. Drupal will take that teaser and the full content and store them separately in the database. In Wordpress, by default, you’ll find a “more...” link at the end of the teaser, inviting you to read the full posting. Drupal does offer a “read more” link, but you’ll find it with the other posting links, away from the teaser. Chances are : readers will miss that link and believe that the teaser is all there is to read in the posting.

This article describes a simple hack to remedy the situation. It works in Drupal 4.7 and 5.

UPDATE April 8th, 2008 : it works in Drupal 6 as well. Make sure your code accounts for the change in the l() function signature. For this, refer yourself to the Drupal API — follow the link.

Decide on which HTML text you want to display as your read more link. Will that be “more...” like in Wordpress, or “more »»” ? That text will become YOUR_TEXT_FOR_THE_LINK in the hack below. If you need to use a special character, use an entity :

Character you want to display Corresponding entity
» &raquo;
&rarr;
&rArr;

In a text editor, open the file modules/node/node.module if you’re using Drupal 5.x, or, alternatively, modules/node.module if you’re using Drupal 4.7.x.

Look for the definition of the function node_prepare(). Once you find it, add to it the following line of code :

<?php
function node_prepare($node, $teaser = FALSE) {
 
$node->readmore = (strlen($node->teaser) < strlen($node->body));

  if (
$teaser == FALSE) {
   
$node->body = check_markup($node->body, $node->format, FALSE);
  }
  else {
   
/* Beginning of hack -- modified by YOUR_NAME */
   
if($node->readmore) {
     
$node->teaser .= '&nbsp;'. l(t('YOUR_TEXT_FOR_THE_LINK'),
       
'node/' . $node->nid, array('class' => 'read-more',
       
'title' => 'Read the rest of this posting.'),
       
NULL, NULL, TRUE, TRUE);
    }
   
/* End of hack */
   
$node->teaser = check_markup($node->teaser, $node->format, FALSE);
  }

 
$node->content['body'] = array(
   
'#value' => $teaser ? $node->teaser : $node->body,
   
'#weight' => 0,
  );

  return
$node;
}
?>

Do you want to remove the existing read more link that’s added by Drupal to the posting links ? Add two lines of code instead :

<?php
function node_prepare($node, $teaser = FALSE) {
 
$node->readmore = (strlen($node->teaser) < strlen($node->body));

  if (
$teaser == FALSE) {
   
$node->body = check_markup($node->body, $node->format, FALSE);
  }
  else {
   
/* Beginning of hack -- modified by YOUR_NAME */
   
if($node->readmore) {
     
$node->teaser .= '&nbsp;'. l(t('YOUR_TEXT_FOR_THE_LINK'),
       
'node/' . $node->nid, array('class' => 'read-more',
       
'title' => 'Read the rest of this posting.'),
       
NULL, NULL, TRUE, TRUE);
     
$node->readmore = FALSE; // To remove the default read more link
   
}
   
/* End of hack */
   
$node->teaser = check_markup($node->teaser, $node->format, FALSE);
  }

 
$node->content['body'] = array(
   
'#value' => $teaser ? $node->teaser : $node->body,
   
'#weight' => 0,
  );

  return
$node;
}
?>

Upload your edited file to your server.

Notes

There is one contributed module that does this, but it modifies the teaser after the teaser has been filtered, instead of before. That module is bloated, i.e. about 200 lines of code... while we’re only adding two lines here, with surgical precision and no performance hit.

The read more link we’re generating is a URL that points to the alias of the full posting as in http://11heavens.com/read-more-link. It’s very important to generate a URL here, rather than a web-root relative link like /read-more-link, because teasers are displayed in RSS feeds, on other web sites. We don’t want that read more link to point to a non-existant node on the other web site.

You may want to change the class and title attributes of the link. The title attribute in the code sample above is Read the rest of this posting. It is what’s used in English by default for the read more link that’s with the other node links, i.e. in $links.

In the l() call, we’re using TRUE as sixth (6th) argument because we want an absolute path, that is, a URL, for the link. And we’re adding TRUE as seventh (7th) argument if we’re using HTML entities in our read more link.

l($text, $path, $attributes = array(), $query = NULL, $fragment = NULL, $absolute = FALSE, $html = FALSE)

$absolute
Whether to force the output to be an absolute link (beginning with http:). Useful for links that will be displayed outside the site, such as in an RSS feed.
$html
Whether the title is HTML, or just plain-text. For example for making an image a link, this must be set to TRUE, or else you will see the encoded HTML. Same thing if you are using HTML entities, you need to set it to TRUE, or else you will see something like read&nbsp;more&nbsp;&rArr;.

Hacking the core

Personally, I hack the core when there is no other solution that I know of to fix something I dislike. If there is another solution, such as one that involves overriding a themeable function or modifying a template file, I’ll do that instead. Hacking the core makes it difficult to upgrade Drupal. After each upgrade, I have to go through my list of hacks and re-implement them as needed. I keep a list, a short list (I currently have 3 very simple hacks in core, one that is a fix to image.inc to improve the jpeg quality of generated images). In my list, I write down 1.- the file name, 2.- the number (#) of the edited line, and 3.- some description of what I have done and why. Additionally, I put my full name in the code in a comment next to the hack I implement (to make it easy to search for in my text editor). As my understanding of Drupal increases, some hacks are dropped. And I make sure to only implement simple hacks. UPDATE April 14th, 2007 : Hacking the core is neither for children, nor monkeys. I will not condescend to my readers by introducing this article with a huge blinking warning sign *CAUTION-WHAT-YOU-ARE-ABOUT-TO-DO-IS-DANGEROUS* because it simply is not dangerous. Whenever we believe that someone is not as smart as us, chances are the truth is opposite, and life will show us that. Have fun with your CMS, it’s all that matters.