Jump to:
| 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
I'm pretty sure you will figure it out :)
#2
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
@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
#5
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...
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
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.
<?phpfunction 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
#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
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).