Last updated August 26, 2009. Created on August 18, 2005.
Edited by ronald_istos, coderintherye, joachim, add1sun. Log in to edit this page.

As of Drupal 4.7, themes can implement any number of regions for rendering blocks and other content into.
Note that as of Drupal 6.x templates now have .info files where this information is stored. If you are using Drupal 6.x, you should refer to the documentation at http://drupal.org/node/171224.

If you take a look at the 'blocks' administration page in Drupal, you will see that regions are essentially containers to which you can add those blocks. You can also add other non-block content to a region using PHP. An example of a region is your sidebar.

These regions can be assigned to either the whole page or any other themed elements, including in nodes or comments.

The PHPTemplate engine defines five default regions: left, right, content, header, and footer. To implement these regions, themes need only include $sidebar_left, $sidebar_right, $content, $header, and $footer_message variables in their page.tpl.php files, e.g., <?php print $header; ?>.

How to define custom regions

If you want to have your own set of regions for a theme, you do this by defining a _regions() hook. In this case, your custom regions will override those defined by default in PHPTemplate.

If the theme doesn't have a template.php file in its directory, create one; otherwise use the existing template.php file. In either case, add a mytheme_regions() function to define your regions. Each region needs to have a name (a string with no spaces) and a description (the text that will show up in, for example, the block configuration pages). The following would define all the standard PHPTemplate regions except the left sidebar and, in addition, two new regions for a theme called "mytheme".

<?php
function mytheme_regions() {
  return array(
   
'right' => t('right sidebar'),
   
'content' => t('content'),
   
'header' => t('header'),
   
'footer' => t('footer'),
   
'floater' => t('floater'),
   
'inline1' => t('inline 1')
  );
}
?>

Note: Regarding the name of the function:

  • use the name of your theme instead of mytheme_regions(), eg: bluemarine_regions()
  • Don't use a hyphen in the name of a region; an underscore is OK.
  • Also, your theme name is your base theme name not the name of your style.css directory (if you are using one). For example, box_cleanslate overrides the style.css file of the box_grey theme; therefore you should name your function box_grey_regions.

How to write the theme's region variables to the page.

If you're assigning your region to page.tpl.php, you don't need to worry about creating a variable for your region and assigning content to it; PHPTemplate handles this automatically. All you need to do is write the variables to the page, by editing your theme's page.tpl.php file. For each new region you've defined, include in page.tpl.php a print call. For the 'floater' region defined above, this would look like:

<?php  print $floater;?>.

Of course, you'll probably want to use HTML, CSS, and possibly PHP (e.g., if tests) to get your new regions looking how you want them.

Inline regions: how to assign regions to nodes, comments, etc.

By default, all defined regions are passed to page.tpl.php. But with an extra step you can also choose to make specific regions available to any other template file: node.tpl.php, comment.tpl.php, etc. Here's how.

In the same template.php file as you defined the regions in, define a function _phptemplate_variables() (or use an existing one if there's one already defined). What you'll do here is assign region content to a specific theme call. When _phptemplate_variables() is called, it receives the theme argument as the $hook variable, for instance 'node'. So we can assign new regions to the node template like this:

<?php
function _phptemplate_variables($hook, $variables) {
 
// Load the node region only if we're not in a teaser view.
 
if ($hook == 'node' && !$vars['teaser']) {
   
// Load region content assigned via blocks.
   
foreach (array('inline1') as $region) {
     
$variables[$region] = theme('blocks', $region);
    }
  }
  return
$variables;
}
?>

Note that we're testing to make sure we aren't in a 'teaser' view, so that the region will be loaded only in a full node view.

Now, in your node template, you can include the region variable in your output. Here's the standard phptemplate node.tpl.php with an 'inline1' region added:

  <div class="node<?php if ($sticky) { print " sticky"; } ?><?php if (!$status) { print " node-unpublished"; } ?>">
    <?php if ($picture) {
      print
$picture;
    }
?>

    <?php if ($page == 0) { ?><h2 class="title"><a href="<?php print $node_url?>"><?php print $title?></a></h2><?php }; ?>
    <span class="submitted"><?php print $submitted?></span>
    <span class="taxonomy"><?php print $terms?></span>
    <div class="content"><div class="floatleft"><?php print $inline1?></div><?php print $content?></div>
    <?php if ($links) { ?><div class="links">&raquo; <?php print $links?></div><?php }; ?>
  </div>

Likely you'll want to add style declarations to the region, which you do as usual via the theme's style.css file. Here, for example, we could make the inline region float left:

div.floatleft {
  float: left;
}

Because a node's variables are passed to other node templates, you can also do your customized display in node-type templates.

And this same basic approach can be applied to any other themed area. This example assigns specific regions to nodes and comments:

<?php
function _phptemplate_variables($hook, $variables) {
 
// Load region content assigned via blocks.
  // Load the node region only if we're not in a teaser view.
 
if ($hook == 'node' && !$variables['teaser']) {
    foreach (array(
'node1', 'node2') as $region) {
     
$variables[$region] = theme('blocks', $region);
    }
  }
  else if (
$hook == 'commment') {
    foreach (array(
'comment1', 'comment2') as $region) {
     
$variables[$region] = theme('blocks', $region);
    }
  }
  return
$variables;
}
?>

Regions without blocks

If you want to assign content to regions but not have it output via blocks, do so with the drupal_set_content() function. This allows you to bypass the regular block system. Try something like this:

Set content to regions
In your module code, set content to the regions. You can use region names that aren't listed in your themename_regions() array. That way, the regions won't be available for blocks, and so won't end up with block content in them. Say your regions are called 'region1' and 'region2'. In your module code, do this:

<?php
$output
= 'whatever';
drupal_set_content('region1', $output);
?>

In a template.php file, set a variable and assign the region content to it.

<?php
function _phptemplate_variables($hook, $variables) {
 
// Load region content assigned via drupal_set_content().
 
if ($hook == 'page') {
    foreach (array(
'region1', 'region2') as $region) {
     
$variables[$region] = drupal_get_content($region);
    }
  }
  return
$variables;
}
?>

Output your content
In your page.tpl.php file, output the regions where you want them:

<?php
 
print $region1;
?>

Looking for support? Visit the Drupal.org forums, or join #drupal-support in IRC.