The theme registry for special cases

Last updated on
31 August 2016

You should be familiar with the purpose of the theme registry before continuing on this page. The instructions here will cover how to manually register a theming hook and explain how it can be manipulated.

The most common case for manually registering hooks is in forms. Form elements are themable but there is another dimension to how they are processed. There are the generic elements such as checkboxes, radio selects, submit button, drop down menus, etc. Each element is themable on its own and overriding it does not require manually registering the hooks associated with it. The extra dimension comes in with custom forms where each element is arranged in very specific ways. In some forms, they are already arranged, themed and registered. For these forms, manually registering is not required. The forms that are not explicitly themed will default to how form API renders them.

Registered form example:
Here's an example for two of the search forms registered by search.module, the search box and search block. Every form has a unique ID associated with it. Registering the IDs also serves as the theming hook. In this case, it is "search_theme_form" and "search_block_form".
function search_theme() {
  return array(
    'search_theme_form' => array(
      'arguments' => array('form' => NULL),
      'template' => 'search-theme-form',
    ),
    'search_block_form' => array(
      'arguments' => array('form' => NULL),
      'template' => 'search-block-form',
    ),
    ...
  );
}

The Form API passes control of its presentation along to the handler of the registered hook. In this example, it is registered with the type of template with its default arguments. The output can be altered easily from the theme since it was already registered as a template. Auto discovery of the hook only happens with existing theming hooks registered below the theming layer. (see image)

Registering an unregistered form:
There is another search form that is not registered. It is the form with the ID of "search_form" used on the main search page. The data for the form is constructed in a function just like any other form but it leaves it up to the Form API to deal with the presentation based on its data structure.

To extend this so it can be overridden, you have to register it from your theme with hook_theme. Place the following inside your template.php file replacing the "drop" prefix with the name of your theme. The theming hook is the ID of the form:

function drop_theme() {
  return array(
    'search_form' => array(
      'arguments' => array('form' => NULL),
    ),
  );
}

Themed forms always have an argument of "form". Since the template was not specified, the hook will be seen as a theme function, not a template. The theme function has to have a matching prefix of the theme that registered it. phptemplate_* will not work. So, with the above entry, the theme function would look like this:

function drop_search_form($form) {
  $advanced = '';
  $simple = '';
  foreach (element_children($form) as $element) {
    if ($element == 'advanced') {
      $advanced .= drupal_render($form[$element]);
    }
    else {
      $simple .= drupal_render($form[$element]);
    }
  }
  return $advanced . $simple;
}

The only thing changed here is the positioning of the advanced search form.

  • Sub-themes overriding a form that was registered in its base theme does not have to manually re-register the form. Remember, the registering allows auto discovery for the layers above it and sub-themes are just another layer on top of base themes.
  • This may be more automated in future versions. The developers are aware of the burden it places on themers.

Manual manipulating

Manual manipulation of the theme registry is an advanced feature. You can read about it by clicking the "Theme registry" in the block provided by devel module. It can also be returned with theme_get_registry.

To be continued...