Leveraging Custom Body Classes for Advanced Theming in Drupal 6


Update: Note, Drupal 7 already gives you useful body classes out of the box</strong>

I recently developed a Drupal site where each page in the site was based on a custom content type and needed some very specific theming. Although my custom theme was based on 960.gs, I decided to borrow from the zen theme its custom body class implementation to give more meaningful CSS classes to leverage for theming.

What's a body class?

The body class rendered by the <body> tag in Drupal outputs something like this for example:

<body class="front page-node no-sidebars section-blog">

That's nice but to theme specific sections of a site as I mentioned above, I needed a little more in the body class. You can do this by adding some PHP code to your theme's template.php file. If your theme does not have this you can create it at: /sites/all/themes/[your theme]/template.php Note if you are using the Zen theme or a Zen sub theme, you do not need to do this. Also, replace any instances of "zen" below with the name of your theme.

Add this php code to your template.php file:

function phptemplate_preprocess_page(&$vars, $hook) {

  // Classes for body element. Allows advanced theming based on context.
  // (home page, node of certain type, etc.).
  $body_classes = array($vars['body_classes']);
  if (!$vars['is_front']) {
    // Add unique classes for each page and website section.
    $path = drupal_get_path_alias($_GET['q']);
    list($section, ) = explode('/', $path, 2);
    $body_classes[] = zen_id_safe('page-' . $path);
    $body_classes[] = zen_id_safe('section-' . $section);
    if (arg(0) == 'node') {
      if (arg(1) == 'add') {
        if ($section == 'node') {
         // Remove 'section-node'.
          array_pop($body_classes);
        }
         // Add 'section-node-add'.
        $body_classes[] = 'section-node-add';
      }
      elseif (is_numeric(arg(1)) && (arg(2) == 'edit' || arg(2) == 'delete')) {
        if ($section == 'node') {
         // Remove 'section-node'.
          array_pop($body_classes);
        }
         // Add 'section-node-edit' or 'section-node-delete'.
        $body_classes[] = 'section-node-' . arg(2);
      }
    }
  }
   // Concatenate with spaces.
  $vars['body_classes'] = implode(' ', $body_classes);
}

function zen_id_safe($string) {
  if (is_numeric($string{0})) {
    // If the first character is numeric, add 'n' in front
    $string = 'n'. $string;
  }
  return strtolower(preg_replace('/[^a-zA-Z0-9_-]+/', '-', $string));
}

Once you add this you just need to modify the <body> tag in your page.tpl.php file. Change it to read:

<body class="<?php print $body_classes; ?>">

Once you have done this you should clear your site cache and voila, you now have meaningful advanced body classes being rendered on every page in your site. The possibilities are endless of what you can do with these advanced classes.

For example this page now shows:

<body class="not-front not-logged-in page-node node-type-blog one-sidebar sidebar-left
page-blog-custom-body-class-php-advanced-theming-and-css-drupal-6 section-blog">

Theoretically I could custom theme a blog page by using code such as this:

.node-type-blog {
/** your custom CSS here **/
}

It's now fairly granular for theming so you can really specific of what and how you want to theme.

Update: 01-03-2011

If you are using Drupal's Domain Access Module, you can also render domain body classes with the following code:

global $_domain;
$body_classes []= 'domain-'. $_domain['domain_id'];

Insert this just after this line of code:

$body_classes = array($vars['body_classes']);

The body class output will simply be of the format domain-numerical_id that represents the domain you are currently on that you can use and leverage in your CSS and theming. You could also use the domain site name as check_plain($_domain['sitename']);.

Tags