Same filename and directory in other branches
  1. 6.x-1.x theming_example/theming_example.module

Explains how a module declares theme functions, preprocess functions, and templates.

The underlying approach is that a module should allow themes to do all rendering, but provide default implementations where appropriate.

Modules are also expected to leave data as render arrays as long as possible, leaving rendering to theme functions and templates.

File

theming_example/theming_example.module
View source
<?php

/**
 * @file
 * Explains how a module declares theme functions, preprocess functions, and
 * templates.
 *
 * The underlying approach is that a module should allow themes to do all
 * rendering, but provide default implementations where appropriate.
 *
 * Modules are also expected to leave data as render arrays as long as possible,
 * leaving rendering to theme functions and templates.
 */

/**
 * @defgroup theming_example Example: Theming
 * @ingroup examples
 * @{
 * Example of Drupal theming.
 *
 * The theming_example module attempts to show how module developers can add
 * theme functions to their projects so that themes can modify output.
 *
 * Module developers should to strive to avoid hard-wiring any HTML into the
 * output of their code, this should all be done in theme functions.
 *
 * Starting with the first example, function 'theming_example_page()':
 * the output is put into an array $content which is then fed to a theming
 * function 'theme_theming_example_content_array()' which loops over the
 * content, wrapping it in html in the process.
 *
 * In order to get function 'theme_theming_example_content_array()' recognized
 * it needs to be registered with the module theme register function of the type
 * 'hook_theme'.
 *
 * function 'theming_example_theme()' does this for this module.
 * for details of what can be done in this hook see the link to api.drupal.org
 *
 * The functions 'theming_example_list_page()' and theming_example_order_form()
 * work in the same way.
 *
 * In 'theme_theming_example_list_page()' the content is themed as an
 * ordered list and given a class attribute 'theming_example_mylist' which
 * is defined in theming_example.css
 *
 * In function 'theme_theming_example_order_form()' the title is loaded into a
 * temporary variable '$title', deleted from the $form array and output
 * wrapped in html. The rest of the form is wrapped in a div using '#prefix'
 * and '#suffix'
 *
 * The theming functions can be copied to a theme's template.php, renaming
 * appropriately, so if your theme is called 'mytheme' you would copy function
 * 'theme_theming_example_content_array()' to function
 * 'mytheme_theming_example_page()' in template.php and it will be used instead
 * of the original.
 *
 * The fourth example shows the use of a template file
 * 'theming_example_text_form.tpl.php'
 * This file can be copied to a theme's folder and it will be used instead.
 *
 * This example also shows what can be done using Drupal's
 * template_preprocess_HOOK method. In this case it modifies the output so
 * that a themer can output the whole form or gain control over some of its
 * parts in the template file.
 */

/**
 * Implements hook_menu().
 *
 * The @link menu_example.module Menu Example @endlink provides extensive
 * examples for hook_menu().
 */
function theming_example_menu() {
  $items['examples/theming_example'] = array(
    'title' => 'Theming Example',
    'description' => 'Some theming examples.',
    'page callback' => 'theming_example_page',
    'access callback' => TRUE,
    'access arguments' => array(
      'access content',
    ),
  );
  $items['examples/theming_example/theming_example_list_page'] = array(
    'title' => 'Theming a list',
    'page callback' => 'theming_example_list_page',
    'access arguments' => array(
      'access content',
    ),
    'weight' => 1,
  );
  $items['examples/theming_example/theming_example_select_form'] = array(
    'title' => 'Theming a form (select form)',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'theming_example_select_form',
    ),
    'access arguments' => array(
      'access content',
    ),
    'weight' => 2,
  );
  $items['examples/theming_example/theming_example_text_form'] = array(
    'title' => 'Theming a form (text form)',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'theming_example_text_form',
    ),
    'access arguments' => array(
      'access content',
    ),
    'weight' => 3,
  );
  return $items;
}

/**
 * Implements hook_theme().
 *
 * Defines the theming capabilities provided by this module.
 */
