As said in http://drupal.org/node/171205 the "base theme" setting in .info file should inherit resources missing in sub-themes. But this is not the case. :-(

If i add a page.tpl.php to a subtheme "mytheme/layouts/my_sub_theme/page.tpl.php" and NO "mytheme/layouts/my_sub_theme/node.tpl.php" the base theme's "mytheme/node.tpl.php" is not used as fallback. The sub-theme wrongly fallback to Drupals standard "modules/node/node.tpl.php" and not my base theme "mytheme/node.tpl.php", what i expect and need.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

dvessel’s picture

Priority: Critical » Normal
Status: Active » Postponed (maintainer needs more info)

Can't reproduce. I setup a custom theme with what you described and node.tpl.php is used as expected.

But while testing, another oddity popped up. Placing sub-themes within sub-folders will cause the parent theme to read the sub-theme's .tpl files. This is because drupal_find_theme_templates() will scan the theme's entire directory for templates.

We'll need to filter that out.

hass’s picture

Status: Postponed (maintainer needs more info) » Active

Tested again with latest dev and now the fallback is working, but it was broken some time ago.

What is about the other bug you mentioned?

hass’s picture

Title: base theme inheritance broken with *.tpl.php files » Filter out sub-theme's .tpl files for parent themes
merlinofchaos’s picture

I don't think we actually want to do this filtering; at least, not as a global filter. It's actually quite valuable that we can split template files up into subdirectories.

I had always assumed that we would enforce the rule that sub-themes all have their own directory. They aren't really sub-themes anymore; they're full themes with a dependency. They have no motivation to be shipped together; and if they are, they can always be shipped like so:

theme: foo, with sub-themes foo-bar and foo-baz:

foo/foo/foo.info <-- master theme
foo/foo-bar/foo-bar.info <-- child of foo
foo/foo-baz/foo-baz.info <-- child of foo

We should instead be very clear on how sub-theme directories should be structured when they are packaged together; then all will be well.

I believe we should won't fix this, but I'll wait for dvessel's comments.

dvessel’s picture

Well, thanks for clearing that up. I have no issues with that myself but all the existing themes using the old sub-theme structure will be in for a surprise. Not to mention what core does and I imagine people using that as their model will get confused..

I'll leave this open for now since I'm not sure myself. If we leave it as is, then I'll add it to the docs.

hass’s picture

Sounds like a bad idea to me. I have all my CSS files in "sites/all/themes/yaml/css/*" and it becomes *very* difficult to find out the master theme directory with drupal API functions - what i need for drupal_add_css or i simply don't know how. The path_to_theme function only gives the path to the current theme and there is no path_to_base_theme() or path_to_theme('base') or something equivalent available.

See the following example how i added the CSS files in sub-themes. This becomes nearly impossible if i use merlins directory structure. Aside - duplicating all CSS files sounds not like an reasonable option.

Example:

function yaml_2col_left_13_preprocess_page(&$vars) {

  // Add YAML Theme styles
  $vars['css'] = _yaml_2col_left_13_add_css($vars);
  $vars['styles'] = _yaml_2col_left_13_add_styles($vars);

}

