I've read the theming guide. I've read example.module and node.module.

  1. theme('a') invokes template_preprocess_a(array &$variables);

  2. template_preprocess_a(array &$variables) sets $variables['theme_hook_suggestions'][] = 'a__b';

  3. Both a.tpl.php and a--b.tpl.php exist in the module directory.

  4. The theme system always invokes a.tpl.php but never invokes a--b.tpl.php

What am I doing wrong?

Comments

pillarsdotnet’s picture

StatusFileSize
new453 bytes
new455 bytes

Example code demonstrates the problem in both d6 and d7. Steps to reproduce:

  1. Install module on example.com.
  2. Visit http://example.com/a
  3. Page content says "a". It should say "b".
pillarsdotnet’s picture

Title: Trivial theme example that follows documented instructions not working. Bug in core or in docs? » Can't get theme_hook_suggestions to work.
Status: Fixed » Active

EDIT: now working, thanks to effulgentsia!

D7 version:

a.info
name = A
core = 7.x
a.module

function a_menu() {
  return array(
    'a' => array(
      'title' => 'A',
      'page callback' => 'a',
      'access callback' => TRUE,
      'type' => MENU_CALLBACK,
    ),
  );
}

function a_theme() {
  return array(
    'a' => array(
      'render_element' => 'elements',
      'template' => 'a',
    ),
    'a__b' => array(
      'render_element' => 'elements',
      'template' => 'a--b',
    ),
  );
}

function a() {
  return theme('a');
}

function template_preprocess_a(array &$v) {
  $v['theme_hook_suggestions'][] = 'a__b';
}
a.tpl.php
a
a--b.tpl.php
b
pillarsdotnet’s picture

Title: Can't get theme_hook_suggestions to work. » Why does this page display "a" instead of "b" ?
pillarsdotnet’s picture

Title: Can't get theme_hook_suggestions to work. » Why does this page display "a" instead of "b" ?

EDIT: now working, thanks to effulgentsia!

D6 version:

a.info
name = A
core = 6.x
a.module

function a_menu() {
  return array(
    'a' => array(
      'title' => 'A',
      'page callback' => 'a',
      'access callback' => TRUE,
      'type' => MENU_CALLBACK,
    ),
  );
}

function a_theme() {
  return array(
    'a' => array(
      'render_element' => 'elements',
      'template' => 'a',
    ),
    'a_b' => array(
      'render_element' => 'elements',
      'template' => 'a-b',
    ),
  );
}

function a() {
  return theme('a');
}

function template_preprocess_a(array &$v) {
  $v['template_files'][] = 'a_b';
}
a.tpl.php
a
a-b.tpl.php
b
ralt’s picture

Hello,

I think you're using your preprocess function the wrong way.

When you do this :

function template_preprocess_a(array &$v) {
  $v['theme_hook_suggestions'][] = 'a_b';
}

You're "creating" a variable named $theme_hook_suggestions, which will be filled with 'a_b'. This means that if you display $theme_hook_suggestions in a.tpl.php OR a-b.tpl.php, you will see the string 'a_b'.

If you want to display $b in a-b.tpl.php ONLY, then you need to create the function template_preprocess_a_b(&$v).

If you use this :

function template_preprocess_a(&$v) {
  $v['b'][] = 'whatever';
}

Then the variable $b will be available in BOTH a.tpl.php and a-b.tpl.php.

I hope I'm making myself clear!

Edit : I'm only talking about D6 version. But D7 shouldn't be very different.

pillarsdotnet’s picture

@Ralt -- Sorry. In the d6 version I should have had template_files instead of theme_hook_suggestions. Will re-edit above to correct. (Testing... corrected, but the problem persists; sigh.)

From the d6 theme() docs:

There are two special variables that these hooks can set: 'template_file' and 'template_files'. These will be merged together to form a list of 'suggested' alternate template files to use, in reverse order of priority. template_file will always be a higher priority than items in template_files. theme() will then look for these files, one at a time, and use the first one that exists.