function theming_example_theme($existing, $type, $theme, $path) {
  return array(
    'theming_example_content_array' => array(
      // We use 'render element' when the item to be passed is a self-describing
      // render array (it will have #theme_wrappers)
      'render element' => 'element',
    ),
    'theming_example_list' => array(
      // We use 'variables' when the item to be passed is an array whose
      // structure must be described here.
      'variables' => array(
        'title' => NULL,
        'items' => NULL,
      ),
    ),
    'theming_example_select_form' => array(
      'render element' => 'form',
    ),
    'theming_example_text_form' => array(
      'render element' => 'form',
      // In this one the rendering will be done by a template file
      // (theming-example-text-form.tpl.php) instead of being rendered by a
      // function. Note the use of dashes to separate words in place of
      // underscores. The template file's extension is also left out so that
      // it may be determined automatically depending on the template engine
      // the site is using.
      'template' => 'theming-example-text-form',
    ),
  );
}

/**
 * Initial landing page explaining the use of the module.
 *
 * We create a render array and specify the theme to be used through the use
 * of #theme_wrappers. With all output, we aim to leave the content as a
 * render array just as long as possible, so that other modules (or the theme)
 * can alter it.
 *
 * @see render_example.module
 * @see form_example_elements.inc
 */
function theming_example_page() {
  $content[]['#markup'] = t('Some examples of pages and forms that are run through theme functions.');
  $content[]['#markup'] = l(t('Simple page with a list'), 'examples/theming_example/theming_example_list_page');
  $content[]['#markup'] = l(t('Simple form 1'), 'examples/theming_example/theming_example_select_form');
  $content[]['#markup'] = l(t('Simple form 2'), 'examples/theming_example/theming_example_text_form');
  $content['#theme_wrappers'] = array(
    'theming_example_content_array',
  );
  return $content;
}

/**
 * The list page callback.
 *
 * An example page where the output is supplied as an array which is themed
 * into a list and styled with css.
 *
 * In this case we'll use the core-provided theme_item_list as a #theme_wrapper.
 * Any theme need only override theme_item_list to change the behavior.
 */
function theming_example_list_page() {
  $items = array(
    t('First item'),
    t('Second item'),
    t('Third item'),
    t('Fourth item'),
  );

  // First we'll create a render array that simply uses theme_item_list.
  $title = t("A list returned to be rendered using theme('item_list')");
  $build['render_version'] = array(
    // We use #theme here instead of #theme_wrappers because theme_item_list()
    // is the classic type of theme function that does not just assume a
    // render array, but instead has its own properties (#type, #title, #items).
    '#theme' => 'item_list',
    // '#type' => 'ul',  // The default type is 'ul'
    // We can easily make sure that a css or js file is present using #attached.
    '#attached' => array(
      'css' => array(
        drupal_get_path('module', 'theming_example') . '/theming_example.css',
      ),
    ),
    '#title' => $title,
    '#items' => $items,
    '#attributes' => array(
      'class' => array(
        'render-version-list',
      ),
    ),
  );

  // Now we'll create a render array which uses our own list formatter,
  // theme('theming_example_list').
  $title = t("The same list rendered by theme('theming_example_list')");
  $build['our_theme_function'] = array(
    '#theme' => 'theming_example_list',
    '#attached' => array(
      'css' => array(
        drupal_get_path('module', 'theming_example') . '/theming_example.css',
      ),
    ),
    '#title' => $title,
    '#items' => $items,
  );
  return $build;
}

/**
 * A simple form that displays a select box and submit button.
 *
 * This form will be be themed by the 'theming_example_select_form' theme
 * handler.
 */
function theming_example_select_form($form, &$form_state) {
  $options = array(
    'newest_first' => t('Newest first'),
    'newest_last' => t('Newest last'),
    'edited_first' => t('Edited first'),
    'edited_last' => t('Edited last'),
    'by_name' => t('By name'),
  );
  $form['choice'] = array(
    '#type' => 'select',
    '#options' => $options,
    '#title' => t('Choose which ordering you want'),
  );
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Go'),
  );
  return $form;
}

/**
 * Submit handler for the select form.
 *
 * @param array $form
 *   Form API form array.
 * @param array $form_state
 *   Form API form state array.
 */
function theming_example_select_form_submit($form, &$form_state) {
  drupal_set_message(t('You chose %input', array(
    '%input' => $form_state['values']['choice'],
  )));
}

/**
 * A simple form that displays a textfield and submit button.
 *
 * This form will be rendered by theme('form') (theme_form() by default)
 * because we do not provide a theme function for it here.
 */
function theming_example_text_form($form, &$form_state) {
  $form['text'] = array(
    '#type' => 'textfield',
    '#title' => t('Please input something!'),
    '#required' => TRUE,
  );
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Go'),
  );
  return $form;
}

