Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does hook_theme() work?

I am having a hard time understanding what hook_theme() does.

My understanding is that it has something to do with making it possible to override templates.

I was looking at:

  $theme_hooks = array(
    'poll_vote' => array(
      'template' => 'poll-vote',
      'render element' => 'form',
    ),
    'poll_choices' => array(
      'render element' => 'form',
    ),
    'poll_results' => array(
      'template' => 'poll-results',
      'variables' => array('raw_title' => NULL, 'results' => NULL, 'votes' => NULL, 'raw_links' => NULL, 'block' => NULL, 'nid' => NULL, 'vote' => NULL),
    ),
    'poll_bar' => array(
      'template' => 'poll-bar',
      'variables' => array('title' => NULL, 'votes' => NULL, 'total_votes' => NULL, 'vote' => NULL, 'block' => NULL),
    ),
  );

Could you provide an example of how it works?

like image 917
Chris Muench Avatar asked Oct 12 '11 15:10

Chris Muench


2 Answers

It provides a place for a module to define its themes, which can then be overridden by any other module/theme. It will also provide the opportunity for any module to use a hook such as mymodule_preprocess_theme_name to change the variables passed to the eventual theme function or template file.

There are basically two ways to initialise a theme function:

theme('poll_results', array('raw_title' => 'title', 'results' => $results, etc...));

and

$build = array(
  '#theme' => 'poll_results',
  '#raw_title' => 'title',
  '#results' => $results,
  etc...
); // Note the '#' at the beginning of the argument name, this tells Drupal's `render` function that this is an argument, not a child element that needs to be rendered.

$content = render($build); // Exact equivalent of calling the previous example now that you have a render array.

Please keep in mind, you should avoid calling theme() directly (per the documentation in theme.inc) since it:

  • Circumvents caching.
  • Circumvents defaults of types defined in hook_element_info(), including attached assets
  • Circumvents the pre_render and post_render stages.
  • Circumvents JavaScript states information.

In Drupal 8, theme() is a private function, _theme(). For more detail, please see www.drupal.org/node/2173655.

When you compare the two of these to the poll_results element in the example you give above you can probably work out what's happening...since PHP is not a strongly typed language Drupal is providing 'named arguments' through either a keyed array passed to the theme function, or as hashed keys in a render array.

As far as 'render element' is concerned, this basically tells the theme system that this theme function will be called using a render array, with one named argument (in this case form). The code would look something like this:

$build = array(
  '#theme' => 'poll_choices',
  '#form' => $form
);

This will pass whatever's in the $form variable to the theme function as it's sole argument.

Regarding the template key:

'poll_vote' => array(
  'template' => 'poll-vote',
  'render element' => 'form',
)

defines a theme called poll_vote which uses a template file (hence the template key) with a name of 'poll-vote.tpl.php' (this is by convention). The path to that template file will be found by using the path to the module that implements it (e.g. modules/poll/poll-vote.tpl.php), so it's fine to put template files in sub-folders of the main module folder.

There are two ways to actually return the output for a theme function, by implementing the physical function name (in this case it would be theme_poll_vote) or by using a template file. If the template key is empty Drupal will assume you've implemented a physical function and will try to call it.

Template files are preferable if you have a fair bit of HTML to output for a theme, or you simply don't like writing HTML in strings inside PHP (personally I don't). In either case though, the variables passed when you call the theme (either using theme() or a render array as described above) are themselves passed through to the template file or theme function. So:

function theme_poll_results(&$vars) {
  $raw_title = $vars['raw_title'];
  $results = $vars['results'];
  // etc...
}

If you were using a template file instead for the same method the variables would be available as $raw_title, $results, etc, as Drupal runs extract on the $vars before parsing the template file.

I'm sure there's a lot I've missed out here but if you have any more specific questions ask away and I'll try to help out.

like image 155
Clive Avatar answered Nov 06 '22 13:11

Clive


Drupal 6

I was stuck all day with this and now successfully implemented, so sharing my finding here, may it will help understand hook_theme.

There are 3 steps involved:

  1. hook_theme

    function YOURMODULENAME_theme() {
      return array(
        'xxx_xxx' => array(
        'template' => 'xxx-xxx', // define xxx-xxx.tpl.php inside module
        'arguments' => array('xxx' => null), //define $xxx so it will available in your xxx-xxx.tpl.php
        ),
      );
    }
    
  2. echo/return the theme in your .tpl or any .module

    $output = theme('xxx_xxx', $xxx);
    
  3. Now variable are magically available in you xxx-xxx.tpl.php.

    <?php echo $xxx ?>
    

Note: you can pass $xxx as array,object or anything :)

like image 29
Serjas Avatar answered Nov 06 '22 13:11

Serjas