27

I'm developing a site using Drupal 8 beta-14. I've created a view block of different terms and now I want to display it using code. How can I display it programatically? I used to do it in Drupal 7 using this code but I'm confused about Drupal 8.

$block = module_invoke('block', 'block_view', '4');
$text_block = render($block['content']);
60

There are two types of blocks, and the method for rendering the two is a bit different:

Content Blocks

Content blocks are blocks that you create in the interface. They are much like nodes configurable data structures, with fields etc. If you want to render one of these, you can do what you would normally do with entities, load them and render them with the view builder:

$bid = ??? // Get the block id through config, SQL or some other means
$block = \Drupal\block_content\Entity\BlockContent::load($bid);
$render = \Drupal::entityTypeManager()->
  getViewBuilder('block_content')->view($block);
return $render;

Plugin blocks

Blocks can also be plugin, defined in various modules. An example could be the breadcrumb block. If you want to render these, you will need to use the block plugin manager.

$block_manager = \Drupal::service('plugin.manager.block');
// You can hard code configuration or you load from settings.
$config = [];
$plugin_block = $block_manager->createInstance('system_breadcrumb_block', $config);
// Some blocks might implement access check.
$access_result = $plugin_block->access(\Drupal::currentUser());
// Return empty render array if user doesn't have access.
// $access_result can be boolean or an AccessResult class
if (is_object($access_result) && $access_result->isForbidden() || is_bool($access_result) && !$access_result) {
  // You might need to add some cache tags/contexts.
  return [];
}
$render = $plugin_block->build();
// In some cases, you need to add the cache tags/context depending on
// the block implemention. As it's possible to add the cache tags and
// contexts in the render method and in ::getCacheTags and 
// ::getCacheContexts methods.
return $render;

Config entities

Shared for the two types are blocks, are that once you insert them into a region, you will create a config entity that has all of the settings for the block. In some cases it will be more useful handling config entities. Since the same block can be place in multiple regions with and with different configuration, it can get more tricky using the block config entities. The nice thing is that you might want to render a block with specific configuration, the bad thing is that config ids can change by messing with the interface, so the code might end up not working after letting users use the block interface.

$block = \Drupal\block\Entity\Block::load('config.id');
$render = \Drupal::entityTypeManager()
  ->getViewBuilder('block')
  ->view($block);
return $render;
  • 1
    The question doesn't specify if it is about rendering a block config entity ( a pre-configured block placement) or a block plugin with hardcoded configuration. Which makes sense because that difference doesn't exist in 7.x. This is more flexible because the other actually a requires a specific block that needs to be placed in a given theme and region. However, you should never create them by hand. Use the block plugin manager's createInstance() method for that with the plugin ID, where you can also provide a $configuration array... – Berdir Sep 5 '15 at 12:52
  • 1
    Also, you might want to consider calling the access() method first in case block access is restricted to e.g. a certain permission by that block. Can you improve your answer a bit on that? Can become a useful resource then :) – Berdir Sep 5 '15 at 12:53
  • @Berdir It's been a while, but I finally got around to improving the answer. With all the various caching going on, using the plugin directly is probably only useful in limited situations. – googletorp Jan 30 '16 at 10:55
  • 3
    The downside with using the block plugin manager createInstance() is that the resulting render array isn't run through block theming, so you can't use the block--blockname.twig.html, for instance. The alternative is to create a block for your theme, but leave it disabled, and then in your code do: ``` $block = \Drupal\block\Entity\Block::load('myblock'); $build = \Drupal::entityManager()->getViewBuilder('block')->view($block); ``` – joachim Apr 26 '16 at 8:21
13

For display only your block in your templates with preprocess the best way is

$block = \Drupal\block\Entity\Block::load('my_block_id');
$variables['My_region'] = \Drupal::entityManager()
          ->getViewBuilder('block')
          ->view($block);

And in your page.html.twig or node.html.twig or xxx.html.twig use your variable My_region like this :

{% if page.My_region %}
    {{ page.My_region }}
{% endif %}

And in renderable array (custom module) by example into an controller custom in content() :

public function content() {
    $block = \Drupal\block\Entity\Block::load('my_block_id');
    $block_content = \Drupal::entityManager()
      ->getViewBuilder('block')
      ->view($block);

          return array(
        '#type' => 'container',
        '#attributes' => array(
          'class' => array("Myclass"),
        ),
        "element-content" => $block_content,
        '#weight' => 0,
      );
}

Using drupal_render is not useful as Drupal already assume the render in D8 and this is deprecated. You should use \Drupal::service('renderer')->renderRoot() instead.