From the d7 theme() docs:

There are two special variables that these preprocess and process functions can set: 'theme_hook_suggestion' and 'theme_hook_suggestions'. These will be merged together to form a list of 'suggested' alternate theme hooks to use, in reverse order of priority. theme_hook_suggestion will always be a higher priority than items in theme_hook_suggestions. theme() will use the highest priority implementation that exists. If none exists, theme() will use the implementation for the theme hook it was called with. These suggestions are similar to and are used for similar reasons as calling theme() with an array as the $hook parameter (see below). The difference is whether the suggestions are determined by the code that calls theme() or by a preprocess or process function.

You are suggesting that I should:

  • (d6) declare template_preprocess_a_b() instead of adding 'a_b' to template_files.
  • (d7) declare template_preprocess_a__b() instead of adding 'a__b' to template_files.

If that were so, then the d6 node.module would need to declare every possible template_preprocess_node_$nid() in order for node-specific templates like node-1.tpl.php to be invoked.

pillarsdotnet’s picture

StatusFileSize
new444 bytes
new451 bytes

updated example code. Corrected "theme_template_suggestions" to "template files" in the d6 version but the problem persists.

pillarsdotnet’s picture

Category: support » bug
meba’s picture

Category: bug » support

Why is this a bug report?

pillarsdotnet’s picture

Category: support » bug

@meba -- When an example as trivial as this doesn't work despite exactly following the instructions in the docs, that's a bug. Dunno if it's a docs bug or a core bug. Do you?

pillarsdotnet’s picture

Title: Why does this page display "a" instead of "b" ? » Trivial theme example that follows documented instructions not working. Bug in core or in docs?
effulgentsia’s picture

See http://api.drupal.org/api/drupal/modules--poll--poll.module/function/pol....

The problem is that the theme system only auto-discovers suggestions (or any templates) within themes. It does not auto-discover templates in modules. Modules need to declare them in hook_theme(), as in the poll.module example.

pillarsdotnet’s picture

Category: bug » support
Status: Active » Fixed

Thanks.

pillarsdotnet’s picture

So the mechanism that makes node--1.tpl.php work doesn't have anything to do with the code in template_preprocess_node()? Or does it need to be supported in both theme and module in order to work?

bfroehle’s picture

Title: Why does this page display "a" instead of "b" ? » Trivial theme example -- now working.
Status: Active » Fixed

I think what @effulgentsia was trying to say is that a--b.tpl.php will work if placed in your theme directory, but not in the module directory.

pillarsdotnet’s picture

Okay; I've got a working example I can build from now; thanks.

Soon as I've solved the immediate problem I'll work on building a docs page.

effulgentsia’s picture

There's two parts to the equation for making suggestions work:
1. The theme registry needs to be aware that the suggestion is implemented (and where the implementation is).
2. A preprocess function needs to instruct the theme system which suggestions to search through.

So, template_preprocess_node() contains $variables['theme_hook_suggestions'][] = 'node__' . $node->nid;, satisfying #2.

For #1, the "--" delimiter is useful, because if node_theme() defines an entry for 'node', then if a theme contains node--1.tpl.php, the theme system automatically finds it when it builds the theme registry. It doesn't do this automatically for any other delimiter.

There is no auto-discovery of templates in modules, though. But, it's also much less common for modules to implement templates for suggestions. I don't think it happens anywhere in core other than poll.module. The main usefulness of suggestions is for greater control by the theme. In other words, there's lots of reasons why a site's custom theme would implement a node--1.tpl.php template, but why would a module do so?

pillarsdotnet’s picture

In my particular case, I want to add a htmlmail--simplenews.tpl.php suggestion template to HTML Mail in order to demonstrate how to customize Simplenews messages. My first attempt failed, and after a couple of hours of reading docs and re-writing code, I created a minimal problem demonstration module, and posted it here.

Status: Fixed » Closed (fixed)

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