Inserting HTML into node titles

Last modified: February 21, 2008 - 12:33

Drupal strips all HTML from node titles when they're displayed to prevent XSS exploits. However, there are some cases where inline HTML elements are needed, such as when titles contain scientific names.

To work around this, we will use pseudotags like [i] and [/i] which Drupal will safely translate into real HTML tags when the page is displayed.

The PHPTemplate file page.tpl.php will need to be edited in order to make this trick work. Specifically, we need to add two new functions.

<?php
function bb2html($text) {
 
$bbcode = array(
                 
"[strong]", "[/strong]",
                 
"[b]""[/b]",
                 
"[u]""[/u]",
                 
"[i]""[/i]",
                 
"[em]", "[/em]"
               
);
 
$htmlcode = array(
               
"<strong>", "</strong>",
               
"<strong>", "</strong>",
               
"<u>", "</u>",
               
"<em>", "</em>",
               
"<em>", "</em>"
             
);
  return
str_replace($bbcode, $htmlcode, $text);
}

function
bb_strip($text) {
 
$bbcode = array(
                 
"[strong]", "[/strong]",
                 
"[b]""[/b]",
                 
"[u]""[/u]",
                 
"[i]""[/i]",
                 
"[em]", "[/em]"
               
);
  return
str_replace($bbcode, '', $text);
}
?>

This is how you make a phrase in the title italicized:

My title [em]rocks[/em]!

One problem with this approach is that node title also shows up in the page titles, and page titles are not allowed to have any markup. That's where the above bb_strip function comes in. Between the HTML title tags in page.tpl.php, add the following:

<?php print bb_strip($head_title); ?>

And whenever you reference the node title in your template use this:

<?php print bb2html($title); ?>

NOTE: If you use books, this mechanism has a problem unless you are willing to patch book.module. book.module, in the function book_tree_recurse, creates links to nodes by their title, and of course doesn't know to use your code

regexes

wholcomb - August 21, 2006 - 05:59

If you want to guarantee that tags are closed, you can use the clichéd regex with a backreference:

<?php
function bb2html($text) {
 
$bbcode_regex = '/\[(strong|cite|em)\](.*)\[\/\1\]/';
  return
preg_replace($bbcode_regex, '<$1>$2</$1>', $text);
}
?>

One correction

sander-martijn - August 21, 2007 - 20:04

If you want/need to access these functions from node.tpl.php or any other file you will need the function to live in template.php. Even if you are only calling it in page.tpl.php it's probably a better idea to keep it in template.php for the sake of code separation. Other than that, great fix for an annoying problem. Now if only we can find a solution for special characters.

Newlines

felipensp - September 4, 2007 - 11:00

Use the modifier 's' in regex to match newline inside of tags.

Using Views...

r00lnyi - March 6, 2008 - 14:31

If you-re using views and want do highlight one or some titles in views-result page or block .....

1. First of all you need edit view.module
Take this function

function theme_views_view_list($view, $nodes, $type) {
  $fields = _views_get_fields();

  foreach ($nodes as $node) {
    $item = '';
    foreach ($view->field as $field) {
      if (!isset($fields[$field['id']]['visible']) && $fields[$field['id']]['visible'] !== FALSE) {
        if ($field['label']) {
          $item .= "<div class='view-label ". views_css_safe('view-label-'. $field['queryname']) ."'>" . $field['label'] . "</div>";
        }
        $item .= "<div class='view-field ". views_css_safe('view-data-'. $field['queryname']) . views_theme_field('views_handle_field', $field['queryname'], $fields, $field, $node, $view) . "</div>";
      }
    }
    $items[] = "<div class='view-item ". views_css_safe('view-item-'. $view->name) ."'>$item</div>\n"; // l($node->title, "node/$node->nid");
  }
  if ($items) {
    return theme('item_list', $items);
  }
}

and replace by this

function theme_views_view_list($view, $nodes, $type) {
  $fields = _views_get_fields();

  foreach ($nodes as $node) {
    $item = '';
    foreach ($view->field as $field) {
      if (!isset($fields[$field['id']]['visible']) && $fields[$field['id']]['visible'] !== FALSE) {
        if ($field['label']) {
          $item .= "<div class='view-label ". views_css_safe('view-label-'. $field['queryname']) ."'>" . $field['label'] . "</div>";
        }
        $item .= "<div class='view-field ". views_css_safe('view-data-'. $field['queryname']) ."' id='v".$node->nid."'>" . views_theme_field('views_handle_field', $field['queryname'], $fields, $field, $node, $view) . "</div>";
      }
    }
    $items[] = "<div class='view-item ". views_css_safe('view-item-'. $view->name) ."'>$item</div>\n"; // l($node->title, "node/$node->nid");
  }
  if ($items) {
    return theme('item_list', $items);
  }
}

So every view element item has id="number of node" anywhere. Do not forget you cant use digits only in css id's so i added "v" as prefix.

Then just css. For example ...

#v3640 a:link, #v3640 a:visited  {
color: red;
font-weight: bold;

}

submitted as a patch

christefano - May 1, 2008 - 21:28

This proposed modification has been submitted as a patch. Please review it at http://drupal.org/node/253686 when you have a chance.

 
 

Drupal is a registered trademark of Dries Buytaert.