Understanding Drupal Themes

Posted by garym on Tue, 08/03/2004 - 11:22

For those new to Drupal, you usually just want to get started with a site that doesn't look like Drupal.org. Here's a quickie guide to getting the site you want out of the code we all share.

To start off, a Drupal distribution contains many alternative _themes_ but this is really a misnomer: the 'themes' listed in the admin pages really means _theme engines_ -- Drupal's modular design has led to many different alternative ways of producing output, each with it's own pet ways of page production. Some themes involve template files loaded and then populated with data values, others just render the page directly. This guide will show you how to wrap your head around this multi-layer approach and hopefully get you on your way to full drupality.

How Drupal Themes Work

The Drupal server communicates with these themes through a collection of _callback_ functions, for example themes/marvin_2k/marvin_2k.theme includes a function marvin_2k_page() that is called to render the overall page framework; individual stories within that page will be rendered by marvin_2k_node().

Themes need not implement _all_ of the callback functions; the defaults can be found in modules/theme.module and each theme is free to pick and choose what it will provide; themes can also reference the default functions by calling them from within their own callbacks.

Most themes use some sort of template, some very basic and streamlined for non-programmers, many of them using flow constructs for conditional or repeated output, some of them allowing PHP code to be embedded in the template. It's worth remembering that PHP is _intended_ as a template language; there's lots of good books and websites about PHP -- I had started with the Smarty theme thinking a simple syntax would be easier to manage, but I've since seen the light and moved all my sites to a PHP-based template, currently marvin_2k although I am migrating to phptemplate.

[? print $variable ?] is more awkward than #variable, but not _that_ much more awkward ;)

Changes by Degrees

Most Drupal themes have four levels of customization control, and where you edit depends mostly on how deeply you need to cut unto the code to get what you want ...

* Theme variables set in the admin/ pages often include headers, logos, titles and may include selecting alternate CSS stylesheets.
* The CSS stylesheets themselves; some themes like marvin_2k and phptemplate have several layers of stylesheets to seperate layout from graphic design, and also have a custom.css that is loaded last -- if you want to keep the default files for easy updates, you can make your customized changes in that last layer to override the defaults.
* Template files, where present, are the raw HTML page peppered with template commands to insert data values; in phptemplate and marvin_2k, the theme engine creates a table of variables that are placed into the page by the template.
* Theme module files are the themes/name/name.theme files; these are pure PHP files containing the callback functions.

So, for example, to change the logo of a page, I'd use the admin pages; to change the border colour or sidebar placements, I'd use the CSS files, to insert my GoogleAds I'd have to change the templates, and to hack the theme to allow me to format a lead story different from the later items, I'd have to edit the PHP theme module itself.

Customizing the Theme sources

The best strategy is to pick a template engine that suits your purposes and programming comfort level, but instead of using the default, you'll want to edit the template files for the particular theme engine; this lets you experiment with hacks to the theme page-production code as well as the templates and stylesheets while keeping you immune from later updates overwriting your changes.

If you are comfortable with CVS, you can make your changes directly to the distribution files you have checked out of the version control; each time you update your sources, CVS will mark your locally modified files with M in the output log, and report a C if your changes conflict with the production code -- it's then left to you to resolve the differences, and your site is likely to be broken until you do. The method I use is to keep a local set of drupal CVS files with my local modifications, and then test these before using rsync to update my live site.

Theme Cloning

Another approach is to create your own distinct theme where you can freely experiment and still have the default as a reference and backup. For example, with the Chameleon theme, here's how I created a clone I called Iguana ;) ...

# clone the theme: cd themes; cp -pr chameleon iguana
# rename the theme file: cd iguana; mv chameleon.theme iguana.theme
# change the internal refs:

  • cat iguana.theme | sed 's/chameleon/iguana/gi' > iguana.theme.new
  • (manually proof the file for stray errors)
  • mv iguana.theme.new iguana.theme

# enable the theme in the admin/ pages -- if your Drupal suddenly goes blank, there is likely an error in the new theme file.

Whenever you make changes to either a template or a theme module, it is important to keep an exit strategy; few things are more frustrating in PHP than an afternoon spent with a blank page.

When I make changes to the templates or theme code, I will login in two browser windows (tabs in FireFox) where I can load my personal profile in one, the homepage in the other. In the first window, I select the new theme and save, then refresh the other -- again, PHP will go blank if there is any error in that file, but you can roll back the change by changing the theme in the first window.

And that, in a nutshell, is it, the path to perfect Drupality. Always remember that this is _community_ software, so while you are on your own and completely responsible when you make changes, there's lots of others who've been there and done that; if you really get stuck, there's many a shoulder to cry on over at drupal.org!



odd PHP syntax example

btw, just as a footnote, the use of the [? print ?] syntax is an artifact of the Drupal Textile support that wouldn't let me use proper entites for angle-brackets. Take my advice, avoid Textile; I'm deeply bound to it now, and it's a long-term pain in the backside.