Drupal solutions for news sites: Rich text in node titles

8 Jun

This is part 2 in a series of posts about Drupal solutions for common issues raised in developing news sites. See a brief preamble in my first entry about the topic.

Solution 2: “Hey, I'm writing a book review. How do I make the book title italic in the story headline?”

Many are the times when I've wished we could get over our need to italicize titles of books, films and publications. Sadly, I don't make the rules of typography. Inevitably your editorial people will need to include bold or italic text (or even hyperlinks) in the headline (or the node title, as we developers would call it).
The first issue to tackle is whether you need a WYSIWYG (“what you see is what you get”) text editor. If you're lucky enough to work with writers and producers who know basic HTML or are willing to learn, then I envy you. That said, I don't hold it against these people for not wanting to deal with HTML. It may seem trivial to us, but it isn't necessarily part of their training or job descriptions.

I don't necessarily recommend any rich text editor. If you have to use one, I do recommend using it in conjunction with the WYSIWYG API and Better Formats modules (the latter will let you control the appearance of the rich editor more readily).

The two most used rich text editors in the Drupal world are TinyMCE and FCKeditor. I've used both. My own fairly lay opinion is that TinyMCE is a little more flexible with its plugins and display, while FCKeditor seemed to be easier to control within Drupal in terms of what fields it took over. In the end I've picked TinyMCE over FCKeditor on multiple occasions because editorial disliked how FCKeditor didn't space out lines between paragraphs, and inserted a whole blank paragraph if you hit return twice. Dumb issue, I know. This is just my experience; both editors are hugely complex black boxes and your decision will probably be just as arbitrary.

Anyway, now that that's out of the way, here's how I went about setting up rich titles. There are multiple ways to do this, but this one worked well for me. Install CCK and add a field your article node type. It should be a “text” type field, with “textarea (multiple rows)” as its widget (since rich editors can only take over textareas). Let's call it field_rich_title. Most likely your writers will not need or want to make every node's title rich, so I recommend leaving the field as optional. It's important to tell your editorial people that the plaintext title will always be required, so they should type that first, then copy/paste it into the rich title field and style it there. This is especially convenient since it means they won't paste from MS Word, which will add several terrible non-standard tags.

The question then becomes how to gracefully insert it into the node template for that type. Here's some code that should do most of the legwork if inserted into template.php:

function mytheme_preprocess_node(&$vars) {  
  $vars['plain_title'] = $vars['title'];
  if (isset($vars['node']->field_rich_title[0]['value'])) {
    $title = filter_xss($vars['node']->field_rich_title[0]['value']);
    $vars['title'] = $title;
    if ($vars['page']) {

In this code, the $title variable in your node template will be left alone if field_rich_title is not set. If is set, $title will be replaced with the rich version. It's a good idea to pass the value through filter_xss. Not that your writers are likely to be dropping exploits into the rich title field, but this function also strips all but a few key tags. Specifically, it strips <p> which might produce weird styling if it's within the space normally occupied by the plain text title.

We also want to run the title through drupal_set_title if the $page variable is set (i.e., we're looking at the node view page instead of seeing it in a list).

Note that you don't need to set $plain_title if you don't plan to use it. Some templates like to use this as the name attribute for links to the story and such, though.

Finally, you need to hunt down any place where you use $node->title directly and check for a rich title. In my last installment I described how you might make a user profile page that lists stories a user wrote. Here's how you could modify that code to account for rich titles:

function mytheme_preprocess_user_profile(&$vars) {
  if (isset($vars['account']->uid)) {
    $result = db_query("SELECT n.nid FROM {node} n 
                        LEFT JOIN {content_field_authors} c ON n.nid=c.nid 
                        WHERE n.type='article' AND c.field_authors_uid=%d 
                        ORDER BY n.created DESC", 
    $nodes = array();
    while ($row = db_fetch_object($result)) {
      $nodes[$row->nid] = node_load($row->nid);
      if (isset($nodes[$row->nid]->field_rich_title[0]['value'])) {
        $nodes[$row->nid]->rich_title = filter_xss($nodes[$row->nid]->field_rich_title[0]['value']);
      else {
        $nodes[$row->nid]->rich_title = $nodes[$row->nid]->title;
    $vars['nodes'] = $nodes;

This tacks a rich_title attribute onto the node object, and actually sets it to the plain title if no rich title exists. You should now just use $node->rich_title in all places in your user-profile.tpl.php file.

One last consideration is Views. Odds are you're using it for the front page crawl, a featured stories queue, contributor block, or something like that. If your display style is Nodes, then you're fine since we already enabled the rich title in node templating. If the style is Fields, you're going to need to consult the theming guide to determine how to splice the rich title into your views display. You'll start by adding field_rich_title to the fields you select in the view, but the rest will be quite specific to your site, so it's up to you.

Good luck, and stay tuned for more.