Giving a Drupal 6 Theme Control of Stylesheets

Drupal has always had an awesome theme hook system. It allows a module to define some output, but gives the theme a chance to override that default. What always bugged me was that modules could also add stylesheets. With Drupal 6, you have two options for overriding module defined styles.

The first method available is to override the individual styles with your own. This means that the user has to download module-style.css to get the styles defined by the module and then theme-style.css to unset those styles. This could potentially be a lot of file downloads to do and undo an action. Plus, your theme styles will become bloated with styles whose sole purpose is to undo something that probably shouldn’t have been done in the first place.

Drupal 6 brought with it a new method by which to override module styles. You can now define a style sheet in your theme.info file with the same name, thus canceling the module style. This reduces the file loads to simply theme-style.css. The problem I have with this method is that now I have to make a css file, even empty files, to override any module style sheet I want to disable. This seems a little hefty to me. I’d like to take it one step further.

My plan is to choose the stylesheets that I want to keep, rather than choosing the stylesheets I want to give up. http://drupal.org/project/stylestripper is a good start. I like the direction that they took, but a module is now in charge of my theme and I’m trying to take control on the theme level. I actually used code from Style Stripper to accomplish my goals.

I feel that this is another good time to use the new theme settings option in Drupal 6. So, I started off by editing my theme-settings.php:

<?php
function myTheme_settings($saved_settings) {
 
/*definint a default value*/
 
$defaults = array(
   
'myTheme_module_css' => 0,
  );
 
$settings = array_merge($defaults, $saved_settings);
  
/*checkbox to disable all module css*/
 
$form['myTheme_module_css'] = array(
   
'#type' => 'checkbox',
   
'#title' => t('Enabled all module css'),
   
'#default_value' => $settings['myTheme_module_css'],
  );
 
/*checkboxes for enabling individual module css*/
 
$form['myTheme_module_css_fieldset'] = array(
     
'#type' => 'fieldset',
     
'#title' => t('Enable individual module css'),
     
'#collapsible' => true,
     
'#collapsed' => true,
  );
 
 
/*any functions used in this file need to be defined in theme-settings.php*/
 
$module_css = myTheme_get_module_css();
 
  foreach (
$module_css as $key => $file) {
   
$var = 'myTheme_module_css_'. str_replace(Array('/', '.', ' '), '_', $file);
   
$form['myTheme_module_css_fieldset'][$var] = array(
     
'#type' => 'checkbox',
     
'#title' => t($file),
     
'#default_value' => $settings[$var],
    );
  } 
 
  return
$form;
}

function
myTheme_get_module_css() {
 
$module_css = Array();
 
 
// Scanning module folders for CSS files and saving index in database
 
$result = db_query("SELECT * FROM {system} WHERE type = 'module' AND status = 1");
  while(
$module = db_fetch_object($result)) {
   
$module_path = pathinfo($module->filename, PATHINFO_DIRNAME);     
   
$css_files = file_scan_directory($module_path, '\.css$', array('.', '..', '.svn''CVS'));
    foreach((array)
$css_files as $key => $file) {
     
$module_css[] = $file->filename;
    }
  }
 
  return
$module_css;
}
?>

With this, we have a form at admin/build/themes/settings/myTheme with a checkbox that allows us to enable all module css or disable all module css and a series of checkboxes that lets us selectively turn module css back on when all module css is disabled.

At this point, we just need to wire it up in our template.php:

<?php

function myTheme_preprocess_page(&$variables) {
 
$variables['styles'] = myTheme_get_css(); 
}

function
myTheme_get_css($css = NULL) {
  if(
$css == null) {
   
$css = drupal_add_CSS();
  }
 
 
// Looping through added CSS files and unsetting files that we don't want to use
 
foreach((array)$css as $media => $types) {
    foreach ((array)
$types as $type => $files) {
      if (
$type == 'module' ) {
        foreach((array)
$files as $file => $preprocess) {
          if (!
theme_get_setting('myTheme_module_css') && !theme_get_setting('myTheme_module_css_'. str_replace(Array('/', '.', ' '), '_', $file))) {
              unset(
$css[$media][$type][$file]);
            }
        }
      }
    }
  }
 
  return
drupal_get_css($css);
}
?>

myTheme_get_css is a mirror of drupal_get_css, utilizing the power of drupal_add_css and drupal_get_css along with a small bit of code, lifted from Style Stripper that has been modified to work with theme settings.

With this theme setting, I can now take visual control out of the hands of the module and put it back into the theme. I can choose to ignore the suggestions of the module, or to embrace them, but it is up to the theme.