vkareh.net

Professional javascript and node.js engineering for functional websites.

Render Arrays

February 2, 2011

It seems that documentation on renderable arrays for Drupal 7 is lacking.

I was working on upgrading the Multistep module to Drupal 7, and turns out that the navigation/progress-bar block was still returning an HTML string. Unacceptable. I need to fix that by returning Render Arrays instead.

After searching for a while, the best I came up with was Render Arrays in Drupal 7 and the Examples for Developers module, by rfay. Digging through the code, I found some definite gems, but still had to figure most of my way around for creating my own theming function that handles Render Arrays.

The trick to understanding Render Arrays is to think about the Form API: structured arrays that define the elements and behavior of the final renderable product. Armed with this information, I proceeded to run some preliminary testing.

This is the first one:

/**
 * Implements of hook_block_view().
 */
function example_block_view($delta = '') {
  return array(
    'subject' => t('My block'),
    'content' => array(
      '#markup' => t('Hello renderer!'),
    ),
  );
}
Render Arrays

You'll notice that this is no different from any other $form element around. Now, there are other properties that I played with, mainly #theme. My next test uses #theme to display a list of items:

/**
 * Implements of hook_block_view().
 */
function example_block_view($delta = '') {
  return array(
    'subject' => t('My block'),
    'content' => array(
      '#theme' => 'item_list',
      '#items' => array('Item 1', 'Item 2', 'Item 3'),
    ),
  );
}
Render Arrays

It actually took me a while to figure out that I wanted to pass the list of items inside the #items property. From the theme_item_list() API, you can see that it takes one parameter: $variable. This is an array that contains items, title, type, attributes. By that same logic, I should be able to pass any of those values as a property of the Render Array:

/**
 * Implements of hook_block_view().
 */
function example_block_view($delta = '') {
  return array(
    'subject' => t('My block'),
    'content' => array(
      '#theme' => 'item_list',
      '#items' => array('Item 1', 'Item 2', 'Item 3'),
      '#title' => t('My item list'),
      '#type' => 'ol',
    ),
  );
}
Render Arrays

Success! I am now confident that I can pretty much return renderable arrays for most implementations of theme_HOOK() (those theme functions registered through hook_theme()).

What about custom theme functions, though? That's what I really wanted for my module: returning Render Arrays for my custom theme functions. For that, I ended up using two different ways: render elements and variables.

First, you have to create your theme functions. The ones that will return the actual HTML.

/**
 * Displays a list of links.
 */
function theme_example_link_list($variables = array()) {
  $links = array();
  foreach ($variables['links']['#children'] as $link) {
    $links[] = l($link['label'], $link['url']);
  }
  return theme('item_list', array('items' => $links));
}

/**
 * Displays a progress bar.
 */
function theme_example_progress_bar($variables = array()) {
  return '<div id="example-progress-bar">' . $variables['progress'] . '%</div>';
}

Then, of course, you have to register your theme functions by implementing hook_theme().

/**
 * Implements hook_theme().
 */
function example_theme() {
  return array(
    'example_link_list' => array(
      'render element' => 'links',
    ),
    'example_progress_bar' => array(
      'variables' => array(
        'progress' => NULL,
      ),
    ),
  );
}

Lastly, you return the corresponding Render Array in your hook_block_view() implementation:

/**
 * Implements of hook_block_view().
 */
function example_block_view($delta = '') {
  return array(
    'subject' => t('Test menu'),
    'content' => array(
      'some_text' => array(
        '#markup' => t('This is the block body'),
      ),
      'just_a_list_of_links' => array(
        '#theme' => 'example_link_list',
        '#children' => array(
          0 => array(
            'label' => t('Step 1'),
            'url' => 'http://www.example.com/1',
          ),
          1 => array(
            'label' => t('Step 2'),
            'url' => 'http://www.example.com/2',
          ),
        ),
      ),
      'nice_looking_progress_bar' => array(
        '#theme' => 'example_progress_bar',
        '#progress' => $progress,
      ),
    ),
  );
}
Render Arrays

The differences between variables and render element are best explained in the hook_theme() documentation, but the basics are:

  • variable is an array of variable names that you will pass the theme function.
  • render element is a the name of the structured array that will hold all the renderable information.
This should be sufficient to get most developers started on returning Render Arrays. For more information about my actual implementation in the Multistep module, browse its source code.