Using hook_page_alter to move node render items into blocks I have a gallery page where I want to move the thumbnails into the sidebar-first region as a block. I'm trying to get a handle on using the code in Drupal 7 so am attempting to do this via hook_page_alter.

In my template.php file I currently have...

/**
* Implements hook_page_alter()
*/
function MYTHEME_page_alter(&amp;$page) {
  $node = menu_get_object();
  if($node &amp;&amp; $node-&gt;type == "imagegallery") {
    // edit only imagegallery nodes
    debug($page['content']['system_main']['nodes'][$node-&gt;nid]['#node']-&gt;field_image);
    $page['sidebar_first']['thumbs']['content'] = $page['content']['system_main']['nodes'][$node-&gt;nid]['#node']-&gt;field_image;
    unset($page['content']['system_main']['nodes'][$node-&gt;nid]['#node']-&gt;field_image);
  }
}


Debug is showing the array for the field_image from the language (['und']) and each of the thumbnails but nothing is rendered out into the sidebar-first region and the field_image is not unset from the node. I had also tried the hide() function unsuccessfully.

What is the correct way to move render objects from the main content to a region?
Well this ended up being a real pain in the bum - but ultimately got it solved. There may be a cleaner way of shifting the content so please comment if it could be done better.

I'll start by answering the question, then I'll try to go through what I think was going on under the hood to exacerbate the problem(s).

The answer is to use hook_page_build() instead of hook_page_alter(). hook_page_build() doesn't trigger from template.php so you need to build a custom module.

MYMODULE.module simply contains:

&lt;?php
/**
 * Implements hook_page_build()
 */
function MYMODULE_page_build(&amp;$page) {
  $node = menu_get_object();
  if($node &amp;&amp; $node-&gt;type == "imagegallery") {
    // edit only imagegallery nodes
    $page['sidebar_first']['thumbs'] = array(
      'content' =&gt; $page['content']['system_main']['nodes'][$node-&gt;nid]['field_image'],
      '#prefix' =&gt; '&lt;div class="thumbs"&gt;',
      '#suffix' =&gt; '&lt;/div&gt;',
    );
    unset($page['content']['system_main']['nodes'][$node-&gt;nid]['field_image']);
  }
}


And that's all there is to it.

Now to go through the various 'gotchas!'.

$page['content']['system_main']['nodes'][$node-&gt;nid]['#node']-&gt;field_image is not $page['content']['system_main']['nodes'][$node-&gt;nid]['field_image']! This took a freaking day to find. Using devel_themer I kept on inspecting the node-level elements rather than the block-level elements. No matter what I did ['#node']-&gt;field_image stayed where it was but I think that #node is just a reference of what was generated and isn't even ultimately rendered. Once I found that ['nodes'][$node-&gt;nid]['field_image'] was the render element for the thumbnails it was down-hill from that point. Lesson learned: Even if you find what you think is the actual render element keep checking up the tree.

hook_page_alter() is great if you are ALTERING existing content but not great if you are moving stuff around. By that I mean if you have content in a region and you just want to clean stuff up then fine, use hook_page_alter. But one of the problems I had was that I had no existing content in the sidebar_first region so by moving things across using this hook, the system already thought that sidebar_first was empty. So while it placed the content where the region should have been, it didn't actually render the region itself. This really screwed up my page display. I'm guessing that Drupal builds the page elements during hook_page_build(), then works out what is what as far as the regions it is going to render out, then allows final altering during hook_page_alter() for the absolute last-step tweaking before render() is run. By using hook_page_build() the system then knew that the sidebar_first region was active.

It also took a little while to figure out hook_page_build() didn't trigger from template.php. I should have started with a debug message in there to test that as well.