by October 8, 2009

Drupal Performance Tip: Block Visibility

This is something we hit a lot when doing performance analysis on very slow websites, so I figured I'd issue a public service announcement. :)

It's not uncommon in more complex themes to have many different block regions, and even dynamic regions that will only appear on certain pages or when viewing nodes of certain types. One very common use-case is to have both a page.tpl.php, and a page-front.tpl.php, each of which print out different regions, particularly for ads or promotions:

Block region examples

Defining block regions is super easy; simply add a couple lines in your theme's .info file:

regions[ad_top]        = Ad Top
regions[ad_bottom]     = Ad Bottom
regions[front_sidebar] = Front Sidebar
regions[sidebar_ad]    = Sidebar Ad
regions[content]       = Content
regions[feature_a]     = Feature A
regions[feature_b]     = Feature B
regions[feature_c]     = Feature C
regions[feature_d]     = Feature D

And then in your *.tpl.php file, wherever you want the region to appear, simply print out its machine-readable name:

<?php print $feature_a; ?>

Don't want the blocks in the "Feature A" region to show up in page.tpl.php? No problem! Just don't print the region out there! Done! Right? For many people, their concern about block visibility ends there; they're not showing up, so they move on with their day. However, this can have a profoundly negative performance impact on your site.

The block_list() function has no knowledge of which block regions are printed out on this page. This means that Drupal's default behaviour is to render every single block on your site that's assigned to any region on every single page view, regardless of whether the region's content is actually being visibly printed out or not.

If you're doing a bunch of complex queries in those feature blocks, and you're not hiding the block by one of the following:

  • Setting the block's visibility settings (on the block's configuration form) to not show up on pages that do not have the region it's assigned to printed. For example, setting any blocks assigned to the Feature A region to only show up on the <front> page.
  • Hiding the visibility of the block by some other means; for example, by limiting it to a role using the checkboxes on the block configuration form (or content types in Drupal 7), or installing a contributed module that implements hook_db_rewrite_sql() on the block list.

...then your server is probably melting. :P

Incidentally, setting <front> visibility by hand in each block that should only appear on the front page can be fairly tedious. You might also have a look at the Block Page Visibility module, which allows you to hijack the block visibility settings. It'll prevent them from being set anymore in the UI, but will allow you to establish whatever complex visibility logic you need in code instead.

So remember: don't rely on regions and template files to hide blocks; they do so visually only. Using block visibility settings will ensure that extra processing is not performed on blocks that aren't being printed out in the first place, and keep your server nice and speedy!