The one required file in any Drupal 6 theme is the .info file. It was a great addition to the theme layer and makes defining functionality almost dead simple. Documented features of the .info file allow for adding descriptive information, features, stylesheets and javascript files to the theme. This has made constructing a custom theme much easier compared to Drupal 5 since there is no mucking about in PHP necessary.
The system is not perfect and there are limitations to this set of supported definitions. For instance, all stylesheets added via the theme are always ordered after all the system and module stylesheets. This is less than optimal for reset CSS files and CSS frameworks like 960 grid system. Another common practice is conditional stylesheets for Internet Explorer browsers. The only option to use this method is to hard code the stylesheets into the page.tpl.php or install a module. It would be so nice to define these files in the theme's .info file and keep the themes flexible.
Thankfully, this is fully possible with the help of a couple variables. As a warning for those not versed in PHP, implementing any of this functionality requires it's use.
A little example
Anything that is added to the .info file is available for use. This is not restricted to the supported features. As an example, let's construct a simple theme called "jim".

Since this is purely an example, our theme is only going to consist of 3 files: jim.info, reset.css and ie6.css. It will not be necessary to add anything to the CSS files since this is only an example, but it will be necessary to add something to the .info file to get it recognized by Drupal.
name = Jim
core = 6.x
engine = phptemplateThis is only the required information for a Drupal theme. It will not win any beauty contests, but now we can now select the theme as our default in themes administration. Since that is done, let's add our stylesheets in an unconventional way by adding the following lines to our jim.info.
top stylesheets[all][] = reset.css
ie stylesheets[ie 6][all][] = ie6.cssThe standard practice is to clear the theme registry cache when adding to a theme's .info file, but there will not be any noticeable effect. To get access to this information we will need to delve into some PHP. The proper place for that would be the template.php, so add one to the theme's folder.
Dig into $theme_info
We will be adding our extra styles to the $styles variable in page.tpl.php. This will be done via hook_preprocess_page() in template.php. In order to use this preprocess function, a page.tpl.php will needed in our theme. I simply copied the core Drupal version at modules -> system -> page.tpl.php to our theme.
To get at our new stylesheets in jim.info, we will need access to the $theme_info variable in the hook_preprocess_page() function. Since it is not immediately available, we will have to load it as a global variable. With all of this in mind, you should have something like this in your template.php:
<?php
function jim_preprocess_page(&$vars) {
global $theme_info;
}
?>If you have the Devel module installed, you can place to a dpm($theme_info); in that function to display the contents of the variable. If you look in $theme_info->info, you will see your new stylesheet definitions. Now to put them to work for us.
Put stylesheets at the top of the stack
Our first task will be to add the top styles to the top of the stylesheet stack. To take advantage of CSS compression in Drupal, we will want to put it in with the rest of the accounted for stylesheets and then run them through drupal_get_css(). There will be a bit of sorting needed to accommodate for the media types. In the end you will have something that looks like the following.
<?php
function jim_preprocess_page(&$vars) {
global $theme_info;
// Get the path to the theme to make the code more
// efficient and simple.
$path = drupal_get_path('theme', $theme_info->info['name']);
// Check if there are stylesheets to be placed at the
// top of the stack.
if (isset($theme_info->info['top stylesheets'])) {
$top_css = array();
// Format the stylesheets to work with
// drupal_get_css().
foreach ($theme_info->info['top stylesheets'] as $media => $styles) {
foreach ($styles as $style){
$top_css[$media][$path . '/' . $style] = TRUE;
}
// Add the stylesheets to the top of the proper
// media type.
array_unshift($vars['css'][$media], $top_css[$media]);
}
// Replace $styles with the new string.
$vars['styles'] = drupal_get_css($vars['css']);
}
}
?>With this code in place, you can now add new stylesheets at will to the jim.info file. Nice, neat and flexible.
Adding conditions for Internet Explorer
For something a little more complicated, we will now add the support for the conditional stylesheets that only Internet Explorer will see. It will be good to pass these through the drupal_get_css() to take advantage of CSS compression, but the final output can be tacked onto the end of the existing $styles variable.
With only the conditional stylesheets, your function will look like this:
<?php
function jim_preprocess_page(&$vars) {
global $theme_info;
// Get the path to the theme to make the code more
// efficient and simple.
$path = drupal_get_path('theme', $theme_info->info['name']);
// Check for IE conditional stylesheets.
if (isset($theme_info->info['ie stylesheets'])) {
$ie_css = array();
// Format the array to be compatible with
// drupal_get_css().
foreach ($theme_info->info['ie stylesheets'] as $version => $media) {
foreach ($media as $type => $styles) {
foreach ($styles as $style) {
$ie_css[$version][$type]['theme'][$path . '/' . $style] = TRUE;
}
}
}
// Append the stylesheets to $styles, grouping by IE
// version and applying the proper wrapper.
foreach ($ie_css as $version => $styles) {
$vars['styles'] .= '<!--[if ' . $version . ']>' . "\n" . drupal_get_css($styles) . '<![endif]-->' . "\n";
}
}
}
?>As with the top stylesheets, you can now add new IE conditional stylesheets via the jim.info file. Each line for a CSS file to add would need to be formatted like so: ie stylesheets[conditional logic][media type][] = filename.
Bringing it all together and base themes
By now, your template.php should look like the following:
<?php
function jim_preprocess_page(&$vars) {
global $theme_info;
// Get the path to the theme to make the code more
// efficient and simple.
$path = drupal_get_path('theme', $theme_info->info['name']);
// Check if there are stylesheets to be placed at the
// top of the stack.
if (isset($theme_info->info['top stylesheets'])) {
$top_css = array();
// Format the stylesheets to work with
// drupal_get_css().
foreach ($theme_info->info['top stylesheets'] as $media => $styles) {
foreach ($styles as $style){
$top_css[$media][$path . '/' . $style] = TRUE;
}
// Add the stylesheets to the top of the proper
// media type.
array_unshift($vars['css'][$media], $top_css[$media]);
}
// Replace $styles with the new string.
$vars['styles'] = drupal_get_css($vars['css']);
}
// Check for IE conditional stylesheets.
if (isset($theme_info->info['ie stylesheets'])) {
$ie_css = array();
// Format the array to be compatible with
// drupal_get_css().
foreach ($theme_info->info['ie stylesheets'] as $version => $media) {
foreach ($media as $type => $styles) {
foreach ($styles as $style) {
$ie_css[$version][$type]['theme'][$path . '/' . $style] = TRUE;
}
}
}
// Append the stylesheets to $styles, grouping by IE
// version and applying the proper wrapper.
foreach ($ie_css as $version => $styles) {
$vars['styles'] .= '<!--[if ' . $version . ']>' . "\n" . drupal_get_css($styles) . '<![endif]-->' . "\n";
}
}
}
?>This bit of code will work great for a standalone theme. Problems will arise when used in a base theme as stylesheet inheritance will be broken. Thankfully, there is a second variable to help with that: $base_theme_info.
This variable has all information on the current theme's base theme, and all base themes of those base themes. Instead of going through all of the explanation, I will simply post the code that takes advantage of it.
<?php
function gaffigan_preprocess_page(&$vars) {
// Collect all information for the active theme.
$themes_active = array();
global $theme_info;
// If there is a base theme, collect the names of all
// themes that may have data files to load.
if(isset($theme_info->base_theme)) {
global $base_theme_info;
foreach($base_theme_info as $base){
$themes_active[] = $base->name;
}
}
// Add the active theme to the list of themes that may
// have data files.
$themes_active[] = $theme_info->name;
// Check for stylesheets to be placed at the top of the
// stack or conditional Internet Explorer styles in the
// .info file and add them to the $styles variable.
$top_styles = array();
$ie_styles = array();
// If there is more than one active theme, check all
// base themes for stylesheets.
if (count($themes_active) > 1) {
foreach ($base_theme_info as $name => $info) {
if (isset($info->info['top stylesheets'])) {
$top_styles[$name] = $info->info['top stylesheets'];
}
if (isset($info->info['ie stylesheets'])) {
$ie_styles[$name] = $info->info['ie stylesheets'];
}
}
}
// Check the current theme for stylesheets.
if (isset($theme_info->info['top stylesheets'])) {
$top_styles[$theme_info->name] = $theme_info->info['top stylesheets'];
}
if (isset($theme_info->info['ie stylesheets'])) {
$ie_styles[$theme_info->name] = $theme_info->info['ie stylesheets'];
}
// If there is at least one entry in the $top_styles
// array, process it.
if (count($top_styles) >= 1) {
// Format the array into a format readable by
// drupal_get_css().
$vars['top_css'] = array();
foreach ($top_styles as $name => $theme_styles) {
$path = drupal_get_path('theme', $name);
foreach ($theme_styles as $media => $styles) {
foreach ($styles as $style){
$vars['top_css'][$media]['featured'][$path . '/' . $style] = TRUE;
}
// Add the new styles to the top of the
// $vars['css'] array.
array_unshift($vars['css'][$media], $vars['top_css'][$media]['featured']);
}
}
// Run $vars['css'] through drupal_get_css and
// replace the $styles variable.
$vars['styles'] = drupal_get_css($vars['css']);
}
// If there is at least one entry in the $ie_styles array,
// process it.
if (count($ie_styles) >= 1) {
// Format the array into a format readable by
// drupal_get_css().
$vars['ie_css'] = array();
foreach ($ie_styles as $name => $theme_styles) {
$path = drupal_get_path('theme', $name);
foreach ($theme_styles as $version => $media) {
foreach ($media as $type => $styles) {
foreach ($styles as $style) {
$vars['ie_css'][$version][$type]['theme'][$path . '/' . $style] = TRUE;
}
}
}
}
// Append the stylesheets to $styles, grouped by IE
// conditional.
foreach ($vars['ie_css'] as $version => $styles) {
$vars['styles'] .= '<!--[if ' . $version . ']>' . "\n" . drupal_get_css($styles) . '<![endif]-->' . "\n";
}
}
}
?>As expected, this ends up being more complicated. The gist of what is going on here is that we have to add an extra level to check what theme is associated with which content. From that point a lot of the process is the same.
Conclusion
For reference, the above themes are attached to this post.
There is a lot of untapped power available in the .info files. I focused on stylesheets in this instance, but there is certainly more that can be accomplished. Placing javascript files in the footer is just one example. I am sure more imaginative people than I can come up with even more.
For those of you wondering, this functionality will be in an upcoming 2.0 version of the Studio theme pack. This will be one of a few changes and others will most like be highlighted at a later date.
- Tags: code, Drupal, Drupal 6, preprocess, theme, Design 4 Drupal









Comments
Drupal Theme Garden writes:
Nice and really useful "trick".
Thanks.
Tim Wright writes:
Good read. Thanks for putting this together!
Daglees writes:
Excellent post, thank you!