blocks

Improve Drupal's performance by not executing block logic on page templates with no regions - Part 2

This is a follow up of an earlier post. You should read this one to understand this one fully: Improve Drupal's performance by not executing block logic on page templates with no regions.

As I told there in the final paragraph, it was possible to generalize this technique to work on multiple templates with a different combination of blocks. This is a general solution to solve this.

As you know, you can have multiple page templates in PHPTemplate by settings $vars['template_file'] in theme_page. We add this variable in _phptemplate_variables for the 'page' hook.

function _phptemplate_variables($hook, $vars) {
  if ($hook == 'page') {
		$vars['template_file'] = phptemplate_get_template();
    return $vars;
  }
  return array();
}

Note that we moved the logic for deciding which page template we use in a seperate function, which implementation is here. This is the only function you need to adjust to your context. The other code you can just copy-paste and reuse in your own templates.

function phptemplate_get_template() {
	static $active_template;
	
	if(isset($active_template)) {
		return $active_template;
	}

	if(drupal_is_front_page()) {
		$active_template = 'page-left';
	} else {
		$active_template = 'page';
	}
	
	return $active_template;
}

We also define a mapping to specify what regions are used on what templates.

function phptemplate_get_template_regions($region) {
	$map = array(
		'page' => array('content', 'left', 'right'),
		'page-left' => array('content', 'left'),
	);
	return $map[$region];
}

As told in the previous article, the core logic of the block was executed on demand of the block_list function. This function was called from the theme_blocks function.

We don't want to run the block_list function on regions that don't appear in our page template, so we put a wrapper function around the core function.

function phptemplate_block_list($region) {
	if(!in_array($region, phptemplate_get_template_regions(phptemplate_get_template()))) {
		return array();
	}
	
	return block_list($region);
}

And now we override theme_blocks to call this function:

function phptemplate_blocks($region) {
  $output = '';

  if ($list = phptemplate_block_list($region)) {
    foreach ($list as $key => $block) {
      // $key == <i>module</i>_<i>delta</i>
      $output .= theme('block', $block);
    }
  }

  // Add any content assigned to this region through drupal_set_content() calls.
  $output .= drupal_get_content($region);

  return $output;
}

And we're done!

To apply this to your own themes, just copy all these functions and change my implementation of phptemplate_get_template and phptemplate_get_template_regions to your situation. If you already have your own _phptemplate_variables, add my logic to yours.

Written on October 12, 2008 at 11:18, tagged as blocks, Drupal, performance, tips

Improve Drupal's performance by not executing block logic on page templates with no regions

Sometimes you have a site with a few different page templates. Most of these templates will have a few regions, but some don't. A few examples are:
- splash pages and intro pages
- webservice/ajax pages where you return json or xml (or some other format)
- pages that don't fall in the normal structure of your site like print pages or "live dashboards" on sport sites

As you may know, even if a region is not displayed in a certain page template (by doing print $sidebar_left), the blocks are constructed behind the scene and all logic is executed. This is really a waste of time and resources.

How can we improve performance here? Well, let me first say that using simple Drupal constructs, you can only use this tip on page templates with absolutely no (= ZERO) regions. Why is that? Because Drupal uses static caching in the block_list function which loads all blocks for all regions on the first call, and only serves the blocks for the requested region from that full batch, which gets cached during the duration of the page request.

Let's see when Drupal performs the block logic. We'll go back in time to see where we can make the best improvement.

All of the core logic of your block, should be handle in the view operation of the hook_block. Let's do a search in the Drupal core code and we'll see that this operation is only called once in the block_list function in the block module.

function block_list($region) {
...
$array = module_invoke($block->module, 'block', 'view', $block->delta);
...
}

Let's now go a bit further back and see where block_list gets called. We're lucky! It gets called only once in the theme_blocks function. And Drupal theme functions are great for customisation without pampering Drupal's code. So let's put some conditional logic in there.

I'll show you a before and after:

Before:

function theme_blocks($region) {
  $output = '';

  if ($list = block_list($region)) {
    foreach ($list as $key => $block) {
      // $key == <i>module</i>_<i>delta</i>
      $output .= theme('block', $block);
    }
  }

  // Add any content assigned to this region through drupal_set_content() calls.
  $output .= drupal_get_content($region);

  return $output;
}

After:

function theme_blocks($region) {
  $output = '';

	if(/*put your condition here like arg(0) != 'splashpage' */) {

  	if ($list = block_list($region)) {
  	  foreach ($list as $key => $block) {
  	    // $key == <i>module</i>_<i>delta</i>
  	    $output .= theme('block', $block);
  	  }
  	}
  	
  	// Add any content assigned to this region through drupal_set_content() calls.
  	$output .= drupal_get_content($region);

	}

  return $output;
}

Advanded usage to get even more performance gain

To be honest, I lied a bit before. It's actually possible to improve this to make it work for pages with regions (but not all of the regions of the site). You can easily copy the block_list function in a module and name it something like my_block_list. You can alter the function so it'll work per region. In your theme_blocks function you just call my_block_list instead of Drupal's block_list.

You can find a description and code of this technique in a follow up article, Improve Drupal's performance by not executing block logic on page templates with no regions - Part 2

Written on September 26, 2008 at 15:52, tagged as blocks, Drupal, performance, tips

About

drupalcoder.com is a blog on all things Drupal in specific and LAMP on OS X in general. It is maintained by Davy Van Den Bremt, a Belgian (Drupal) web developer and designer living in Ghent. The goal of this blog is to log all interesting things that have crossed the writer's path while developing Drupal sites. You can read all about Davy's professional activities on his LinkedIn profile. If you want to get in touch, use the contact form.