Subsubthemes and in-theme-hooks

I am really loving the improvements to subthemes in Drupal 6. They took what was an interesting idea in Drupal 5 and made it even more powerful and much easier to use. I have been finding a lot of power rolling out a sets of websites, using subsubthemes.

Theme X: Free theme downloaded from drupal.org
Theme Y: My modifications to that theme, as a subtheme of Theme X. I want these mods to apply to all my subsubthemes. base_theme = Theme X
Themes A, B, & C: The actual themes used on my sites. base_theme = Theme Y

The great thing about this setup is that I can continue to install updates to Theme X, with minimal disruption to my actual sites' themes. There was one problem though:

I wanted to add an optional $imagemap to all the logo in the subsubthemes that would be easily overridable.

The obvious solution seemed to be to add the following code to Theme Y's template.php:

<?php
// Hook Theme.
function y_theme () {
  return array(
   
'imagemap' => array(
     
'arguments' => array( 'logo' => null ),
     
'template' => 'imagemap' ,
    ),
  );
}

// Inject $imagemap into the page.tpl.php
function y_preprocess_page (& $vars ) {
 
$logo = theme_get_setting ( 'logo' );
 
$vars [ 'imagemap' ] = theme ( 'imagemap' , $logo );
}
?>

Then create a imagemap.tpl.php in Theme Y

  <div id="logo">
    <a href=http://www.starbowconsulting.com/" <?php print url ( null , array( 'absolute' => true )) ?> ">
      <img src=http://www.starbowconsulting.com/" <?php print $logo ; ?> " alt="' . t('Home') . '" id="logo-image" />
    </a>
  </div>

But this approach did not work. "Imagemap" was registered in the theme system, but theme('imagemap') returned null. I need to do more testing, but I believe there is a bug in the Drupal 6.5 theming system. I worked around it by moving the hook_theme call out of the subtheme and pushing the call down into the subsubthemes.

So it Theme Y template the code looks like this:

<?php
// Inject $imagemap into the page.tpl.php
function y_preprocess_page (& $vars ) {
 
$logo = theme_get_setting ( 'logo' );
 
$imagemap = theme ( 'imagemap' , $logo );
  if (!
$imagemap ) {
   
$imagemap = y_imagemap ( $logo );
  }
 
$vars [ 'imagemap' ] = $imagemap ;
}

// Fallback if the subsubtheme doesn't declare imagemap in a hook_theme.
function y_imagemap ( $logo ) {
  return
'<div id="logo">' .
   
'<a href="'http://www.starbowconsulting.com/ . url ( null , array( 'absolute' => true )) . '">' .
     
'<img src="'http://www.starbowconsulting.com/ . url ( $logo , array( 'absolute' => true )) . '" alt="' . t ( 'Home' ) . '" id="logo-image" />' .
   
'</a>' .
 
'</div>' ;
}
?>

And the hook_theme call goes into each subsubtheme that wants to override it. Then that subsubtheme can include an imagemap.tpl.php that defines the custom imagemap. A little bit of fuss to set up, but super powerful and easy to use from then on.

Inheritance fail

I've run into the same issue... subthemes do not inherit a basetheme's hook_theme(). And, a subtheme will not inherit base theme .tpl.php files for hooks defined in the subtheme's hook_theme().

Module-defined callbacks do inherit across subthemes though, so as a work-around you can define your hook_theme() inside a site-specific module. Do note that simply defining your callbacks with 'type' => 'module' inside template.php does not work.

Whether it is a bug, oversight or deliberate decision is up for debate though. For theme-hook inheritance to work, a subtheme would need to include its base theme's template.php, which could lead to conflicts. But I think this behaviour would be preferable to the current limitations.

Bug

This would be a bug or oversight. The base theme(s) template.php should in fact be included.

Bug, but not what you think:

So actually the registration of the theme function works just fine, I tested it. However, if you didn't have a page.tpl.php, then the *preprocess* doesn't get registered. This is a known bug: http://drupal.org/node/258089

No, that’s not quite it.

No, that's not quite it. I do have a page.tpl.php in my middle level subtheme, and the prepossess is getting called in the first example. And if I look at the devel theme report, it shows imagemap as registered. But there is something off, b/c theme('imagemap') returns null. And using theme developer to click on the text produced on the final page by "print $imagemap" does not show any $imagemap related info. I know, I need to do some testing with a virgin copy of D6.6 and file an issue :)

Re: inheritance fail

Actually, I found it worked fine if I put the hook_theme into the top level parent theme. But then I can't update the theme when new versions are released without painful change management.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.