Using Theme Override Functions

Last modified: August 23, 2009 - 15:12

Many resources for and about Drupal will tell you that the road to true customization lies through overriding theme functions in order to create exactly the kind of output you desire. Doing so is extremely powerful, though it can require a little PHP knowledge to pull off, since you need to create a function. However, there are many snippets and examples to choose from, and many of these are cut and paste with just a little bit of modification necessary to get them to work.

Which File to Use

In order to use theme overrides, the first thing you need is a place to put them. Exactly where you put them depends upon which theme engine you are using. The default theme engine in Drupal 4.6 was XTemplate; however, XTemplate proved problematic when paired with PHP5, so Drupal 4.7 and higher now use PHPTemplate as the default theming engine.

The file you need will live in themes/MYTHEMENAME.

PHPTemplate
(This is by far the most common theme engine.) PHPTemplates keep their theme overrides in template.php.
Plain PHP Theme
If using a plain PHP Theme, such as Marvin or Chameleon, the file you place your overrides in is THEMENAME.theme
XTemplate
XTemplate does not allow theme function overriding.
SmartyTemplates
SmartyTemplates use the file smartytemplate.php.
wgSmarty
wgSmarty uses template.php but as of this writing that code is commented out; it may not be possible to do theme overrides in wgSmarty.
phptal
PHPTAL uses template.php, and is very similar to PHPTemplate.

If your theme does not come with a template.php file inside it, you will have to create one. Save a new blank file called template.php, and make sure the first line contains a <?php statement at the top, or you might cause your site to crash with a White Screen Of Death. There's no need to have a closing php tag.

How to Name your Override Function

When overriding a theme function, module documentation will usually inform you to use or override something along the lines of theme_SOME_FUNCTION_NAME. In order to override this, you need to name it something slightly different from this, since PHP requires all function names to be unique.

The example function we're going to look at for this is theme_item_list, which is used whenever Drupal wants to display a list of items, and is used almost everywhere you see the <li> tag in Drupal, except in the menu structure.
This function is defined as:

<?php
 
