Using Theme Override Functions
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?
"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
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
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?
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
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...
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)
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
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.
Solved. I had not cleared drupal cache.
help with ubercart theme overide?
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!!
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!