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.

Modules and themes implementing this hook return an array of arrays. The key to each sub-array is the internal name of the hook, and the array contains information about the hook. Each array may contain the following elements:

  • arguments: (required) An array of arguments that this theme hook uses. This value allows the theme layer to properly utilize templates. The array keys represent the name of the variable, and the value will be used as the default value if not passed to the theme() function. These arguments must be in the same order that they will be given to the theme() function. Default values will only be passed to templates. If you want your theme function to assume defaults, specify them as usual in the argument list in the theme_HOOK_NAME() default implementation.
  • 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.
  • original hook: A string declaring the original 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 use 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.
  • theme paths: (automatically derived) An array of template suggestions where .tpl.php files related to this theme hook may be found.

The following parameters are all optional.

Parameters

$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: What 'type' 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 which 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 that is being being checked (mostly only useful for theme engine).

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

Return value

A keyed array of theme hooks.

Related topics

29 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.

$custom_theme in developer/globals.php
Name of custom theme to override default theme.
aggregator_theme in modules/aggregator/aggregator.module
Implementation of hook_theme()
block_theme in modules/block/block.module
Implementation of hook_theme()
book_theme in modules/book/book.module
Implementation of hook_theme()
chameleon_theme in themes/chameleon/chameleon.theme
Implementation of hook_theme. Auto-discover theme functions.

... See full list

1 invocation of hook_theme()
_theme_build_registry in includes/theme.inc
Rebuild the hook theme_registry cache.

File

developer/hooks/core.php, line 2190
These are the hooks that are invoked by the Drupal core.

Code

function hook_theme($existing, $type, $theme, $path) {
  return array(
    'forum_display' => array(
      'arguments' => array(
        'forums' => NULL,
        'topics' => NULL,
        'parents' => NULL,
        'tid' => NULL,
        'sortby' => NULL,
        'forum_per_page' => NULL,
      ),
    ),
    'forum_list' => array(
      'arguments' => array(
        'forums' => NULL,
        'parents' => NULL,
        'tid' => NULL,
      ),
    ),
    'forum_topic_list' => array(
      'arguments' => array(
        'tid' => NULL,
        'topics' => NULL,
        'sortby' => NULL,
        'forum_per_page' => NULL,
      ),
    ),
    'forum_icon' => array(
      'arguments' => array(
        'new_posts' => NULL,
        'num_posts' => 0,
        'comment_mode' => 0,
        'sticky' => 0,
      ),
    ),
    'forum_topic_navigation' => array(
      'arguments' => array('node' => NULL),
    ),
    'node' => array(
      'arguments' => array(
        'node' => NULL,
        'teaser' => FALSE,
        'page' => FALSE,
      ),
      'template' => 'node',
    ),
    'node_filter_form' => array(
      'arguments' => array('form' => NULL),
      'file' => 'node.admin.inc',
    ),
  );
}

Comments

If you do something like this:

<?php
function test_theme($existing, $type, $theme, $path) {
 
drupal_set_message("<pre>".print_r($existing,true)."</pre>");
}
?>

You will (potentially) get a White Screen of Death (WSOD).

Remember to return, at the very least, an empty array:

<?php
function test_theme($existing, $type, $theme, $path) {
 
drupal_set_message("<pre>".print_r($existing,true)."</pre>");
  return array();
}
?>

Try a regular /update.php to remedy it.

you may not need to use the path argument of the hook_theme(), instead you can just prefix the value of the template string with the name of the subfolder in your module folder that contains the template

'template' => 'templates/mymoduletemplate' ,
etc...

that has allowed me to keep my folders cleaner

if you want to use the path argument, you can use
drupal_get_path('module', $module_name);
to get the path to the folder of your module, and then suffix the fodler that will contain your templates

this can also be helpful to break apart large modules into subfolders for better organziation, and use them as includes in your code.

Be careful. I dont' think this will work if a theme tries to override your module's template since it will look for a templates directory within the theme.

No,
'template' => 'templates/' . $template_base_filename,
will absolutely work fine when the template file does NOT reside in a "templates" sub directory of the current theme. Just copy the template file to the theme directory to get it loaded.

Just wanted to throw this out there so other people don't run into the same problem I did.

The default argument defined in by 'arguments' aren't used when functions are called.

So say you have this

<?php
function HOOK_theme(...) { ... $hooks['reminder'] = array('arguments' => array('reminder_color' => 'blue')); ...}

function

HOOK_reminder($reminder_color) {... print $reminder_color; ...}

function

foo(...) {... theme('reminder') ...} //will not print 'blue', will throw an error - too few arguments
function bar(...) {... theme('reminder', NULL) ...} //will not print 'blue'
?>

BUT, if you were in reminder.tpl.php then

<?php
print $reminder_color; //prints 'blue'
?>

----------------

To see why read through the theme() function and pay special attention to these variables: $info['arguments'], $info['function'], $info['template']

The way to catch both instances is to also use argument defaults in your theme function:

<?php
function HOOK_reminder($reminder_color = 'blue') {... print $reminder_color; ...}
?>

Yeah, this just happened to me. Now I have one further complication: I want my default value to be a call to variable_get(), not a static value, and I can't put that into the function definition's default arg value.. i.e. this is a no-go:

<?php
function HOOK_reminder($reminder_color = variable_get('reminder_color', 'blue')) { ... }
?>

