Block visibility, block rendering and performance in Drupal 5

In Drupal 5 you can control the visibility of each block by specifying a rule (allow all except ..., allow only ..., or use user submitted PHP code to evaluate the pattern) and a pattern on the URL. However this does not only control the visibility (show or hide) of the block, but controls whether the block is rendered (ie. the code of the block executed) at all or not. Of course this means a huge difference in performance.

You'll find in various PHPTemplate themes that some regions are shown or hidden based on a few conditions. But at the time the PHPTemplate engine gets to the various page/block/node/etc. templates, these regions were already rendered and the code of all the blocks in them were already executed. This execution takes place in the block_list Drupal function, right after the evaluation of the various visibility factors. Unfortunately there's no hook for themes to inject their own logic into visibility rules, so the only place to do this remains the blocks' visibility configuration which you can do only in Administration/Blocks. A hook would be nice so one can enable or disable blocks (or even regions) via generic rules. Eg. if I wanted to have some region visible only on node pages, then I've to put the "node/*" pattern in every block that I put in that region.

Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Region hiding

I thought I could cheat the system to not render a region by not adding the region name to the region list in the theme_regions() hook implementation of my theme's template.php. Unfortunately this does not work either. Sad I've now taken a closer look at the block_list function and found that it first queries all the blocks in the current theme and renders them (unless the block's visibility rules prohibit this of course) and fills up an internal static array with the rendered block contents. In the end (when all blocks are ready) it checks whether there're any blocks for the requested region (parameter of the block_list function) and returns them to the caller.

It means block_list runs all the blocks regardless whether they'll be needed (aka. requested) or not. This is a huge performance killer imho. Of course you can avoid all this by adding block visibility rules to all blocks (a quite tedious job since the block administration form can get awkardly slow with a hundred blocks or so). Unfortunately neither the region, nor the block name are available to the block visibilty code you might add, so if you want your visibility rule to depend on the region of the block (eg. you want to hide a region alltogether under certain circumstances), then you've to hard-code the region name into the block visibility code. Sad

Re: region hiding

I've finally figured it out how to make it happen (region hiding) without messing around in block.module (patching core modules is never a really good idea). We're allowed to theme the theme_blocks function, which used to call block_list. We simply make a copy of theme_blocks (replacing "theme_" with our theme's name) and block_list and put them into our template.php file.

In our copy of block_list we've to add the region filtering to the query that gets the list of blocks. Replace this part:
  if (!count($blocks)) {
    $rids = array_keys($user->roles);
    $placeholders = implode(',', array_fill(0, count($rids), '%d'));
    $result = db_query("SELECT DISTINCT b.* FROM {blocks} b LEFT JOIN {blocks_roles} r ON b.module = r.module AND b.delta = r.delta WHERE b.theme = '%s' AND b.status = 1 AND (r.rid IN ($placeholders) OR r.rid IS NULL) ORDER BY b.region, b.weight, b.module", array_merge(array($theme_key), $rids));
    (...)
  }

With this:
  if (!count($blocks)) {
    $regionlist = array_keys(system_region_list($theme_key));
    if (isset($regionlist) && count($regionlist) > 0) {
      $regionsholder = "'" . implode("','", $regionlist) . "'";
      $rids = array_keys($user->roles);
      $placeholders = implode(',', array_fill(0, count($rids), '%d'));
      $result = db_query("SELECT DISTINCT b.* FROM {blocks} b LEFT JOIN {blocks_roles} r ON b.module = r.module AND b.delta = r.delta WHERE b.theme = '%s' AND b.status = 1 AND b.region IN ($regionsholder) AND (r.rid IN ($placeholders) OR r.rid IS NULL) ORDER BY b.region, b.weight, b.module", array_merge(array($theme_key), $rids));
      (...)
    }
  }

PS: this works for Drupal 5.7. In Drupal 6 regions are handled in a completely different way.

Region Assign

I've implemented a module which evaluates regexp against URI, Region Assign. Basically, you just have to choose: theme, region and pattern. Example: ^/node.*$, assigned to right region in garland theme, so will display right region only in node pages. I also plan use php patterns, to let evaluate arg(x).

If interested please report your feedback to issue queue: http://drupal.org/project/issues/region_assign

Blessings!

Re: Region Assign

Thanks for the comment. I've implemented something similiar in our project (at my company), but in the template of the site (with hardcoded number of regexps that are matched against the hardcoded regions - the regexps themselves can be modified through the UI though) and not as a reusable module. But I'll remember your module in our next Drupal based project. Smile

Re: Block visibility, block rendering and performance in Drupal5

Very good post. thanks

Thanks

Hi,

Thanks very much for sharing. It's really very helpful. I will try using this trick.

Regards,
Ravi Verma

Joomla

dear ,
Some really helpful information here. I Like of your website design . Did you make this templete yourself or did you get it from any templetes websites? Looks pretty cool for me . I use Joomla but wants something better.

Re: Joomla

I use the default template of Drupal and it's called "Garland". I created this blog primarily for myself (a searchable "knowledge base") and to minimize maintenance efforts, I stick with the Drupal core and added only a very few 3rd party modules. The Garland theme is nice and is well maintained by the Drupal core theme developers.

joomla developer

Hello,

I'm looking for freelance joomla developer or web designer webdesign.

Installing the site and I need someone to add functions to some site.

If you are interested thank you kindly send us an email.

Re: joomla developer

Sorry. I'm not too much into Joomla. I'm more of a Drupal fan.

Drupal5 is so amazing

Drupal5 is so amazing