Add "first" and "last" classes on blocks

Last modified: August 23, 2009 - 15:25

Sometimes, the first or last block in a region needs to be styled different than the rest. To get 'first' and 'last' classes on the first and last block in a region, you need to override two theme functions: theme_block() and theme_blocks().

1) Override theme_blocks()

<?php
function phptemplate_blocks($region) {
 
$output = '';

  if (
$list = block_list($region)) {
   
$blockcounter = 1; // there is at least one block in this region
   
foreach ($list as $key => $block) {
     
// $key == <i>module</i>_<i>delta</i>
     
$block->extraclass = ''; // add the 'extracclass' key to the $block object
     
if ($blockcounter == 1){ // is this the first block in this region?
       
$block->extraclass .= ' first'
      }
      if (
$blockcounter == count($list)){ // is this the last block in this region?
       
$block->extraclass .= ' last';
      }
     
$output .= theme('block', $block);
     
$blockcounter++;
    }
  }

 
// Add any content assigned to this region through drupal_set_content() calls.
 
$output .= drupal_get_content($region);

  return
$output;
}
?>

2) Override theme_block()

<?php
function phptemplate_block($block) {
 
$output  = "<div class=\"block block-$block->module $block->extraclass\" id=\"block-$block->module-$block->delta\">\n"; // in this line, the extraclass value is added as class
 
$output .= " <h2 class=\"title\">$block->subject</h2>\n";
 
$output .= " <div class=\"content\">$block->content</div>\n";
 
$output .= "</div>\n";
  return
$output;
}
?>

That's it!

already overriding _block function phptemplate.engine

vood002 - February 21, 2009 - 20:43

Thank you very much for the function... I was able to apply it to my theme.

I'm not entirely sure why this was, but my phptemplate was already overriding the theme_block function with a phptemplate_block() function in the phptemplate.engine file.

Once I thought about it it made sense, however, as I am using a block.tpl.php file...so I got this function to work by adding the phptemplate_blocks() function to my template.php file, then changing

class="block <?php print $block_classes; ?>

to

class="block <?php print $block_classes.$block->extraclass; ?>

in my block.tpl.php file. I'm kind of curious how I would override other theme functions that have already been overridden in the phptemplate.engine file as this was the approach I first attempted to no avail, but I'm just happy I got this to work.

Drupal 6 + Zen Theme

remi - February 23, 2009 - 16:48

I had to do something different to add "first" and "last" classes to my blocks. The site I was working on is using Drupal 6 and its custom theme is based on Zen.

To add "first" and "last" classes to blocks in this situation, I had to add the following in my theme's template.php:

<?php
function themename_preprocess_block(&$vars, $hook)
{
    static
$counts;
    if(!isset(
$counts)) $counts = array();
   
$region = $vars['block']->region;
    if(!isset(
$counts[$region])) $counts[$region] = count(block_list($region));
   
$count = $counts[$region];
   
$extremity = '';
    if(
$vars['id'] == 1) $extremity = 'first';
    if(
$vars['id'] == $count) $extremity = 'last';
   
$vars['classes'] .= $extremity != '' ? ' ' . $extremity : '';
}
?>

My preferred D6 method

marcvangend - May 1, 2009 - 13:31

For Drupal 6, I prefer this method (basically a rewrite of the D5 method above, the code goes in template.php):

<?php
function themename_blocks($region) {
 
$output = '';

  if (
$list = block_list($region)) {
   
$blockcounter = 1;
    foreach (
$list as $key => $block) {
     
$block->extraclass = '';
     
$block->extraclass .= ( $blockcounter == 1 ? ' block-first' : '' ); 
     
$block->extraclass .= ( $blockcounter == count($list) ? ' block-last' : '' ); 
     
$output .= theme('block', $block);
     
$i++;
    }
  }

 
// Add any content assigned to this region through drupal_set_content() calls.
 
$output .= drupal_get_content($region);

  return
$output;
}

function
themename_preprocess_block(&$vars){
 
$vars['classes'] .= $vars['block']->extraclass;
}
?>

This method is (at least in theory) better for performance: block_list() is already called in themename_blocks(), so I don't want to call it again in themename_preprocess_block().

I noticed a typo in the above

jstoller - May 5, 2009 - 18:19

I noticed a typo in the above code when I tried to implement it. It should be as follows:

<?php
function themename_blocks($region) {
 
$output = '';

  if (
$list = block_list($region)) {
   
$blockcounter = 1;
    foreach (
$list as $key => $block) {
     
$block->extraclass = '';
     
$block->extraclass .= ( $blockcounter == 1 ? ' block-first' : '' );
     
$block->extraclass .= ( $blockcounter == count($list) ? ' block-last' : '' );
     
$output .= theme('block', $block);
     
$blockcounter++;
    }
  }

 
// Add any content assigned to this region through drupal_set_content() calls.
 
$output .= drupal_get_content($region);

  return
$output;
}

function
themename_preprocess_block(&$vars){
 
$vars['classes'] .= $vars['block']->extraclass;
}
?>

For my own uses I only needed to mark the last block in a class, so I addapted this as follows:

<?php
function csc_zen_blocks($region) {
 
$output = '';

  if (
$list = block_list($region)) {
   
$blockcounter = 1;
    foreach (
$list as $key => $block) {
     
$block->is_last = ( $blockcounter == count($list) ? true : false );
     
$blockcounter++;
     
$output .= theme('block', $block);
    }
  }

 
// Add any content assigned to this region through drupal_set_content() calls.
 
$output .= drupal_get_content($region);

  return
$output;
}

function
csc_zen_preprocess_block(&$vars, $hook) {
  if (
$vars['block']->is_last) :
   
$vars['classes'] .= ' region-last';
  endif;
}
?>

––
Jeremy Stoller
Senior Graphic Artist
California Science Center

Hey Jeremy, Thank you, and

Campsoupster - October 4, 2009 - 01:22

Hey Jeremy,

Thank you, and the rest of the folks on this post for this snippet. I just added it to my customized Basic theme. I did notice a small issue, however. B/c of the way that you have the counter setup, if there's only one block in the region, it adds both the first and last classes. I'm not sure if that's intentional - you could argue it either way. Just something for folks to keep in mind.

Cheers,
Sean
ThinkShout.com

Sean Larkin
Think!Shout

 
 

Drupal is a registered trademark of Dries Buytaert.