Increasingly, themes are utilising multi-column areas for blocks--like the "triptych" regions in the beautiful Bartik theme. However, here I'm providing an alternative to this, where, in some regions, blocks are arranged automatically into columns, dependant on the number of blocks. So, where there are only two blocks to display, Drupal would make each one 50% wide in two columns. If you add another block to that region, they'd be 33% wide across three columns.

One approach might be to style each block to float to the left. All well and good, but if some of those blocks are different sizes, we'll get a very untidy layout, like this (image).

Instead, I'm aiming for nice columns, with the ordering of the blocks running across the columns; block number one, two and three being at the top of each column, and so on. Here's an example of what I mean (image).

So, the HTML we're aiming to produce is as follows:

  <div class="column-one">
    <div class="block">
      Block one.
    </div>
    <div class="block">
      Block four.
    </div>
  </div>
  <div class="column-two">
    <div class="block">
      Block two.
    </div>
    <div class="block">
      Block five.
    </div>
  </div>
  <div class="column-three">
    <div class="block">
      Block three.
    </div>
    <div class="block">
      Block six.
    </div>
  </div>

However, this is going to be a bit tricky. Drupal gives us all the blocks for a block region in one long list. We need to sort them into three columns--exactly like dealing a deck of cards into three tidy piles.

So, in brief, we need a PHP function that will do the following:

  1. Get all the blocks for a region in an array.
  2. Set up three additional arrays: one for each column.
  3. Loop through the array of blocks, dealing each into the next column array.

Furthermore, it would also be nice if we could tell the function the maximum number of columns we want.

The solution? I put this in my template.php file:

// replace "mytheme" with the name of your theme.
function mytheme_block_columns($region, $max_columns=3) {

  if (module_exists('context')) {
    // if the Context Module is being used, we need to collect all of its blocks as well as those set in Drupal's core blocks admin interface.
    $context_blocks = context_get_plugin('reaction', 'block');
    $blocks = $context_blocks->block_list($region);
  }
  else {
    $blocks = block_list($region);
  }

  if ($blocks) {
    $column_pointer = 1; // the column we're currently adding to
    $columns = array();
    foreach ($blocks as $key => $block) { // loop through the blocks
      $columns[$column_pointer] .= theme('block', $block); // in the current column, place a themed block:
      $column_pointer++; // move on to the next column
      if ($column_pointer > $max_columns) $column_pointer = 1; // if we're at the last column, move back to the first
    }
  }

  // to finish off, we need to take our column arrays and surround them with the HTML needed to lay them out effectively:
  if ($columns) { // we don't want to do this if there are no columns (for example, if an empty block region is being displayed on the blocks admin page)
    $column_count = count($columns);
    $output .= "<div class=\"block-columns columns-$column_count clearfix\">\n";
    foreach ($columns as $key => $column) {
      switch ($key) {
        case $column_count: $firstlast = ' last'; break;
        case 1: $firstlast = ' first'; break;
        default: $firstlast = '';
      }
      $output .= "<div class=\"block-column block-column-$key clearfix$firstlast\">" . $column . '</div>';
    }
    $output .= "</div>";
  }

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

}

and I add this to my page.tpl.php file, at the point where I want to display a block region in this way:

<!-- replace "footer" below with the name of your block region -->
<!-- also, as before, replace "mytheme" below with the name of your theme -->
<?php print mytheme_block_columns('footer'); ?>

Hope I got all this across clearly. I'm open to suggestions for improvement--either in the code, or the documentation.

Comments

macrigor’s picture

The script have some minor syntax errors (escape characters are missing in parts).

Other than that this solution is one of the very few on the net that can take on the problem of arranging blocks into columns in a region.
I wasn't able to get it to work with drupal 7 though.

Drupal 7 doesn't use the drupal_get_content() function either.

In the end I am use the the Blocks group module . It's the best solution thus far for me.