4.6.x theme.inc theme()
4.7.x theme.inc theme()
5.x theme.inc theme()
6.x theme.inc theme()
7.x theme.inc theme($hook, $variables = array())

Generates the themed output.

All requests for theme hooks must go through this function. It examines the request and routes it to the appropriate theme function. The theme registry is checked to determine which implementation to use, which may be a function or a template.

If the implementation is a function, it is executed and its return value passed along.

If the implementation is a template, the arguments are converted to a $variables array. This array is then modified by the module implementing the hook, theme engine (if applicable) and the theme. The following functions may be used to modify the $variables array. They are processed in this order when available:

  • template_preprocess(&$variables, $hook) This sets a default set of variables for all template implementations.
  • template_preprocess_HOOK(&$variables) This is the first preprocessor called specific to the hook; it should be implemented by the module that registers it.
  • MODULE_preprocess(&$variables, $hook) This will be called for all templates; it should only be used if there is a real need. It's purpose is similar to template_preprocess().
  • MODULE_preprocess_HOOK(&$variables) This is for modules that want to alter or provide extra variables for theming hooks not registered to itself. For example, if a module named "foo" wanted to alter the $submitted variable for the hook "node" a preprocess function of foo_preprocess_node() can be created to intercept and alter the variable.
  • ENGINE_engine_preprocess(&$variables, $hook) This function should only be implemented by theme engines and exists so that it can set necessary variables for all hooks.
  • ENGINE_engine_preprocess_HOOK(&$variables) This is the same as the previous function, but it is called for a single theming hook.
  • ENGINE_preprocess(&$variables, $hook) This is meant to be used by themes that utilize a theme engine. It is provided so that the preprocessor is not locked into a specific theme. This makes it easy to share and transport code but theme authors must be careful to prevent fatal re-declaration errors when using sub-themes that have their own preprocessor named exactly the same as its base theme. In the default theme engine (PHPTemplate), sub-themes will load their own template.php file in addition to the one used for its parent theme. This increases the risk for these errors. A good practice is to use the engine name for the base theme and the theme name for the sub-themes to minimize this possibility.
  • ENGINE_preprocess_HOOK(&$variables) The same applies from the previous function, but it is called for a specific hook.
  • THEME_preprocess(&$variables, $hook) These functions are based upon the raw theme; they should primarily be used by themes that do not use an engine or by sub-themes. It serves the same purpose as ENGINE_preprocess().
  • THEME_preprocess_HOOK(&$variables) The same applies from the previous function, but it is called for a specific hook.

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.


$hook: The name of the theme function to call. May be an array, in which case the first hook that actually has an implementation registered will be used. This can be used to choose 'fallback' theme implementations, so that if the specific theme hook isn't implemented anywhere, a more generic one will be used. This can allow themes to create specific theme implementations for named objects.

...: Additional arguments to pass along to the theme function.

Return value

An HTML string that generates the themed output.

224 calls to theme()
aggregator_block in modules/aggregator/aggregator.module
Implementation of hook_block().
aggregator_categorize_items in modules/aggregator/aggregator.pages.inc
Form builder; build the page list form.
aggregator_page_categories in modules/aggregator/aggregator.pages.inc
Menu callback; displays all the categories used by the aggregator.
aggregator_page_opml in modules/aggregator/aggregator.pages.inc
Menu callback; generates an OPML representation of all feeds.
aggregator_page_rss in modules/aggregator/aggregator.pages.inc
Menu callback; generate an RSS 0.92 feed of aggregator items or categories.

... See full list

31 string references to 'theme'
block_admin_display_form in modules/block/block.admin.inc
Generate main blocks administration form.
block_admin_display_form_submit in modules/block/block.admin.inc
Process main blocks administration form submission.
block_schema in modules/block/block.install
Implementation of hook_schema().
color_get_info in modules/color/color.module
Retrieve the color.module info for a particular theme.
color_scheme_form in modules/color/color.module
Form callback. Returns the configuration form.

... See full list


includes/theme.inc, line 613
The theme system, which controls the output of Drupal.


