Download & Extend

Regression: There is no (resonable) way to programmatically render a block

Project:Drupal core
Version:8.x-dev
Component:block.module
Category:bug report
Priority:normal
Assigned:Unassigned
Status:active
Issue tags:needs backport to D7

Issue Summary

In D6 you could easily render a block by doing this:

<?php
  $block
= module_invoke($module, 'block' ,$delta);
 
$output = theme('block', $block);
?>

In D7, module_invoke($module, 'block' ,$delta); returns a non-renderable array and there is no easy way to convert that array into something that drupal_render() can handle correctly. The only way to do this is to take the result of the module_invoke(...) and manually rebuild that array into a renderable array using bits and pieces of code form _block_render_blocks() The closest I have come to getting this to work is:

<?php
    $array
= module_invoke('views', 'block_view', $display);
   
// == array('content' => '...', 'subject' => '...')
   
$block['content'] =$array['content'];
   
$block['#block'] = new StdClass();
   
$block['#block']->subject = array('subject');
   
$block['#block']->region = '';
   
$block['#block']->module = 'views';
   
$block['#block']->delta $display;
   
$block['#theme_wrappers'][] = 'block';
   
$output .= drupal_render($block);
?>

...although even this still doesn't work (trying to figure out why.

All this said, I might be just be missing something because I'm still learning about renderable arrays so please feel free to set me straight and downgrade/close this issue, but if there is no good way to do this, then it is a regression from D6 and therefore critical.

Comments

#1

Category:bug report» support request
Priority:critical» major

I'm pretty sure you will figure it out :)

#2

Category:support request» bug report

Damein ... I've been digging through this since yesterday afternoon, and I'm convinced there is no way to actually render a block without completely building a renderable array from scratch. If that's true, wouldn't this be considered a regression and therefore a bug?

If you have a suggestion as to what I may be missing, I'm all ears...

#3

Category:bug report» support request

@bleen18: the block module provides no API whatsoever to render a single block. You are on your own here. That said, it shouldn't be that hard.

<?php
$block
= block_load($module, $delta);
$output = drupal_render(_block_get_renderable_array(_block_render_blocks(array($blocks))));
?>

#4

Category:support request» bug report
Priority:major» normal

#5

Category:bug report» support request

Wow ... that's a bit round-about, but it certainly works. Thanks Damien

#6

Does this require an update of the documentation in the module_invoke api for D7?
http://api.drupal.org/api/drupal/includes--module.inc/function/module_in...

#7

#3:
Little typo:
This one works and renders block 5:

<?php
$block
= block_load('block', '5');
$output = drupal_render(_block_get_renderable_array(_block_render_blocks(array($block))));
print
$output;
?>

#8

It would be nice to get a single function to do this common task in Drupal.

Views for one for rendering views, why not block module?

#9

Is it safe to use _block_get_renderable_array() and _block_render_blocks() ?

Aren't these private functions? In researching this issue I have seen countless threads of people struggling with this change in D7...

  • either having to use the module_invoke method which gets the guts of a block but doesn't actually render as a block with contextual links and block theme wrapper markup.
  • or trying to hand build a renderable array for each block (cumbersome at best)
  • or using the method in this thread that relies on private functions?

Guidance on this is much appreciated.

#10

Here's a stab at a simple helper function, based on the comments above, that would be nice to have in the D7 blocks module. We're finding something similar to be useful in a current D7 project:

/**
* Gets the rendered or render-ready contents of a block.
*
* @param string $module
*   The machine name of the module that provides the block.
* @param mixed $delta
*   The delta of the desired block.
* @param bool $render
*   Whether or not to run the block through render(). Defaults to TRUE.
*   Set this argument to FALSE if you wish to modify the render-ready block
*   data before passing to render().
* @return mixed
*   If $render is TRUE, the string representing the rendered block contents.
*   If $render is FALSE, the render-ready block data array.
* @see http://drupal.org/node/957038
*/
function block_embed_block($module, $delta, $render = TRUE) {
  $block = ($render) ? '' : array();
 
  $block_info = block_load($module, $delta);
  if ($block_info->bid) {
    $block = _block_get_renderable_array(_block_render_blocks(array($block_info)));   
    if ($render) {
      $block = render($block);
    }   
  }

  return $block;
}

#11

I'd like this integrated in to the block.module as well. Would make a lot of peoples lives easier.

#12

Version:7.x-dev» 8.x-dev

bdurbin: can you submit your function as a patch? We need to fix this for D8 before dries/webchick would consider adding it to D7

#13

Use print render() to render a block from module_invoke().

for example:

<?php
$block
= module_invoke('views', 'block_view', 'rotation_image-block');
print
render($block);
?>

#14

clock: its been a while since my original post, but as I recall your suggestion didnt work ... hence the problem

#15

Possible this has been fixed through a related issue then, as this code is currently working on 7.2

#16

@clock:
your solution doesn't seem to work for me. Not even in Drupal 7.4

#17

This seems to work fine in D7 and does not call any private functions.

<?php
function MODULE_render_block($module, $delta) {
 
$block = module_invoke($module, 'block_view', $delta);
 
$block['module'] = $module;
 
$block['delta'] = $delta;
 
$vars = array('elements' => array('#block' => (object) $block, '#children' => render($block['content'])));
  return
theme('block', $vars);
}
?>

#18

<?php
//to show Block 26 in Drupal 7
$block = module_invoke('block', 'block_view', '26');
print
$block['content'];
?>

See also: http://www.werockyourweb.com/drupal-block-in-node

I think this issue can be closed now!

#19

Version:8.x-dev» 7.x-dev
Category:support request» bug report
Status:active» closed (fixed)

#20

see also: http://drupal.org/node/360605 in case that 'strict warning'-errors are shown when applying #18 (are only shown when in Configuration / Logging and errors the option 'all messages' is selected)

#21

Version:7.x-dev» 8.x-dev
Status:closed (fixed)» active

Nikdilis: #18 does not work. It returns a $block array with no content in 'subject' or 'content'. As well as throwing this error:

Notice: Trying to get property of non-object in block_block_view() (line 245 of /..../modules/block/block.module).

#22

After further testing in Drupal 7.5 I agree that there is no (reasonable) way to programmatically render a block with module_invoke. See also: http://drupal.org/node/126070 - module_invoke('block', 'view', ...) doesn't return subject. This issue is from March 8, 2007!!!

However, in Drupal 7.5 the following works:

<?php
//to show Block '15' (Custom Block) without title:
$block = module_invoke('block', 'block_view', '15');
//to show the title: ???????
//   See: <a href="http://drupal.org/node/126070" title="http://drupal.org/node/126070" rel="nofollow">http://drupal.org/node/126070</a> - module_invoke('block', 'view', ...) doesn't return subject
//to show the content of the block - no render!:
print $block['content'];

//--------------------------------------------------------------------------

//to show Block 'recent blog posts' - see also: http://drupal.org/node/957038#comment-4595150
$block = module_invoke('blog', 'block_view', 'recent');
//to show the title of the block:
print $block['subject'];
//to show the content of the block - render must be used:
print render($block['content']);
?>

#23

Something along the lines of #10 looks good (at least as a first step for D8), and is a good candidate to backport to D7.

On a quick glance, it seems like it takes care of all the things that need to be (title vs subject, making sure that drupal_alter() gets called) in order to render the block properly.

But render() should be replaced with drupal_render().... or possibly removed from this function entirely? (There could be separate functions for getting the renderable array and rendering it rather than the $render parameter used here, or just assume that once you have a renderable array you don't even need another helper function at that point, because calling drupal_render() explicitly when you want to render something is pretty common).