Is block weight ignored when setting content in hook_block_list_alter()? I am using hook_block_list_alter and hook_block_view_alter to force caching upon a block provided by nice_menus, which has bad performance when used with my HUGE taxonomy menu. Here is an abstract of my code:

/**
 * Performance hack for nice_menus
 * Force the nice menu blocks to be cached globally.
 * Note that the same menu will be displayed for all users on all pages where the block is enabled.
 */
function mymodule_block_view_alter(&amp;$data, $block) {
  $deltas = variable_get('mymodule_nice_menus_performance_hack_deltas',array());

  if ($block-&gt;module == 'nice_menus' &amp;&amp; in_array($block-&gt;delta,$deltas)) {
    // if we are here, then the block has been rendered. set the cache.
    cache_set('mymodule_nice_menu_'.$block-&gt;delta.'_data', $data, 'cache_block', CACHE_TEMPORARY);
    cache_set('mymodule_nice_menu_'.$block-&gt;delta.'_block', $block, 'cache_block', CACHE_TEMPORARY);
  }
}

function mymodule_block_list_alter(&amp;$blocks) {
  $deltas = variable_get('mymodule_nice_menus_performance_hack_deltas',array());

  foreach($blocks as &amp;$block) {
    if ($block-&gt;module == 'nice_menus' &amp;&amp; in_array($block-&gt;delta,$deltas)) {
      $cached_data = cache_get('mymodule_nice_menu_'.$block-&gt;delta.'_data', 'cache_block');
      $cached_block = cache_get('mymodule_nice_menu_'.$block-&gt;delta.'_block', 'cache_block');
      if (!empty($cached_data) &amp;&amp; !empty($cached_block)) {
        $block = $cached_block-&gt;data;
        $block-&gt;content = $cached_data-&gt;data['content'];
        $block-&gt;subject = $cached_data-&gt;data['subject'];
      } // else just don't set anything, and nice_menus will recreate it! 
    }
  }
  dpm($blocks);
}


Now my problem is, that whenever $block-&gt;content is set, the block's weight is ignored, and it is rendered as the first block in the region, even though $block-&gt;weight was set to the correct value.

What causes this, and how does one enforce the weight?
Symptoms: When the block is not loaded from cache, but from the database, the ordering works fine. When loading from cache, the weight is ignored.

Diagnosis: The block module uses SQL to order the blocks:

function _block_load_blocks() {
  global $theme_key;

  $query = db_select('block', 'b');
  $result = $query
    -&gt;fields('b')
    -&gt;condition('b.theme', $theme_key)
    -&gt;condition('b.status', 1)
    -&gt;orderBy('b.region')
    -&gt;orderBy('b.weight')
    -&gt;orderBy('b.module')
    -&gt;addTag('block_load')
    -&gt;addTag('translatable')
    -&gt;execute();

// ...


After that, it ignores the weight value, and relies on the order of php array keys (order in which foreach iterates) when rendering:

function _block_get_renderable_array($list = array()) {
  $weight = 0;
  $build = array();
  foreach ($list as $key =&gt; $block) {
    $build[$key] = $block-&gt;content;
    unset($block-&gt;content);

// ...

    $build[$key] += array(
      '#block' =&gt; $block,
      '#weight' =&gt; ++$weight, // HERE LIES THE MADNESS!
    );
    $build[$key]['#theme_wrappers'][] ='block';
  }
  $build['#sorted'] = TRUE;
  return $build;
}


Strategy: Either hack the blocks module (DON'T) or find a workaround. I looked through the block.module and found (using lots of dpm()) where the order of array keys are being reversed:

function _block_render_blocks($region_blocks) {

// ...      

  foreach ($region_blocks as $key =&gt; $block) {
    // Render the block content if it has not been created already.
    if (!isset($block-&gt;content)) {
      // Erase the block from the static array - we'll put it back if it has
      // content.
      unset($region_blocks[$key]); // THIS IS WHY THE ORDER OF KEYS CHANGE

// ...

      if (isset($block-&gt;content) &amp;&amp; $block-&gt;content) {

// ...

        $region_blocks["{$block-&gt;module}_{$block-&gt;delta}"] = $block; // THIS IS WHY THE ORDER OF KEYS CHANGE
      }
    }
  }

  return $region_blocks;
}


Workaround: Manually sort the render array in a hook_page_alter(&amp;$page) implementation.

function mymodule_page_alter(&amp;$page) {
  if (!empty($page['sidebar_first']['my_block_1'])) {
    $page['sidebar_first']['my_block_1']['#weight'] = -1; // move it to the top
    $page['sidebar_first']['#sorted'] = FALSE; // indicate that it still needs to be sorted before rendering
  }
}


I only have two blocks in sidebar_first, of which the bottom one is cached. So I only need to lift the other block ('my_block1') above the cached block. A more sophisticated approach will be to query the weights from the block table again.

I'm not sure whether I should consider this to be a bug in the block module. It is a shortcoming, but it's only exposed because of my custom caching hack.