Some lessons from building Drupal 6 themes

Get the most of the revamped Drupal 6 theme API

After a few Drupal 6 projects where I had to create themes from scratch, including my recently released Woodpig theme for Ventanazul I've learned a lot and decided to gather some tips I'm sure will help you, my fellow Drupalist, when turning your next design into a functional Drupal managed site. Sounds good? Let's dive into the powerful Drupal 6 theme API.

Flowers And Plants

Get the documentation right

There are a lot of changes in the Drupal 6 theming API and even being quite familiar with Drupal 5 theming I had to invest a considerable amount of time to get all the new ideas; hence, the theme guide for Drupal 6 should be your first stop.

But quickly reading the theme guide for Drupal 6 once may not be enough, topics like preprocess functions and registering hook themes still confused me after my first try at the documentation so I had to re-read many parts. My advice is to read the guide at least twice, the first time just try to get the idea and the second one start playing with a test install of Drupal 6 to see how the new theme API works.

You always need to register theme functions and templates

Drupal 6 calls these theme hooks. A theme hook is something that can be themed, usually output from your modules that may need alternative HTML or CSS. In Drupal 5 you could write a module and add as many theme functions as you wanted, these functions could then be overriden by any theme or converted into a tpl.php file using the _phptemplate_callback function.

Drupal 6 needs to know which theme hooks are available in your theme beforehand; this is to be more efficient and avoid discovering theme hooks on run time. To register theme hooks you should use the new hook_theme. Here you can tell Drupal what theme functions or templates your module will provide and what variables can be used.

Here's some code from the custom module I use in Ventanazul:

function ventanazul_theme() {
return array(
'ventanazul_flickr' => array(
'template' => 'ventanazul-flickr',
'arguments' => array('flickr_user' => NULL, 'attributes' => array()),
),
'ventanazul_google_search' => array(
'arguments' => array('publisher_id' => NULL, 'attributes' => array()),
),
);
}

The first hook, ventanazul_flickr, will use a file called ventanazul-flickr.tpl.php as a template that will have a couple of variables available: $flickr_user and $attributes. This is what I use for showing some pictures from my Flickr account.

The second hook, ventanazul_google_search does not provide a template and that means it will just use a theme function with the following signature: theme_google_search($publisher_id, $attributes). Notice how the variables in this case are passed directly to the theme function.

Don't forget to clear the theme registry

The theme registry is where Drupal 6 stores what it knows about the available theme hooks, every time you modify theme hooks you need to clear it or your changes won't be recognized. Clear theme registry in any of these ways:

  • Visit Administer > Site configuration > Performance and click on Clear cached data. This is my preferred way and I always keep a tab open in Firefox just for this page.
  • Use the devel block from the devel module and click the Empty cache link.
  • Call the function drupal_rebuild_theme_registry.

Define regions for blocks in .info files

For Drupal 5 you added your theme's regions in template.php, now you just need to add a few lines to your theme's .info file. This code is from a theme called Winds of Change that I've just finished coding for a client:

name = Winds of Change
description = Site of Winds of Change Group
version = VERSION
core = 6.x
engine = phptemplate
stylesheets[all][] = style.css
stylesheets[print][] = print.css
regions[left] = left sidebar
regions[right] = right sidebar
regions[content] = content
regions[header] = header
regions[footer] = footer
regions[social] = social

Notice the regions entries by the end, this is plain text but the syntax is similar to PHP arrays. These lines tell your theme to make those regions available and will use the names in brackets as variable names; regions[left] will create a $left variable for your page templates.

Changes in your theme's .info files require clearing the theme registry as explained above. Actually, I'm a little paranoid and everytime some of my theme changes are not reflected on the site I clear the theme registry.

Cache and theming for authenticated and anonymous users

This is a minor but very important detail. Drupal caches it's output for anonymous users and may optimize your CSS and Javascript files. Review your settings in Administer > Site configuration > Performance to disable all caching and optimization while you are developing a new theme and clear the theme registry to see your changes as an anonymous user.

Do your best with the available theme hooks

There are many times when you are tempted to override a certain theme function or template in Drupal 6. This is what I tried to do when theming navigation links for Ventanazul but after thinking a little more I realized I could get the same results with some smart CSS and a few additional variables. For example, for the bottom navigation, I just used:

print theme('links',array_merge($primary_links,$secondary_links), array('id' => 'alternate-menu'))

Woodpig footer

theme_links is provided by Drupal core. Notice how I merge primary and secondary links and apply an id alternate-menu to be styled from CSS inside an #alternate-menu rule.

Before overriding a theme function or template check the source and see if you can pass some variables to affect it's behavior.

Use templates from modules

Drupal 6 recommends all module developers to provide templates, that means you should check in your module's directory to see what .tpl.php files are available and copy the ones you need to modify to your theme's directory. For the Woodpig theme I copied user-profile.tpl.php from modules/user to make a few changes in user account pages. Remember to clear the theme registry after adding a tpl.php file to your theme.

You can create theme hooks for modules you did not write

When I wanted to theme the comments form the first thing I did was looking at comment.module. There I found a call like this:

drupal_get_form('comment_form', $edit, $title)

Ok, I had a comment_form function that I could theme according to Drupal Form API, then I started looking for theme_comment_form but there was none.

How to override a theme hook that does not exist? Just as you do with your own modules, you just need to know the code involved and, this is important, you can include a hook_theme function in your template.php file. This is what I did for Woodpig:

function woodpig_theme() {
return array(
'comment_form' => array(
'arguments' => array('form' => array()),
),
);
}

The function starts with the theme name and the theme hook takes the form argument because it's a that's what drupal_get_form requires. Then I can write my own woodpig_comment_form($form) function.

Behold the power of preprocess functions

Preprocess functions allow you to modify the variables available to your templates. You can also add new variables. This is pretty important and I use it a lot for things like customizing breadcrumbs, passing the theme's path to my templates and separating the comment form from the content of a node. I suggest you play a lot with preprocess functions and understand their power. I'll have a few more articles about them soon.

Far from complete

There are still many lessons to learn from the Drupal 6 theme API and I find more and more in every new project. Even if this wasn't intended to be a complete guide I'm sure these ideas will help you in your next theming adventure.

Let me know what you think in the comments and if you have more questions or suggestions for coding with Drupal pay a visit to the Drupal forums in Ventanazul. Happy coding!

Join the conversation

Hi, great article! Thanks for

Hi,

great article! Thanks for sharing this with us. :-)

have fun, bye!tom

Thanks! Always interesting to

Thanks!

Always interesting to see how fellow drupalists are doing things, really liked the array_merge tip there, never thought of that myself :D

Nice job on the site btw, I'll be keeping an eye on it, greetings from Barcelona!

Thank you for educating us on

Thank you for educating us on the new theme system. Some of your tips demystified how the D6 theme system works. Good work!

How to name file for theming

How to name file for theming my menu?
menu-tree-mymenu.tpl.php ?

nice and useful, thanks.

nice and useful, thanks.

A useful one thanks.

A useful one thanks.

Keep your comments relevant, written in good English and don't spam. Let's create useful and valuable discussions. Markdown is welcome.

Add your comment