/**
 * Submit handler for the text form.
 *
 * @param array $form
 *   Form API form array.
 * @param array $form_state
 *   Form API form state array.
 */
function theming_example_text_form_submit($form, &$form_state) {
  drupal_set_message(t('You entered %input', array(
    '%input' => $form_state['values']['text'],
  )));
}

/**
 * Theme a simple content array.
 *
 * This theme function uses the newer recommended format where a single
 * render array is provided to the theme function.
 */
function theme_theming_example_content_array($variables) {
  $element = $variables['element'];
  $output = '';
  foreach (element_children($element) as $count) {
    if (!$count) {

      // The first paragraph is bolded.
      $output .= '<p><strong>' . $element[$count]['#children'] . '</strong></p>';
    }
    else {

      // Following paragraphs are just output as routine paragraphs.
      $output .= '<p>' . $element[$count]['#children'] . '</p>';
    }
  }
  return $output;
}

/**
 * Theming a simple list.
 *
 * This is just a simple wrapper around theme('item_list') but it's worth
 * showing how a custom theme function can be implemented.
 *
 * @see theme_item_list()
 */
function theme_theming_example_list($variables) {
  $title = $variables['title'];
  $items = $variables['items'];

  // Add the title to the list theme and
  // state the list type. This defaults to 'ul'.
  // Add a css class so that you can modify the list styling.
  // We'll just call theme('item_list') to render.
  $variables = array(
    'items' => $items,
    'title' => $title,
    'type' => 'ol',
    'attributes' => array(
      'class' => 'theming-example-list',
    ),
  );
  $output = theme('item_list', $variables);
  return $output;
}

/**
 * Theming a simple form.
 *
 * Since our form is named theming_example_select_form(), the default
 * #theme function applied to is will be 'theming_example_select_form'
 * if it exists. The form could also have specified a different
 * #theme.
 *
 * Here we collect the title, theme it manually and
 * empty the form title. We also wrap the form in a div.
 */
function theme_theming_example_select_form($variables) {
  $form = $variables['form'];
  $title = $form['choice']['#title'];
  $form['choice']['#title'] = '';
  $output = '<strong>' . $title . '</strong>';
  $form['choice']['#prefix'] = '<div class="container-inline">';
  $form['submit']['#suffix'] = '</div>';
  $output .= drupal_render_children($form);
  return $output;
}

/**
 * Implements template_preprocess().
 *
 * We prepare variables for use inside the theming-example-text-form.tpl.php
 * template file.
 *
 * In this example, we create a couple new variables, 'text_form' and
 * 'text_form_content', that clean up the form output.  Drupal will turn the
 * array keys in the $variables array into variables for use in the template.
 *
 * So $variables['text_form'] becomes available as $text_form in the template.
 *
 * @see theming-example-text-form.tpl.php
 */
function template_preprocess_theming_example_text_form(&$variables) {
  $variables['text_form_content'] = array();
  $text_form_hidden = array();

  // Each form element is rendered and saved as a key in $text_form_content, to
  // give the themer the power to print each element independently in the
  // template file.  Hidden form elements have no value in the theme, so they
  // are grouped into a single element.
  foreach (element_children($variables['form']) as $key) {
    $type = $variables['form'][$key]['#type'];
    if ($type == 'hidden' || $type == 'token') {
      $text_form_hidden[] = drupal_render($variables['form'][$key]);
    }
    else {
      $variables['text_form_content'][$key] = drupal_render($variables['form'][$key]);
    }
  }
  $variables['text_form_content']['hidden'] = implode($text_form_hidden);

  // The entire form is then saved in the $text_form variable, to make it easy
  // for the themer to print the whole form.
  $variables['text_form'] = implode($variables['text_form_content']);
}

/**
 * @} End of "defgroup theming_example".
 */

Functions

Namesort descending Description
template_preprocess_theming_example_text_form Implements template_preprocess().
theme_theming_example_content_array Theme a simple content array.
theme_theming_example_list Theming a simple list.
theme_theming_example_select_form Theming a simple form.
theming_example_list_page The list page callback.
theming_example_menu Implements hook_menu().
theming_example_page Initial landing page explaining the use of the module.
theming_example_select_form A simple form that displays a select box and submit button.
theming_example_select_form_submit Submit handler for the select form.
theming_example_text_form A simple form that displays a textfield and submit button.
theming_example_text_form_submit Submit handler for the text form.
theming_example_theme Implements hook_theme().