function hook_theme

You are here

7 system.api.php hook_theme($existing, $type, $theme, $path)
6 core.php hook_theme($existing, $type, $theme, $path)
8 system.api.php hook_theme($existing, $type, $theme, $path)

Register a module (or theme's) theme implementations.

The implementations declared by this hook have two purposes: either they specify how a particular render array is to be rendered as HTML (this is usually the case if the theme function is assigned to the render array's #theme property), or they return the HTML that should be returned by an invocation of theme(). See Using the theme layer Drupal 7.x for more information on how to implement theme hooks.

The following parameters are all optional.

Parameters

array $existing: An array of existing implementations that may be used for override purposes. This is primarily useful for themes that may wish to examine existing implementations to extract data (such as arguments) so that it may properly register its own, higher priority implementations.

$type: Whether a theme, module, etc. is being processed. This is primarily useful so that themes tell if they are the actual theme being called or a parent theme. May be one of:

  • 'module': A module is being checked for theme implementations.
  • 'base_theme_engine': A theme engine is being checked for a theme that is a parent of the actual theme being used.
  • 'theme_engine': A theme engine is being checked for the actual theme being used.
  • 'base_theme': A base theme is being checked for theme implementations.
  • 'theme': The actual theme in use is being checked.

$theme: The actual name of theme, module, etc. that is being being processed.

$path: The directory path of the theme or module, so that it doesn't need to be looked up.

Return value

array An associative array of theme hook information. The keys on the outer array are the internal names of the hooks, and the values are arrays containing information about the hook. Each information array must contain either a 'variables' element or a 'render element' element, but not both. Use 'render element' if you are theming a single element or element tree composed of elements, such as a form array, a page array, or a single checkbox element. Use 'variables' if your theme implementation is intended to be called directly through theme() and has multiple arguments for the data and style; in this case, the variables not supplied by the calling function will be given default values and passed to the template or theme function. The returned theme information array can contain the following key/value pairs:

  • variables: (see above) Each array key is the name of the variable, and the value given is used as the default value if the function calling theme() does not supply it. Template implementations receive each array key as a variable in the template file (so they must be legal PHP variable names). Function implementations are passed the variables in a single $variables function argument.
  • render element: (see above) The name of the renderable element or element tree to pass to the theme function. This name is used as the name of the variable that holds the renderable element or tree in preprocess and process functions.
  • file: The file the implementation resides in. This file will be included prior to the theme being rendered, to make sure that the function or preprocess function (as needed) is actually loaded; this makes it possible to split theme functions out into separate files quite easily.
  • path: Override the path of the file to be used. Ordinarily the module or theme path will be used, but if the file will not be in the default path, include it here. This path should be relative to the Drupal root directory.
  • template: If specified, this theme implementation is a template, and this is the template file without an extension. Do not put .tpl.php on this file; that extension will be added automatically by the default rendering engine (which is PHPTemplate). If 'path', above, is specified, the template should also be in this path.
  • function: If specified, this will be the function name to invoke for this implementation. If neither 'template' nor 'function' is specified, a default function name will be assumed. For example, if a module registers the 'node' theme hook, 'theme_node' will be assigned to its function. If the chameleon theme registers the node hook, it will be assigned 'chameleon_node' as its function.
  • base hook: A string declaring the base theme hook if this theme implementation is actually implementing a suggestion for another theme hook.
  • pattern: A regular expression pattern to be used to allow this theme implementation to have a dynamic name. The convention is to use __ to differentiate the dynamic portion of the theme. For example, to allow forums to be themed individually, the pattern might be: 'forum__'. Then, when the forum is themed, call:
    theme(array('forum__' . $tid, 'forum'), $forum)
    
  • preprocess functions: A list of functions used to preprocess this data. Ordinarily this won't be used; it's automatically filled in. By default, for a module this will be filled in as template_preprocess_HOOK. For a theme this will be filled in as phptemplate_preprocess and phptemplate_preprocess_HOOK as well as themename_preprocess and themename_preprocess_HOOK.
  • override preprocess functions: Set to TRUE when a theme does NOT want the standard preprocess functions to run. This can be used to give a theme FULL control over how variables are set. For example, if a theme wants total control over how certain variables in the page.tpl.php are set, this can be set to true. Please keep in mind that when this is used by a theme, that theme becomes responsible for making sure necessary variables are set.
  • type: (automatically derived) Where the theme hook is defined: 'module', 'theme_engine', or 'theme'.
  • theme path: (automatically derived) The directory path of the theme or module, so that it doesn't need to be looked up.

See also

hook_theme_registry_alter()

Related topics

44 functions implement hook_theme()

Note: this list is generated by pattern matching, so it may include some functions that are not actually implementations of this hook.

aggregator_theme in modules/aggregator/aggregator.module
Implements hook_theme().
ajax_base_page_theme in includes/ajax.inc
Theme callback for Ajax requests.
block_theme in modules/block/block.module
Implements hook_theme().
book_theme in modules/book/book.module
Implements hook_theme().
color_theme in modules/color/color.module
Implements hook_theme().

... See full list

1 invocation of hook_theme()
_theme_build_registry in includes/theme.inc
Builds the theme registry cache.

File

modules/system/system.api.php, line 2220
Hooks provided by Drupal core and the System module.

Code

function hook_theme($existing, $type, $theme, $path) {
  return array(
    'forum_display' => array(
      'variables' => array(
        'forums' => NULL,
        'topics' => NULL,
        'parents' => NULL,
        'tid' => NULL,
        'sortby' => NULL,
        'forum_per_page' => NULL,
      ),
    ),
    'forum_list' => array(
      'variables' => array(
        'forums' => NULL,
        'parents' => NULL,
        'tid' => NULL,
      ),
    ),
    'forum_topic_list' => array(
      'variables' => array(
        'tid' => NULL,
        'topics' => NULL,
        'sortby' => NULL,
        'forum_per_page' => NULL,
      ),
    ),
    'forum_icon' => array(
      'variables' => array(
        'new_posts' => NULL,
        'num_posts' => 0,
        'comment_mode' => 0,
        'sticky' => 0,
      ),
    ),
    'status_report' => array(
      'render element' => 'requirements',
      'file' => 'system.admin.inc',
    ),
    'system_date_time_settings' => array(
      'render element' => 'form',
      'file' => 'system.admin.inc',
    ),
  );
}

Comments

Just in case it's not completely obvious to those implementing hook_theme in Drupal 7, the custom theme function is passed an array of associative elements. Take for example the following callback function passing the node object:

function custom_output_callback($node) {
  print theme('custom_output', array('node' => $node));
}

function custom_theme() {
  return array(
    'custom_output' => array(
      'variables' => array('node' => NULL),
    ),
  );
}

function theme_custom_output($variables) {
  $node = $variables['node'];
  $build = node_view($node);
  $output = drupal_render($build);
  return $output;
}

The function theme_custom_output() includes the array argument $variables, which contains the node object accessed with the key "node" defined in custom_theme().

I wasted some time figuring out this subtle, but vital difference between Drupal 6 and 7.

Thanks für the handy example. It's a big time saver.

Don't get burned by the descriptions above about template and pattern. They are not as flexible as they are made out to be.

When you override a template, even if the template property is set, the template must match the theme function key (or hook). This essentially makes the template property useless.

@mradcliffe

I ran into this same problem. It's very surprising. Is there something we're missing, or is the template property actually just a redundant, useless setting?

A fix for this is available for D8 and D7 at http://drupal.org/node/342350. It's been committed for D8, but not yet D7.

If you happen to have same name for a module and a theme don't forget to check the type in hook_theme, because otherwise it may hit 'theme' type and try to include file mymodule-template.tpl.php from the theme's folder instead of the module's folder
Hook theme:

function mymodule_theme($existing, $type, $theme, $path)
{
  if($type == 'module')
  {
    return array(
      'mymodule_template' => array(
        'variables' => array('var_name'=>NULL),
        'template' => 'mymodule-template'
      ),
    );
  }
  return array(); //will raise fatal error if void
}

Call it as usual:

theme('mymodule_template', array('var_name'=>mymodule_variable()));

You should never name your module and theme the same. You may have found a workaround for hook_theme but there are many other places where it will cause confusion. Everything must be unique to prevent naming collisions. This includes theme engines if anyone thinks of writing one. Possibly other types of components too.

The documentation says "render element: (required if "variables" not present) A string that is the name of the sole renderable element to pass to the theme function. The string represents the name of the "variable" that will hold the renderable array inside any optional preprocess or process functions."

It would be better to clarify that $variables can contain a single key whose value is a render array.

To set this up, 'render element' in hook_theme() should hold the name of the key in $variables whose value is the render element. Thus 'render element' => 'myElement' in hook_theme() means that $variables['myElement'] is the render element (or array).

This $variables, with its single key-value pair, is passed to the [pre]process functions and thence to the theme function or template.

See the video http://chicago2011.drupal.org/sessions/render-api-drupal-7 , time 8:00 to 13:30 .

The name of theme hooks must be less than 32 caracters (it's a database limitation). Theme hooks with longer than 32 caracters name won't work.

Exmaple;

mymods/custompage.tpl.php
mymods/mymods.module

<?php
// in mymods.module
function mymods_menu() {
   
// define your custom path here
   
$items['a-path/custompage'] = array(
     
'page callback' => 'mymods_custompage',
     
'page arguments' => array(),
     
'access arguments' => array('access content'),
     
'type' => MENU_CALLBACK,
    ); 
    return
$items;
}

function

mymods_custompage() {
    return
theme('mymods_custompage_template');
}

function

mymods_theme() {
   
$themes = array (
       
'mymods_custompage_template' => array(
           
'template' => 'custompage', // your template file called custompage.tpl.php
           
'arguments' => array(),
        ),
    );
    return
$themes;
}
?>

Now you can add whatever to custompage.tpl.php and it'll show up in /a-path/custompage

step 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
    ),
  );
}