It's a bit heavy, it is better to use the maximum area system and does not add load block from the preprocess. In the case of using a controller in your modules this seems a justified use.

  • This controller implementation is exactly what I was looking for. Thanks! – Mrweiner May 24 '18 at 0:46
  • I'm interested in this controller implementation for a similar use case I'm dealing with. But I can't find any documentation about element-content property in a render array. Do you know where it's documented ? – Eria Jun 18 '18 at 9:52
  • I don't know why, but \Drupal\block\Entity\Block::load does not return a block all the time. It only returns something if the block I load is placed within the view in block layout. If it's not placed, it returns null. – Arthur Attout Oct 8 '18 at 14:18
3

In addition to the top answer... If you want to render a block from a view, you may have to do things a little differently.

$view = views_embed_view('my_view_name', 'my_display_name');

(display name eg -> block_1)

Since we're going to pass it to twig, we don't need to render (using render service).

So you can just pass it as a variable to twig (for this example, its the return of a Controller):

return [
  ['description' => [
    '#theme' => 'your_theme_hook',
    '#your_variable => $view
  ]
]

in your module you need a hook_theme() for your variable:

function hook_theme($existing, $type, $theme, $path) {
  return array(
    'your_theme_hook' => array(
      'variables' => [
        'your_variable' => NULL,
      ]
    )
  )
}

And finally in your twig template:

{{ your_variable }}
2

I needed to get the HTML of a custom block and got it using:

$con = \Drupal\block\BlockViewBuilder::lazyBuilder('bartik_search', 'full');
$d   = \Drupal::service('renderer')->renderPlain($con);

print $d->__toString();
  • I needed to add it to a render array and there it worked without __toString(). – leymannx Nov 15 '16 at 12:32
  • Important to mention that a block at least needs to be placed in "Disabled blocks" region. Or any other active region. – leymannx Dec 21 '16 at 9:07
0
// You need a block_id! to get it just click configure in the desire block and you'll get url like this /admin/structure/block/manage/bartik_search   the last part of the parameter is the block id
$block = \Drupal\block\Entity\Block::load('bartik_search');
$block_content = \Drupal::entityManager()
  ->getViewBuilder('block')
  ->view($block);

return array('#markup' => \Drupal::service('renderer')->renderRoot($block_content));
  • If possible, you should avoid using drupal_render or the render service. drupal_render is depricated but returing a render a array with the rendered content is pretty bad, you should return $block_content instead, the render array can be altered before the actual render and you should let Drupal do the rendering as much as posisble instead or doing it your self. – googletorp Jan 30 '16 at 10:59
  • This is going to work only if the block is already placed on the page through block layout. – hugronaphor Sep 9 '17 at 14:41
0

Seems this works for plugin blocks ..

$block = \Drupal\block\Entity\Block::load('some_block_id_3');
  $pluin = $block->getPlugin();
  $build = $pluin->build();
  $build['#weight'] = 4;
  $form['block'] = $build;
-1

You get block output:

$block = \Drupal\block\Entity\Block::load ('my_bock_id');
$block_content = \Drupal::entityManager ()->
  getViewBuilder ('block')->
  view ($block);

And then you may return output in different ways:

return array (
    '#type' => 'container',
    'element-content' => $block_content
);

or:

return ['#markup' => \Drupal::service ('renderer')->render ($block_content)];
  • \Drupal::service ('renderer')->render ($block_content) may be done as drupal_render ($block_content) However the latter is deprecated in Drupal 8. – olegiv Jan 29 '16 at 14:17
  • If possible, you should avoid using drupal_render or the render service. drupal_render is depricated but returing a render a array with the rendered content is pretty bad, you should return $block_content instead, the render array can be altered before the actual render and you should let Drupal do the rendering as much as posisble instead or doing it your self. What you returns needs to be rendered again, which makes the actual rendering pointless – googletorp Jan 30 '16 at 11:01
-1

Based on my research, you could base the code from How to render a block programmatically in drupal 8. You could also change

return array('#markup' => \Drupal::service('renderer')->renderRoot($block_content));

into something as simple as:

$output .= \Drupal::service('renderer')->renderRoot($block_content);

to attach it for example into a page's return variable.

  • If possible, you should avoid using drupal_render or the render service. drupal_render is depricated but returing a render a array with the rendered content is pretty bad, you should return $block_content instead, the render array can be altered before the actual render and you should let Drupal do the rendering as much as posisble instead or doing it your self. – googletorp Jan 30 '16 at 10:59
  • You're right. This isn't the recommended and most flexible solution. – Leolando Tan Jan 30 '16 at 21:09

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.