function theme() {
  $args = func_get_args();
  $hook = array_shift($args);

  static $hooks = NULL;
  if (!isset($hooks)) {
    $hooks = theme_get_registry();

  if (is_array($hook)) {
    foreach ($hook as $candidate) {
      if (isset($hooks[$candidate])) {
    $hook = $candidate;

  if (!isset($hooks[$hook])) {

  $info = $hooks[$hook];
  global $theme_path;
  $temp = $theme_path;
  // point path_to_theme() to the currently used theme path:
  $theme_path = $hooks[$hook]['theme path'];

  // Include a file if the theme function or preprocess function is held elsewhere.
  if (!empty($info['include files'])) {
    foreach ($info['include files'] as $include_file) {
      include_once ($include_file);

  // Handle compatibility with theme_registry_alters to prevent failures.
  if (!empty($info['file'])) {
    static $included_files = array();
    $include_file = $info['file'];
    if (!empty($info['path'])) {
      $include_file = $info['path'] . '/' . $include_file;

    if (empty($included_files[$include_file])) {
      // Statically cache files we've already tried to include so we don't
      // run unnecessary file_exists calls.
      $included_files[$include_file] = TRUE;
      if (file_exists('./' . $include_file)) {
        include_once ('./' . $include_file);

  if (isset($info['function'])) {
    // The theme call is a function.
    $output = call_user_func_array($info['function'], $args);
  else {
    // The theme call is a template.
    $variables = array(
      'template_files' => array()
    if (!empty($info['arguments'])) {
      $count = 0;
      foreach ($info['arguments'] as $name => $default) {
        $variables[$name] = isset($args[$count]) ? $args[$count] : $default;

    // default render function and extension.
    $render_function = 'theme_render_template';
    $extension = '.tpl.php';

    // Run through the theme engine variables, if necessary
    global $theme_engine;
    if (isset($theme_engine)) {
      // If theme or theme engine is implementing this, it may have
      // a different extension and a different renderer.
      if ($hooks[$hook]['type'] != 'module') {
        if (function_exists($theme_engine . '_render_template')) {
          $render_function = $theme_engine . '_render_template';
        $extension_function = $theme_engine . '_extension';
        if (function_exists($extension_function)) {
          $extension = $extension_function();

    if (isset($info['preprocess functions']) && is_array($info['preprocess functions'])) {
      // This construct ensures that we can keep a reference through
      // call_user_func_array.
      $args = array(&$variables, $hook);
      foreach ($info['preprocess functions'] as $preprocess_function) {
        if (function_exists($preprocess_function)) {
          call_user_func_array($preprocess_function, $args);

    // Get suggestions for alternate templates out of the variables
    // that were set. This lets us dynamically choose a template
    // from a list. The order is FILO, so this array is ordered from
    // least appropriate first to most appropriate last.
    $suggestions = array();

    if (isset($variables['template_files'])) {
      $suggestions = $variables['template_files'];
    if (isset($variables['template_file'])) {
      $suggestions[] = $variables['template_file'];

    if ($suggestions) {
      $template_file = drupal_discover_template($info['theme paths'], $suggestions, $extension);

    if (empty($template_file)) {
      $template_file = $hooks[$hook]['template'] . $extension;
      if (isset($hooks[$hook]['path'])) {
        $template_file = $hooks[$hook]['path'] . '/' . $template_file;
    $output = $render_function($template_file, $variables);
  // restore path_to_theme()
  $theme_path = $temp;
  // Add final markup to the full page.
  if ($hook == 'page' || $hook == 'book_export_html') {
    $output = drupal_final_markup($output);
  return $output;


joshmiller’s picture

This documentation makes no sense to me ;P

The docs book page on the theme registry and how to use it has illustrations and MAKES SENSE:


and of particular interest is this AMAZING pdf that explained this whole thing in about 10 seconds:


Also... it turns out I was actually looking to implement a hook for the theme function and that means you have tell drupal about this hook using hook_theme() ... who knew?

armanschwarz’s picture

This is terrible. I was less confused before I read that. Drupal documentation isn't the best but this needs some serious revision.

pcher1bw’s picture

Try reading Pro Drupal Development by John K. VanDyk, Chapter 3 discusses Hooks, Triggers and Actions, Chapter 2 describes how to write a module. MODULE_ above refers to your module name, for example if your module name is annotate then annotate_theme() is the hook for the theme for the annotate module.

MattBondi’s picture

Thank goodness......... I thought I was the only one who was struggling with Drupal documentation. It is so relieving to have others to commiserate with. Thanks for the tip on Pro Drupal Development.

Diogenes’s picture

So I looked at this page again, because I manage both D6 & D7 sites. I agree - this page is confusing.

At the very top of the page are two different function prototypes. I'm using C programming terminology here; bear with me, I'm getting old. To express this in old fashioned C style, the prototypes would be more like:

Drupal 4.6-6 theme( ... )
Drupal 7-8 theme( hook, ... )

The ... in the prototypes above mean a variable argument list. It could be a PHP associative list, it could be an object with the grand unifying theory of the universe embedded within.

In any event, the function using the ... parameter must have knowledge of the context to behave differently from the default behavior if the ... parameter is used.

So theme(...) is always passed an argument, though it elegantly defaults if no arguments are passed. In most situations there are arguments. The first one should always be the hook name. The theme() function has all kind of ways to derive and overide,

So both prototypes above are really expressing the same thing. It's a variable argument list.

There are remarkable ways of theming output with Drupal and the code included above gives to clues as to how it's all possible.

Don't worry if the included code doesn't make sense right now. Read more about hooks and templates first, and then visit here again.

Botros’s picture

I need to theme the user profile, what can i do ?
can i do something like that
theme('user_profile', $account);
is user_profile is a hook?

johnnydarkko’s picture

'user_profile' is the name of the theme hook function you'll need to use to override the default output. So to override this, you can copy the theme_user_profile() function to your theme's template.php and override the output. Change the function name to {YOUR_THEME_NAME}_user_profile().

Hope that helps!

mottolini’s picture

Hope this could help someone else.

If you have a hook_theme like this:

function yourmodule_theme() {
  return array(
    'xxx_yyy_zzz' => array(
      'arguments' => array(
        'arg1' => NULL, 
        'arg2' => NULL, 
      'template' => 'any_name_here', 

You'll probably find out that the template file used to render this theme function will always be the one provided by your module in /sites/all/modules/yourmodule/any_name_here.tpl.php. Any file named any_name_here.tpl.php put in any theme will simply be ignored, regardless of how many time your clear the cache or install and deinstall module and themes.

What you have to do is simply to name your template exactly like your function and not "any_name_here". So your hook_theme has to be:

function yourmodule_theme() {
  return array(
    'xxx_yyy_zzz' => array(
      'arguments' => array(
        'arg1' => NULL, 
        'arg2' => NULL, 
      'template' => 'xxx-yyy-zzz', 

You can use 'xxx-yyy-zzz' even if the function uses underscores instead of hyphens, because Drupal translates one into the other in core when it has to match functions and templates.
Of course your template file in the module and in the theme has to be named xxx-yyy-zzz.tpl.php.