step 2- echo/return the theme in your page.tpl or any .tpl

$output = theme('xxx_xxx', $xxx);

step 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 :)

'arguments' should be 'variables'

so..

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

step 2 should be this:

$output = theme('xxx_xxx', array('xxx' => $xxx));

Hi, this is my code:

function kitt_menu(){
$items['quoting'] = array(
'title' => '',
'page callback' => '_kitt_quotes',
'access callback' => TRUE,
'type' => MENU_CALLBACK,
);
return $items;
}

function _kitt_quotes() {
$quotes_array = get_quotes_array();
return theme('quoting', array('quotes' => $quotes_array));
}

function kitt_theme($existing, $type, $theme, $path) {
return array(
'quoting' => array(
'variables' => array('risk' => NULL, 'quotes' => NULL),
)
);
}

i would like to do a simple and obvious thing: i have a variable in my module ($quotes_array) and i want to pass to my theme page. I think i should find it inside $variables in my page template, but i can't find it, it seems that the hook theme doesn't work correctly.
I made some errors in my code?
Can someone help me?
Thanks,

Calcifer

I tried modifying the template in a theme() declared by webform module, with the following code

function mytheme_theme() {
  $theme = array(
    'webform_results_submissions' => array(
    'render element' => 'element',
    'template' => drupal_get_path('theme', 'mytheme_theme') . '/templates/webform-results-submissions',
    'file' => drupal_get_path('module', 'webform') . '/includes/webform.report.inc'),
  );

  return $theme;
}