function theme_item_list($items = array(), $title = NULL, $type = 'ul') {
?>

Overrides can be named in two ways, unless you're using a plain PHP theme. First, all theme overrides can be named by replacing the 'theme_' at the beginning of the function with 'MYTHEMENAME_'. So if you're using the chameleon template, in your chamelon.theme file you, to override the function theme_item_list as:

<?php
 
function chameleon_item_list($items = array(), $title = NULL, $type = 'ul') {
?>

This is not actually the preferred method of overriding, however, but it is the one that always works. Most themes, however, are derived from one of the Template Engines. They can override these functions by using the name of the template engine instead of the theme name. This is preferred, because it makes it very easy to share these functions with other users who might be using a different theme. Or even share a single file of functions with several themes on the same site!

Some examples:

<?php
 
function phptemplate_item_list($items = array(), $title = NULL, $type = 'ul')
  function
smarty_item_list($items = array(), $title = NULL, $type = 'ul')
?>

How to Find which Theme Function to Override

If you can't find what you're looking for in the Drupal API or don't know where to begin, here's a last resort method of figuring out what theme function you need to override.

WARNING: This trick requires hacking Drupal core, which should never happen on a production site! You should employ this trick only when absolutely necessary -- and even then, only on a development site.

Open /includes/theme.inc. Look for the theme() function on line 161. Find line 170. It should look like this:

<?php
return call_user_func_array($functions[$function], $args);
?>

Add this line directly above it (and comment out the original line):

<?php
   
return '<!-- begin ' . $functions[$function] . ' -->' . call_user_func_array($functions[$function], $args) . '<!-- end ' . $functions[$function] . ' -->';
//    return call_user_func_array($functions[$function], $args);
?>

This will output code like this in your HTML source:

<!-- begin theme_athemefunction -->[OUTPUT]<!-- end theme_athemefunction -->

override for all themes?

vegeneric - December 10, 2007 - 18:39

"Or even share a single file of functions with several themes on the same site!" --> more info, please!

how exactly can a single function override all my themes at once, without having to copy my template.php file into each theme's folder? if i create a function phptemplate_so_on_so_forth and put it in a theme's template.php file, it still only overrides for that single theme.

Sharing functions

zeta ζ - January 29, 2008 - 20:40

The point is that you won’t have to rename the functions, as you would if they were theme_function(). Yes, the file needs to be copied (or linked), but will only require the same theme engine.

Modularisation

kingandy - March 14, 2008 - 15:30

One option would be to create a shared module - for example a module called myglobaltheme.module (with the concordant myglobaltheme.info file), which declares some functions called phptemplate_so_on_so_forth(). If that module were placed in the sites/all/modules folder, it could then be activated on a site-by-site basis simply by visiting the modules page and switching it on as though it were a normal module. It's sneaky but it works ;)

Alternatively - if you want to avoid modules - you could create a PHP file elsewhere on the site (say, in sites/all), and include it in each of your sites by use of the PHP include_once() function in the template.php.

--Andy
Developing Drupal websites for Livelink New Media

Overriding theme functions in modules?

Todd Nienkerk - October 6, 2008 - 20:04

I've never quite understood the phptemplate_/mytheme_ difference, either. According to kingandy and the others, the only advantage to using
"phptemplate_" besides easier copying/pasting between themes is the ability to override theme functions from other modules. This strikes me as a very bad idea. If two modules override the same theme function, there would be a name collision.

It seems to be it's always wiser to use the "mytheme_" convention, as relatively few sites utilize multiple themes. I think the preferred behavior should be switched to the more common situations: single themes with single overrides.

Todd Ross Nienkerk
Co-founder, Four Kitchens

Caveat

kingandy - October 9, 2008 - 10:30

For general distribution, yes, it would be incredibly bad practice to include a phptemplate_ theme override function in your module. (There's no guarantee that your users will be using a phptemplate theme, and modules shouldn't be operating at a theme level anyway.) However, for personal use, if there's something that you know you're going to be overriding on a lot of themes on your own site(s), and want to define in a single place in case of future revisions, the shared nature of a custom-built module is ideal.

FWIW, it feels like the engine_/themename_ precedence was built with this kind of thing in mind - a smaller number of theme-specific exceptions to a more common override (though perhaps more for the "common include file" strategy than a module).

--Andy
Developing Drupal websites for Livelink New Media

Can you do it for...

GBain22 - July 10, 2009 - 09:13

user_pass_reset() ?

Is it possible to do, for example, garland_user_pass_reset() and edit one of the $form['message'] values?

Just struggling to see what I can actually do without editing the actual user.pages.inc file!

Garry Bain, sdesign1
Drupal Experts

How to Find which Theme Function to Override (Drupal 6)

random_ - October 30, 2009 - 10:10

Great tip, thanks! To do the same thing in Drupal 6, inside the theme() function of /includes/theme.inc, change line 617 from this:

$output = call_user_func_array($info['function'], $args);

To this:

$output = '<!-- begin ' . $info['function'] . ' -->' . call_user_func_array($info['function'], $args) . '<!-- end ' . $info['function'] . ' -->' ;

The advice about not doing this on a production site stands.

unable to override

mghatiya - November 23, 2009 - 17:45

I created a function named 'phptemplate_uc_catalog_item' and put it in template.php file of my theme. I checked that value of variable $theme_engine is 'phptemplate'.

But I see that my function is not being executed. What am I doing wrong?

Solved.

mghatiya - November 24, 2009 - 06:17

Solved. I had not cleared drupal cache.

help with ubercart theme overide?

aosiname - February 3, 2010 - 12:55

Hi all, i am trying to modify the code in ubercart for a function called: theme_uc_catalog_product_grid($products) (found in ubercart/uc_catalog/uc_catalog.module
I have copied the function to the template.php file for my template
Opened my template.info to get the name (in the correct case)
Renamed the function in template.php to themeName_uc_catalog_product_grid($products)
Then made some changes.
However, it doesnt seem to be working.
It looks like it is ignoring the function.

Any ideas?

nice!!

aosiname - February 3, 2010 - 13:09

i then looked at the solution above and tried it...
yes it works
Clear the drupal cache in admin/settings/performance (there is a button right down the bottom) if you experience the same problem!

 
 

Drupal is a registered trademark of Dries Buytaert.