function _yaml_2col_left_13_add_css($vars = array()) {

  global $theme_key;
  $base_theme_directory = str_replace('/layouts/'. $theme_key, '', $vars['directory']);

  // Add core and layout specific styles
  drupal_add_css($base_theme_directory .'/yaml/core/base.css', 'theme');
  drupal_add_css($base_theme_directory .'/css/screen/basemod.css', 'theme');
  drupal_add_css($base_theme_directory .'/css/screen/basemod_2col_left_13.css', 'theme');
  drupal_add_css($base_theme_directory .'/css/screen/basemod_drupal.css', 'theme');

  // Add horizontal navigations
  $yaml_nav_primary = theme_get_setting('yaml_nav_primary');
  if ($yaml_nav_primary == 1) {
    drupal_add_css($base_theme_directory .'/css/navigation/nav_shinybuttons.css', 'theme');
  }
  else {
    drupal_add_css($base_theme_directory .'/css/navigation/nav_slidingdoor.css', 'theme');
  }

...

And as dvessel said, people will use core themes as "template"...

merlinofchaos’s picture

Is there some reason that putting these .css file additions in the .info file not acceptable? The sub-theme system here was built more on the concept of inheritance, not of sharing.

There are other ways to do that, too.

But also, if you end up enabling some kind of filtering, you're going to destroy a feature that could also be highly beneficial.

hass’s picture

This is not possible. The theme have around 15 theme settings and they switch for e.g. menus with different styles, add debug CSS files with debug overlays and many other nice things. Additional i must keep the css cascading order intact... this is not possible with the static .info file settings together with a few dynamic settings. So i'm made to go abroad the inflexible .info file stuff.

Only one small example for dynamic switching:

$yaml_nav_primary = theme_get_setting('yaml_nav_primary');
  if ($yaml_nav_primary == 1) {
    drupal_add_css($base_theme_directory .'/css/navigation/nav_shinybuttons.css', 'theme');
  }
  else {
    drupal_add_css($base_theme_directory .'/css/navigation/nav_slidingdoor.css', 'theme');
  }

I saw this bug dvessel found, too in past too, but haven't opened a case. I offer example templates for specific modules in /mytheme/contrib/* folder and they have been used, but should only used if inside the theme folder them self. If someone place a file anywhere in a subdirectory he/she must name it differently or it get used by theme system. I don't like this confusing behavior and it add difficulties for deep directory structures.

What other ways are you talking about?

What benefits are you talking about? I don't see pro's for the current behavior.

dvessel’s picture

@merlinofchaos, how about selectively filtering for sub-themes? I totally agree, what we have now is very useful but due to legacy it could affect a lot of themes. I haven't checked, just a guess.

I'll work on a non-intrusive patch so we can keep what we have now but still filter for these situations.

dvessel’s picture

Status: Active » Needs review
FileSize
1.44 KB

What this does now:

When the active theme (foo) is a base theme:

foo/node.tpl.php                         < read
foo/templates/comment.tpl.php            < read
foo/foo-baz/node.tpl.php                 < sub-theme filtered
foo/foo-baz/templates/page.tpl.php       < sub-theme filtered

When active theme (foo-baz) is a sub-theme:

foo/node.tpl.php                         < ignored as usual
foo/templates/comment.tpl.php            < ignored as usual
foo/foo-baz/node.tpl.php                 < read
foo/foo-baz/templates/page.tpl.php       < read

I'm fairly confident this will work no matter how deep the hierarchy goes. Please review.

And the structure Merlinofchaos pointed out in #4 will work too.

fractile81’s picture

IMHO, I think it makes total sense to prune directories that have .info files in them that aren't the base theme's. The alternative is to create similarly-named .tpl.php files in the parent theme, which can be somewhat of a pain.

+1 on the patch. Applied it (RC1) and it properly skipped files from sub-themes.

merlinofchaos’s picture

Status: Needs review » Reviewed & tested by the community

Ok, hard to argue with that logic. I didn't think it'd be that easy to filter out just subdirs with a .info file.

Looks good to me, and fractile81 tested it successfully.

Gábor Hojtsy’s picture

Status: Reviewed & tested by the community » Fixed

Looks reasonable, thanks, committed.

hass’s picture

Status: Fixed » Active

What will happen in this situation?

foo/node.tpl.php                         < ignored as usual
foo/node-module.tpl.php                  < read base theme template if sub-theme does not have this template
foo/templates/comment.tpl.php            < ignored as usual
foo/foo-baz/node.tpl.php                 < read
[foo/foo-baz/node-module.tpl.php]        < file do not exist here in sub-theme
foo/foo-baz/templates/page.tpl.php       < read

That's something i wished it would work in D5 times and hoped this works now in D6 together with the base theme setting only... i haven't yet found the time to test your patch above. In past i was made to create dummy node.tpl.php files in the sub-theme folder that only have had the code include(realpath(dirname(__FILE__) .'/../../node.tpl.php'));. This was required after i placed a page.tpl.php in the sub-theme folder. In CSS only layouts there was nevertheless a fallback to the higher folder templates...

hass’s picture

Status: Active » Fixed

sorry, crossposted

fractile81’s picture

@hass: In the testing I've done with CSS-only themes (does this designation matter at this point with .info files?) in D6, all of the parent theme's .tpl.php files are being used unless there's an equivalent one supplied by the sub-theme.

merlinofchaos’s picture

hass: I'm not quite sure I understand your question exactly, so I'm going to give an example that I think addresses what you're looking for, and you can correct me if it's not right:

I have theme 'foo' and theme 'foo-bar' whose base theme is 'foo'.

foo/foo.info 
foo/foo-bar/foo-bar.info

If I have no tpl files in foo-bar at all, then foo-bar will automatically use tpl files from foo. Any tpl files actually in foo-bar will get precedence when using the foo-bar theme, however. So let's say I have this:

foo/foo.info 
foo/node.tpl.php
foo/page.tpl.php
foo/foo-bar/foo-bar.info
foo/foo-bar/page.tpl.php

When using the theme 'foo':

theme('page') --> foo/page.tpl.php
theme('node') --> foo/node.tpl.php

When using the theme 'foo-bar':

theme('page') --> foo/foo-bar/page.tpl.php
theme('node') --> foo/node.tpl.php

hass’s picture

When using the theme 'foo-bar':

theme('page') --> foo/foo-bar/page.tpl.php
theme('node') --> foo/node.tpl.php

Does this only happen if foo-bar implements "base theme" = foo? If so - perfect. :-)

dvessel’s picture

Exactly.! but there's one thing I missed in the patch since I'm not so good with loops. :)

With foo being active and foo-bar being dependent on foo:

foo
foo/foo-bar             < filtered

foo/foo-bar/foo-bar-baz < unfiltered
  ==or==
foo/foo-bar-baz         < unfiltered

The last two being dependent on foo-bar won't filter out the templates. It only processes the immediate sub-theme as it's structured with .info files.