However, I end up with the following error :

Warning : include_once(.../htdocs/prod_danity.fr_multi/sites/all/themes/mytheme_theme/sites/all/modules/webform/includes/webform.report.inc) [function.include-once]: failed to open stream: No such file or directory dans theme() (ligne 942 dans /Users/.../includes/theme.inc).

As you can see, even thought I tried to set different folder path for the file and template file, it seems like the both of them are related

Be careful, there are some words you can't use as variable names inside the 'variables', because they will be overriden on the template_preprocess function:

http://api.drupal.org/api/drupal/includes!theme.inc/function/template_pr...

Those words are: zebra, id, directory, classes_array and default_variables.

Be careful when naming hooks. Do not use hyphens as separators in hook names i.e 'user-picture', use underscores instead. i.e. 'user_picture'. This is because hooks become part of preprocess function names. Hyphens are illegal in PHP function names.

I found that when registering a brand new theme function (not an override) inside template.php, it was necessary to specify the 'function'. The documentation above says a default function will be used, but that just doesn't happen.

<?php
function MYTHEME_theme() {
  return array(
   
'my_custom_name' => array(
     
'variables' => array(...),
    )
  );
}

function

theme_my_custom_name($variables) {
  ...
  return
$output;
}
?>

...seems like that should work, but it doesn't. The function needs to be specified:

<?php
function MYTHEME_theme() {
  return array(
   
'my_custom_name' => array(
     
'variables' => array(...),
     
'function' => 'theme_my_custom_name',
    )
  );
}
?>

This worked for me as well. This is still the only reference I've found to the function attribute.

I really like working with render array. It's easy and clean.

So why should I use theme() function and not render() function?

Actually, render() and theme() functions have different purposes, and are designed to work in conjunction.
The purpose of render() is traversing callback result (renderable array), converting it to HTML (or other format). Converting individual pieces is a work of theme(), and renderable array contains special elements like #theme and #theme_wrapper elements, to help render() decide which theme functions to use.

