0

If a base theme overrides a certain template, how can I tell a sub theme to revert to the default template instead of using the overridden template?

Of course I could simply copy the default template to the sub theme's templates directory, but that's not an ideal solution because it duplicates code and one would not take advantage of future (security?) updates in the default template.

My ideal solution would be smart enough to undo the template override provided by the base theme, but still allow for other overrides on the module level.

1
+50

I don't know if there is a perfect solution to do that without any inconvenient. Here are two proposals :


Altering the Theme Registry :

To prevent the base theme from overriding a specific template, an idea would be to alter the theme registry. The theme registry array is keyed by theme hook name, and contains informations returned from hook_theme().

As Clive suggested above, you can achieve this by implementing hook_theme_registry_alter(). Here an example of how to revert theme overrides to preserve the original "node" template :

function example_theme_registry_alter(&$registry) {
  // Default template file path we want to use (relative to the Drupal root directory).
  $default = 'modules/node';

  // In Drupal 6, we can retrieve default template path in 'theme paths' array. The 1st key should
  // contain it, however 3rd party code might already have altered the registry...
  // $default = $registry['node']['theme paths'][0]; -> should be 'modules/node'

  // Reassign the template file path and theme path accordingly.
  $registry['node']['path'] = $default;
  $registry['node']['theme path'] = $default;

  // Reassign the name of the template file if needed (could have been overriden too).
  $registry['node']['template'] = 'node';

  // You may also need to unset some preprocess functions to protect template variables as well.
  unset ($registry['node']['preprocess functions'][11], ... , ... );
}

This hook is executed as the theme cache is rebuilt, you will need to clear it to see the changes.

This solution still "allows for overrides" on the module/theme level. However, since this code will always hook after modules and themes, you will probably need to bypass it every time you expect a change (e.g. brought by a new overriding template), just to be sure that what you see is what you expect, and to know which theme do what in the rendered page. So, if allowing module/subtheme overrides while preventing base theme overrides is required, you may want to try the 2nd solution.


Bypassing specific theme overrides :

This is not the clean way but according to your needs and how specific it is, you may prefer to directly "tweak" your base theme :

  • Templates : prevent override by renaming the theme template file : in the node example, one would rename node.tpl.php to bypass.node.tpl.php (or whatever).
  • Preprocessing : comment out preprocess functions in the base theme's template.php, e.g: themename_preprocess_node()
  • CSS, JS, ... : depending on how well your theme is structured, it can be easy or simply horribly boring to comment out the "overriding" part in these files.

The inconvenient here is that you'll have to redo these 3 steps every time you update or change the base theme, but until such a case happens, this will make it easier for modules and subthemes to manage overrides without messing with the theme registry.

  • Thank you. You answer more or less confirms what I was expecting. Both methods are hackish (no offense to you, just an observation) and it's hard, if not impossible, to unset a specific template override without touching another part of the system in the process. – marcvangend Jan 12 '15 at 13:03
  • I managed to test both methods in a reasonable time and they works but I agree with you : it's hackish! Eventually one would prefer simply copy the default template to the sub theme's directory, as you suggested first, but in that case theme js/css would still apply.. I'm afraid there is no proper solution here. – user26231 Jan 12 '15 at 13:17
  • @marcvangend in my opinion its not hackish. the point of hook_theme and sub-themeing is to provide a mechanism these types of overriding. with regards to JS at least your subtheme can use drupal hooks to unset JS easily on certain urls for example. – tenken Jan 15 '15 at 22:52
  • @tenken I call this hackish because there is no really clean way to control the priority of templates. I cannot tell Drupal "do not use template X but use whatever had the highest priority before that". The first methods requires intimate knowledge of template names. It does not really "undo" a certain override, but rather overrides the override with a hard coded value. The second method modifies contrib code, which is pretty similar to hacking core. – marcvangend Jan 16 '15 at 9:39
  • @n0tting I'm not marking this as accepted answer because it's not a complete solution to the problem. I did award you the +50 bounty because the answer was helpful in understanding the essence of the problem. – marcvangend Jan 16 '15 at 9:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.