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;
}
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
Comments
The goal of this tip is to branch logic so if a top-level condition isn't met then Drupal/PHP should get out of that function as fast as possible, reducing the computation of that function (until actually necessary).
In the blog post example, by wrapping all the block logic in an IF statement the PHP engine doesn't have to do any other function calls or retain memory for temp variables (like the array_merge).
Another boost is when using APC (opcode cache) then any PHP code added will be pushed into memory, thus eliminating the need for the PHP server to keep opening/loading include files.
Application logic should always be this way: only run what's needed.
That depends on your situation. If you don't have such a region on admin paths this can give you some performance gain.
Hello,
Thanks for posting these tips.
I'm a little bit confused by your statement of whether or not an implementation of hook_block can achieve a performance gain by not building blocks from a certain region. Can you please clarify?
I'm using code like this:
<?phpfunction theme_blocks($region) {
//Return empty if on select page
$matched_path = preg_match('/(admin)/', $_GET['q']);
if ($matched_path && $region == 'right') {
return;
}
...
$output .= drupal_get_content($region);
return $output;
}
?>
I believe your article states that using this method will achieve the desired performance gain, is this correct? Thanks!
Hi - thanks for your great article :)
Post new comment