First off, thanks for the awesome theme! It's been the best tool for me so far in learning how Drupal 6's theming works. I've already used Framework as the basis for my custom themes on two sites that I've launched in the last couple of months:

http://www.westerntech.edu
http://www.rallycapconsulting.com

Anyway, something that's been really helpful in modifying individual pages/sections/views/etc is a wider array of dynamic body classes in the markup. The first thing to note is the template engine variable $body_classes, which is defined in the template_preprocess_page function. If you print that variable in page.tpl.php, you get some useful classes like "sidebar-left one-sidebar logged-in not-front". I realize that you have a similar function in Framework's template.php (framework_body_class), but isn't that function redundant in Drupal 6?

The Zen theme (which I don't use, but I do like to steal code from) expands on $body_classes in the zen_preprocess_page function. After stripping some Zen-specific code, here's the chunk that I usually steal and drop in to Framework's template.php:

function framework_id_safe($string) {
  // Replace with dashes anything that isn't A-Z, numbers, dashes, or underscores.
  $string = strtolower(preg_replace('/[^a-zA-Z0-9-]+/', '-', $string));
  // If the first character is not a-z, add 'id' in front.
  if (!ctype_lower($string{0})) { // Don't use ctype_alpha since its locale aware.
    $string = 'id' . $string;
  }
  return $string;
}

function framework_preprocess_page(&$vars, $hook) {
  // Classes for body element. Allows advanced theming based on context
  // (home page, node of certain type, etc.)
  $classes = split(' ', $vars['body_classes']);
  // Remove the mostly useless page-ARG0 class.
  if ($index = array_search(preg_replace('![^abcdefghijklmnopqrstuvwxyz0-9-_]+!s', '', 'page-'. drupal_strtolower(arg(0))), $classes)) {
    unset($classes[$index]);
  }
  if (!$vars['is_front']) {
    // Add unique class for each page.
    $path = drupal_get_path_alias($_GET['q']);
    $classes[] = framework_id_safe('page-' . $path);
    // Add unique class for each website section.
    list($section, ) = explode('/', $path, 2);
    if (arg(0) == 'node') {
      if (arg(1) == 'add') {
        $section = 'node-add';
      }
      elseif (is_numeric(arg(1)) && (arg(2) == 'edit' || arg(2) == 'delete')) {
        $section = 'node-' . arg(2);
      }
    }
    $classes[] = zen_id_safe('section-' . $section);
  }
  $vars['body_classes_array'] = $classes;
  $vars['body_classes'] = implode(' ', $classes); // Concatenate with spaces.
  
  $vars['tabs2'] = menu_secondary_local_tasks();

I also changed the body tag in page.tpl.php to use this variable, instead of framework_body_class, as such:

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

After these changes, I get a couple more valuable body classes. For example:

<body class="not-front not-logged-in one-sidebar sidebar-right page-about-us-faculty section-about-us"> 
or 
<body class="not-front logged-in one-sidebar sidebar-left page-admin-build-block-add section-admin">

The only problem with the above is that it removes your "admin" class, effectively replacing it with "section-admin". To fix the minor issues that causes, I usually update Framework's style.css, changing all instances of .admin to .section-admin. You could also add the appropriate code from framework_body_class to add "admin" back in to the $body_classes array.

Is this something you'd be interested in incorporating in future versions? Thanks again!

Comments

peterjmag’s picture

Forgot to mention one other thing: This also changes the "sidebars" class to "two-sidebars", so you'd need to update one selector in style.css.

andregriffin’s picture

Hi Peter

This is incredibly useful! Thanks for being so thorough with this. This will surely be something I'll implement into the next version of Framework.

Nice looking sites by the way.

andregriffin’s picture

To anyone who implements this themselves, note that the ending bracket didn't make it's way into the code above. Should be:

function framework_id_safe($string) {
  // Replace with dashes anything that isn't A-Z, numbers, dashes, or underscores.
  $string = strtolower(preg_replace('/[^a-zA-Z0-9-]+/', '-', $string));
  // If the first character is not a-z, add 'id' in front.
  if (!ctype_lower($string{0})) { // Don't use ctype_alpha since its locale aware.
    $string = 'id' . $string;
  }
  return $string;
}

function framework_preprocess_page(&$vars, $hook) {
  // Classes for body element. Allows advanced theming based on context
  // (home page, node of certain type, etc.)
  $classes = split(' ', $vars['body_classes']);
  // Remove the mostly useless page-ARG0 class.
  if ($index = array_search(preg_replace('![^abcdefghijklmnopqrstuvwxyz0-9-_]+!s', '', 'page-'. drupal_strtolower(arg(0))), $classes)) {
    unset($classes[$index]);
  }
  if (!$vars['is_front']) {
    // Add unique class for each page.
    $path = drupal_get_path_alias($_GET['q']);
    $classes[] = framework_id_safe('page-' . $path);
    // Add unique class for each website section.
    list($section, ) = explode('/', $path, 2);
    if (arg(0) == 'node') {
      if (arg(1) == 'add') {
        $section = 'node-add';
      }
      elseif (is_numeric(arg(1)) && (arg(2) == 'edit' || arg(2) == 'delete')) {
        $section = 'node-' . arg(2);
      }
    }
    $classes[] = framework_id_safe('section-' . $section);
  }
  $vars['body_classes_array'] = $classes;
  $vars['body_classes'] = implode(' ', $classes); // Concatenate with spaces.
 
  $vars['tabs2'] = menu_secondary_local_tasks();
}

This took 1 minute to get working on the http://d6.andregriffin.com development site. It's working brilliantly. Thanks again.

peterjmag’s picture

Great! Glad I could help.

andregriffin’s picture

Status: Active » Fixed

Marked as fixed. To be included in Framework 2.7.

halloffame’s picture

Very useful. Thanks! Subscribing...

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

jpshayes’s picture

Sorry, I am kind of new around here, but, I can not seem to get this to work. When I try adding the code provided by andre to the bottom of the template.php file (not including the open and close php tags) and replace the body tag in the page.tpl.php with the one provided by peterjmag. I get a blank white screen. Do i need to replace some code in the template.php file or just add it to the bottom?

jpshayes’s picture

Well, I got it to work, I removed this function from the template.php file

/**
 * Override or insert PHPTemplate variables into the templates.
 */
function framework_preprocess_page(&$vars) {
  $vars['tabs2'] = menu_secondary_local_tasks();
}

Is that correct?

peterjmag’s picture

Yep, that's correct. You were probably getting a "Cannot redeclare function" PHP error, which was causing the blank screen. It's important that you only have one definition per function in template.php.

gozigzag’s picture

quick notes: in original code there is one line: $classes[] = zen_id_safe('section-' . $section); that needs to be $classes[] = framework_id_safe('section-' . $section);

also admin is only changed to section-admin as body class. div.admin is still div.admin.

Thanks, very useful!

BrianLewisDesign’s picture

Title: Adding more body classes for page-specific CSS targeting » D6 $body_classes in core.
Component: Code » CSS/HTML markup

In D6, the $body_classes is defined in core. All you need is to echo:
<body class="<?php print $body_classes; ?>">

And for more classes use themer, and:
http://drupal.org/project/themer
<body class="<?php print themer_body_class(); ?> <?php print $body_classes; ?>">