Friday, 25 May 2012

Drupal 7 - Render a block in a template file

I can see how Drupal's region system works well for content that flows vertically e.g. sidebars, and maybe even the main content area, but I've always struggled with positioning blocks in the header and footer. This is because for me at least, these areas have lots of blocks of content, in a more complex arrangement (perhaps separated into multiple columns etc). I thought about adding custom regions, maybe one for each column of blocks i wanted to display, but this seemed overly rigid, and I don't see the advantage of doing this over just manually rendering the blocks in my page.tpl.php for example (I think it would be slower to login to the website and mess around with the block admin GUI than to just make a tweak to my page.tpl.php).

So I had to search around for a good way to manually render blocks in a template file, and there are lots of sub-optimal solutions floating around the internet, so when I found a good solution, I thought I would document it here.


Solution

Chuck the following function at the bottom of your theme's template.php file:

/**
 * Custom function to render a block so I can manually position it in the markup
 */
function block_render($module, $block_id) {
  $block = block_load($module, $block_id);
  $block_content = _block_render_blocks(array($block));
  $build = _block_get_renderable_array($block_content);
  $block_rendered = drupal_render($build);
  return $block_rendered;
}

Next, use a preprocess function to set some variables for your tpl file e.g. in your THEME_preprocess_page() function, add something like this for each block you want to render:

$variables['commerce_cart_block'] = block_render('commerce_cart', 'cart');

Where the first argument is the module that produced the block, and the second is the block name - you can get these from going to the block admin page, and hovering the "configure" link e.g. for the Commerce Cart example above, the URL was http://example.com/admin/structure/block/manage/commerce_cart/cart/configure.

Now you have a $commerce_cart_block variable in your page.tpl.php to print wherever you want! I should think this would work for node.tpl.php as well (you would have to set the variables in your THEME_preprocess_node() function instead).

print $commerce_cart_block;


References
http://api.drupal.org/api/drupal/includes%21module.inc/function/module_invoke/7#comment-15709