This should be an easy fix. Only this part needs to be rearranged. Should be simple but I'm guessing it needs to use a while loop and I totally suck with those.

  // Collect sub-themes for the current theme. This allows base themes to have
  // sub-themes in its folder hierarchy without affecting the base theme.
  global $theme;
  $sub_themes = array();
  foreach (list_themes() as $theme_info) {
    if (!empty($theme_info->base_theme) && $theme_info->base_theme == $theme) {
      $sub_themes[] = dirname($theme_info->filename);
    }
  }

As long as $sub_themes is fed a list of paths, it'll work. It's not so complete ATM.

dvessel’s picture

Status: Fixed » Needs review
FileSize
1.96 KB

That was silly. No need to check for sub-theme. Just make sure the current theme isn't included in the list.

  // Collect a list of themes directories not owned by the current theme.
  // This is to prevent the active base theme from reading sub-theme templates
  // when they are placed in a sub-directory of the base theme.
  global $theme;
  $filter_list = array();
  foreach (list_themes() as $theme_info) {
    if ($theme_info->name != $theme) {
      $filter_list[] = dirname($theme_info->filename);
    }
  }
dvessel’s picture

forgot to remove a line from debugging.

dvessel’s picture

Status: Needs review » Needs work

Hrm, nevermind that patch. That would ignore base templates when the sub-theme is active. duh!

Any help with #19?

fractile81’s picture

How about this approach?

- It checks explicitly against the file's directory rather than relying on a search/replace
- A / is suffixed to directories to make sure you only match the desired sub-theme directories

I would think removing the string-functions would also boost the performance of the check. Thoughts?

This patch is untested, and is only a modification of a previous patch file. It's really meant more for illustrative purposes.

dvessel’s picture

fractile81, that wouldn't work. in_array() needs an exact match for the values. I used strpos & str_replace instead since it can detect partial matches. Performance isn't a problem. It's only done once when the registry is being rebuilt.

This isn't as important anymore since having multiple levels of inheritance wasn't supported before but it still annoys me knowing that there's a hole which should be easy to fix. :) I'll try updating this later. Any other input would be appreciated though.

dvessel’s picture

Status: Needs work » Needs review
FileSize
2.27 KB

Okay, this does it. It builds a complete list of interdependencies. Needed two loops, one to map immediate children then another to merge everything together. Fully tested and it's rock solid.

Mind reviewing please?

dvessel’s picture

Same as before cleaned up a bit.

dvessel’s picture

So, anyone mind testing? I've tested this myself and it's solid. Although minor, the idea that sub-themes can be structured within base themes, it's easy to fall into a trap where your lead to believe 2nd level sub-themes should behave the same.

Hass, especially your complicated theming could potentially run into this problem. :)

hass’s picture

I'd like to test this, but i'm very busy (16-18h at work) and i'm not sure how to test this patch in the right way.

hass’s picture

Status: Needs review » Reviewed & tested by the community

Ok, i've tested this patch in many ways. Testing goes from top to down and depends... i hope it's comprehensible.

1. Added "yaml/block.tpl.php".
2. Added "yaml/layouts/yaml_2col_left_13/block.tpl.php".
3. Activated "yaml" base theme and "yaml/layouts/yaml_2col_left_13"
->Result: Whatever theme is used as "Standard", the correct block.tpl.php is included. Success.

4. Moved "yaml/block.tpl.php" to "yaml/contrib/block.tpl.php".
->Result: Tested the inclusion of the "yaml/contrib/block.tpl.php" in base theme and subtheme block.tpl.php in yaml_2col_left_13. Success.

5. Removed "yaml/contrib/block.tpl.php".
6. Used "yaml" theme as default.
->Result: "yaml" included the Drupal Standard block.tpl.php and is not using the subtheme file as expected. Success.

7. Switched Standard Theme to Subtheme "yaml_2col_left_13".
8. Deactivated "yaml" base theme.
->Result: "yaml/layouts/yaml_2col_left_13" included the subthemes yaml/layouts/yaml_2col_left_13/block.tpl.php as expected. Success.

9. Added "yaml/contrib/block.tpl.php" back.
10. Deleted "yaml/layouts/yaml_2col_left_13/block.tpl.php".
->Result: "yaml_2col_left_13" included the base theme block.tpl.php as expected, nevertheless the base theme is active or not. Success.

11. Removed "yaml/contrib/block.tpl.php".
12. Moved "yaml/layouts/yaml_2col_left_13/block.tpl.php" to "yaml/layouts/yaml_2col_left_13/test/block.tpl.php"
13. Activated "yaml" base theme and deactivated "yaml_2col_left_13".
->Result: base theme fall back to drupal Standard block.tpl.php and does not include block.tpl.php in subthemes subdirectories. Success.

14. Activated "yaml" base theme and activated "yaml_2col_left_13".
->Result: base theme does not include block.tpl.php in subthemes subdirectories. Success.

All this testing worked as expected. THX.

Gábor Hojtsy’s picture

Status: Reviewed & tested by the community » Fixed

Thanks, committed.

Anonymous’s picture

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for two weeks with no activity.