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?
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:
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.