If you have a default template in your module, you MUST define the 'template' directive or D7 by default will only look in theme's template dir ( will not look in module dir ):

/**
* Implement hook theme
*/
function my_module_name_theme( &$existing, &$type, &$theme, &$path )
{
return array(
'my_module_name_page' => array(
'results' => array(),
// REQUIRED if you want to put your
// default template in module dir,
// otherwise D7 will ALWAYS look in theme dir
'template' => 'my_module_name_page'
)
);
}

Also, unlike D6, you must put your theme variable[s] in an array:
Set variables (both D6 and D7):

$results = array(
'module_path' => drupal_get_path( 'module', 'my_module_name' ),
'theme_path' => drupal_get_path( 'theme', 'my_theme' ),
);

Theme:
D6:

return theme( 'my_module_name_page', $results );

D7:

return theme( 'my_module_name_page', array( 'results' => $results ) );

Where I have to use theme ()?
Thank you.

Always try to use a template filename that matchs your theme (hook).

The template filename should be the theme hook name (you have to replace underscores '_' by dashes '-'). If you use a different template filename by using the 'template' key, Drupal theme registry won't reconize the template file placed in your theme folder as an implementation of your theme hook.

This is good example :

function HOOK_theme() {
   return array(
    'homepage_carousel' => array(
      'template' => 'homepage-carousel'
      'variables' => array(...),
    )
  );
}

The following example is bad, if you copy-paste the template file from the module folder to a theme (bartik, zen, your own, etc...) folder, it won't be reconize by Drupal as an implementation of the 'homepage_carousel' theme.

function HOOK_theme() {
   return array(
    'homepage_carousel' => array(
      'variables' => array(...),
      'template' => 'a-random-funny-name',
    )
  );
}

There is another good exemple, i put templates files in a templates folder in my module as a default implementation :

function HOOK_theme() {
  $module_path = drupal_get_path('module', 'MYMODULE');

   return array(
    'homepage_carousel' => array(
      'variables' => array(...),
      'template' => 'homepage-carousel'
      'path' => $module_path.'/templates',
    )
  );
}

once i changed the 'render element' => 'form' to 'render element' => 'fuck'. nothing changed in my page!!
so,what's the 'render element' real meaning?

Might be worth mentionning that when you implement this hook, DO NOT use a module name ending with "custom" (or "exisitingModuleName_custom", I'm not sure).

After a quick look, it seems to choke on line 1744 in menu.inc :
$custom_themes = array_filter(module_invoke_all('custom_theme'), 'drupal_theme_access'); which ends up passing the array returned by this implementation of hook_theme() to the function drupal_theme_access($theme) in theme.inc, which results in the following warning : Warning : Illegal offset type in isset or empty in drupal_theme_access() (line 53 in includes/theme.inc)

THANK YOU THANK YOU @Paulmicha!
Confirmed: I was seeing the same thing. I moved my hook_theme out of xyz_custom into another module, and the warning went away after clear-cache.

It seems "pattern" property doesn't exist really. It documented here but you won't find it in the theme() function

You'll find it used in drupal_find_theme_functions(). This function breaks down any variants based on the pattern and registers them against that theme implementation.

The theme implementations array is then cached, and theme() then just passively consumes it later.

If the template-name is not equal to the theme-name, it will not be found outside your module. eg:

  return array(
    'new_champs_slider' => array(
      'template' => 'blablabla',
      'variables' => array('start_slide' => 0),
    ),
  );

Here blablabl.tpl.php will be found in the module's-folder but not in the theme.
Rename the 'template' in this way:

      'template' => 'new_champs_slider',

so new_champs_slider.tpl.php will be found in your custom-theme.

If the 'template' string contains a dot, likewise:

function moo_theme() {
  return array(
    'moo_theme_stuff' => array(
      'variables' => array(
        'moo' => NULL,
      ),
      'template' => 'moo-stuff.stuff',
    ),
  );
}

It will fail. In your module, the tpl.php will be recognized and used, but you won't be able to override it from a theme.

And the reason for this:

foreach ($matches as $match) {
          $file = substr($match, 0, strpos($match, '.'));

- theme.inc , line ~1362
Here some magic happen that rely on the first dot in the string simply.

Information that returns from the hook implementation may also contain an 'includes' element (@see theme()) which is an array of filepaths relative to DRUPAL_ROOT that should be included before a theme function call if it resides not in the main .module file.