Give your Drupal blocks a more descriptive HTML ID attribute

29-Oct-2008
Filed under: Drupal, Drupal 5.x

I don't know about you, but I like my HTML ID attributes and therefore my CSS selectors to be descriptive. It makes both my HTML and CSS more readable, and lets me scan a document more effectively, locating the section I need with relative ease.

If you create a custom Drupal block the system will typically output a line of HTML which might look like this:

<div id="block-block-1" [...]

That doesn't help me very much when I have a bunch of custom blocks and I'm trying to track down a particular one. The code snippet below will change the way Drupal outputs block IDs in your templates, making them a little more palatable:

<div id="block-block-my-block-description" [...]

Step 1: Copy the code snippet below to your theme's template.php file (create one in your theme's folder if it doesn't exist). The snippet will try to calculate the new ID by looking at the block description field. If that's blank, it will revert to Drupal's standard method of calculating the ID.

<?php
function block_id(&$block) {
 
$info = module_invoke($block->module, 'block', 'list');
  if (
$info[$block->delta]['info']) {
   
$block_id = 'block-' . $block->module . '-' . $info[$block->delta]['info'];
   
$block_id = str_replace(array(' ', '_'), '-', strtolower($block_id));
    return
preg_replace('/[^\-a-z0-9]/', '', $block_id);
  } else {
    return
'block-' . $block->module . '-' . $block->delta;
  }
}
?>

Step 2: In block.tpl.php change the opening DIV tag to match the following line:

<div id="<?php print block_id($block); ?>" class="clear-block block block-<?php print $block->module ?>">

The line above is based on the opening block DIV tag from Drupal's Garland theme. If your opening DIV tag doesn't match, just make sure you change the value of the ID attribute to match.

Comments

very useful tip - thanks.
the combination of the $block->module and the $block->id or $block->delta will keep the dom id's from conflicting right?

2 things:
1. don't forget to retain on the first line of block.tpl.php or your layout will explode.
2. I added some static variables to keep from processing the same things repetitively (preg_replace()s and module_invoke()s can get expensive) and changed the function name to try to ensure fewer collisions. I think it works ok - lemme know if you find any bugs:

<?php
function phptemplate_block_id(&$block) {
  static
$lists, $infos, $subjects;
 
$prefix = 'block-';
 
  if(isset(
$lists[$block->module])) {
   
$info = $lists[$block->module];
  } else {
   
$info = $lists[$block->module] =
   
$module_invoke($block->module, 'block', 'list');
  }
 
  if(isset(
$infos[$info[$block->delta]['info']])) {
   
$block_id = $infos[$info[$block->delta]['info']];
  } else {
   
$block_id = $infos[$info[$block->delta]['info']] = strtolower($block->module . '-' . preg_replace("/[^a-zA-Z0-9]/","", $info[$block->delta]['info']));
  }
   
  if(
$block_id) { return $prefix . $block_id; }

  if (isset(
$subjects[$block->subject])) {
   
$block_id = $subjects[$block->subject];
  } else {
   
$block_id = $subjects[$block->subject] = strtolower($block->module . '-' . preg_replace("/[^a-zA-Z0-9]/","", $block->subject));
  }
 
  return
$prefix . $block_id;

}
?>

point #1 above:
1. don't forget to retain on the first line of block.tpl.php or your layout will explode.
should be
1. don't forget to retain "<div class="block-inner">" on the first line of block.tpl.php or your layout will explode.

very nice! almost seems a shame to give up the desc field to write IDs :)

have look at block class,
it adds a field in the block config screen for a custom class.

this snippet could even be used with $block_id for more semantic heading tags (h2, h3, h4) instead of the same default one across blocks.

God bless you :D
This really helps me

Thanks for your very useful code! I love it!

I would just suggest that you also pass $block->module in the preg_replace arguments, so that the module name is also "CSS id proof".

<?php
$block_id
= $infos[$info[$block->delta]['info']] = strtolower($block->module . '-' . preg_replace("/[^a-zA-Z0-9]/","", $info[$block->delta]['info']));
?>

becomes
<?php
$block_id
= $infos[$info[$block->delta]['info']] = strtolower(preg_replace('/[^a-zA-Z0-9]/', '-', $block->module . '-' . $info[$block->delta]['info']));
?>

By the way, if you want to improve even more in performances, you may use single quotes instead of double quotes as often as you can. This will avoid PHP parsing the strings to find "in-string" variables.

Excellent! Thanks.

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <i> <b> <cite> <code> <a>
  • Lines and paragraphs break automatically.
  • You may post code using <code>...</code> (generic) or <?php ... ?> (highlighted PHP) tags.
CAPTCHA
Are you human?