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=" <?php print url(null, array('absolute'=>true)) ?> ">
<img src="<?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="' . url(null, array('absolute'=>true)) . '">' .
'<img src="' . 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.