I'd think when theme() retrieves the output via function (not template), it should pass in the default values for arguments as they're defined in HOOK_theme() implementations...

Remember that, since hook_theme results are cached, using variable get as a default value can get outdated values sometimes. Is better to set a "default value" on preprocess.

The key to each sub-array is the internal name of the hook

It took me a while to figure this out. To most of you this is probably quite obvious but don't forget to start your theme functions with "theme_"

<?php
function myModule_theme($existing, $type, $theme, $path) {
    return array(
       
'my_theme_function' => array(
           
'arguments' => array('argument1' => null, 'argument2' => null)
    );
}

function

theme_my_theme_function($argument1, $argument2) {
   
// Do something with the arguments en generate some content
   
$content = "Blah blah";
    return
$content;
}
?>

# function: If specified, this will be the function name to invoke for this implementation. If neither file 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.

I'm totally confused by this. In my 5.x module I used _phptemplate_callback($hook, $vars), where $hook was name of the template and $vars its variables. I don't understand how to implement this hook from a module where I can pass the template name with variables. Please advise.

I think I'm starting to get it now, but still didn't get to work it right. So here is my implementation:
Instead of _phptemplate_callback($hook, $vars) I now have:

theme('template_name', $vars_array); //which should be the final output

hook_theme implementation

function mymodule_theme($existing, $type, $theme, $path){
  return array(
    'template_name' => array(
      'template'    => 'template_name',
      'arguments'  => array(),
    ),
  );
}

I see my custom template appears, but without the arguments' values.

OK. Got it to work. The array of arguments has to have pre-defined keys in the hook_theme().

The keys returned by this function have changed in D7

http://drupal.org/update/modules/6/7#hook_theme_render_changes

If you set in an overriding path in the hook_theme array Drupal will still look for a templates directory in the themes directory. It will take from the theme's template directory before looking to the override path.

I want to Drupal use tpl-file from theme folder, if it exists here, else to use file from module folder. How i can do that?

<?php
function ttanalytics_theme() {
    return array(
        
'ttanalytics_news_view' => array(
           
'arguments' => array('ttanalytics_news' => NULL),
           
'template' => 'analytics-news',
            
'path' => path_to_theme(),
            
'theme paths' => array(path_to_theme(),drupal_get_path('module', 'ttanalytics')),

         ),
    );
}

?>

Doesn't work

try this

<?php
function ttanalytics_theme() {
    return array(
        
'ttanalytics_news_view' => array(
           
'arguments' => array('ttanalytics_news' => NULL),
           
'template' => 'ttanalytics-news-view',
         ),
    );
}
?>

i think, but not sure. The template name must be same as theme hook name, but '_' replaced by '-'.
Sorry for my english

Yes, it is very important to name the template file based on the theme hook name. Otherwise, template files won't be recognized when located in a theme directory. Here is a code template that should work well:

<?php
function MYMODULE_theme($existing, $type, $theme, $path) {
 
$hook_name = HOOK;
 
$template_base_filename = preg_replace('/_/', '-', $hook_name);
 
$include_filename = MYMODULE . '.theme.inc';
  return array(
   
$hook_name => array(
     
'file' => 'includes/' . $include_filename,
     
'template' => 'templates/' . $template_base_filename,
     
'arguments' => array(
      ),
    ),
  );
}
?>

To the detriment of what hair remains, this bit of documentation eluded me when trying to set up a template theme hook. For the arguments return value:
* These arguments must be in the same order that they will be given to the theme() function.

I have a scenario where we can upload zipped packages of content. Each package has a .tpl file to be used to display the content contained therein.

I am launching the content via a url such as "content_view/99/longid", where:
"99" is the node id of the package in question
"longid" is an identifier for the content item we want to display (located IN the package)

As mentioned above, each of the uploaded content packages has it's own .tpl file to be used for displaying the content. THESE ARE NOT page.tpl.php FILES. They are used to theme a piece of page content - NOT the page proper.

I want to be able to tell Drupal to use the appropriate file for the appropriate package.

eg. The "Poker" package has a contentview.tpl.php file which should be used to display all of the content for the "Poker" package, but a "Light Trucks" package would have it's own version of the contentview.tpl.php file. The kicker is that these .tpl files are located in their respective packages - not in either the theme folder or the module folder.

From the supplied path, I can get the location of the .tpl file I need , but I can't get Drupal to use it.

It would seem like I could use a preprocess_hook function (eg. mymodule_preprocess_contentview()), but so far, no joy. :(

Does anyone have any suggestions or links of note that deal with this subject?

Cheers!

Ok... After a good night's sleep, I decided to have a look at the core code. I figured, "If Drupal can do it, so can I".

I found the function that actually processes the tpl files and copied that code to my own theming function (in my module directory).

Now my themeing function looks like this:

function theme_my_launchpage($data){
$template_file=$data['template'];
extract($data, EXTR_SKIP);  // Extract the variables to a local namespace
ob_start();                      // Start output buffering
include "./$template_file";      // Include the template file
$contents = ob_get_contents();   // Get the contents of the buffer
ob_end_clean();                  // End buffering and discard
return $contents;
}

Now, the variables stored in $data are inserted into the .tpl file ($data['template']) which is assigned when the menu callback runs.

Hope this helps someone. ...and if it does, please say so. I'm curious how many other people run into this type of use-case.

If you have defined some variables to be used in templates, but receive some incorrect values, check template_preprocess() and make sure that your variable name is not one of those "helper variables".