29

I need to render a views block in my page.html.twig template. In D7 I would do this:

<?php
  $block = module_invoke('module_name', 'block_view', 'block_delta');
  print render($block['content']);
?>

In Drupal 8 module_invoke is deprecated and recommended to use this: (I've added the block's name as the second parameter)

Drupal::moduleHandler()->invoke($block, 'views_block__blog_block_1', $args = array());

I tried a few things. First tried to do it in a twig template but I don't know how to call php functions in a twig template, so that didn't turn out too well.

Then I called the function in the preprocess_page() function in the .theme file but before I could get it to work I tried something simpler just to try make a variable work inside the twig template which didn't work either, for example:

In the template_preprocess_page(&$vars) function in the .theme file:

$test = 'Hello World';
$vars['$my_var'] = $test;

I tried to call my_var inside the twig template but it didn't work and I got an error message saying "The site has an error, please contact the administrator"

So, to summarize, here are my questions:

  1. How do I make variables available inside twig templates?
  2. How do I call functions inside twig templates?
  3. Do I render blocks inside the .theme file or twig template?

3 Answers 3

50

You're on the wrong track with module_invoke(). That's just a fancy way of calling the {$module_name}_block_view() function.

The fact that it changed doesn't matter, the point is that the block system completely changed in 8.x and is now using plugins and config entities, those functions no longer exist.

You have a few options.

a) Re-use an existing block config entity and view it. Very easy, but requires that configuration to exist, e.g. as a disabled block.

$block = \Drupal\block\Entity\Block::load('your_block_id');
$variables['block_output'] = \Drupal::entityTypeManager()
  ->getViewBuilder('block')
  ->view($block);

b) Create the block plugin instance directly, pass it the configuration (you can find the block plugin id and configuration easily in an exported block config entity). The downside is that you don't get render caching, but if you display it somewhere that is already cached (like a node template), that doesn't really matter.

$variables['block_output'] = \Drupal::service('plugin.manager.block')
  ->createInstance($plugin, $configuration)
  ->build();

c) In case of a view, you can also load the view directly and display it.

d) You can also re-think your approach completely and use block regions or Page Manager (which uses standard block plugins in 8.x).

13
  • Thank you for your answer. I would like to go with A or B. A Region will work but I want to avoid using a region. The only problem I'm having is when I call block_output in the twig template I have an error - "Unexpected tag name "block_output" so I don't know how to make that variable available even though I created it in the preprocess_page function. I will try work it out. Commented Mar 29, 2015 at 20:59
  • Sounds like you're using {% ? Use {{ block_output }}.
    – Berdir
    Commented Mar 29, 2015 at 21:13
  • Yes, that was it! Still trying to get the hang of twig. Thanks. Commented Mar 29, 2015 at 22:25
  • Since Drupal 8.0.0 entityManager is deprecated. Use entityTypeManager instead. Commented Feb 29, 2016 at 12:31
  • where do I put this code? $block = \Drupal\block\Entity\Block::load('your_block_id'); $variables['block_output'] = \Drupal::entityManager() ->getViewBuilder('block') ->view($block); Thank you!
    – user59001
    Commented Mar 14, 2016 at 18:58
13

In Drupal 8, this works for rendering a block plugin (that is, one that you've created in a custom module) in a preprocess_hook:

function mymodule_preprocess_something(array &$variables) {
  $customblock = \Drupal::service('plugin.manager.block')->createInstance('my_custom_block', []);
  $variables['content']['custom_block_output'] = $customblock->build();
}

You can then render it in your twig template like this:

{{ content.custom_block_output }}

Note: this will load up a generic version of your block. If you want to load up an instance of your block with variables (after you have created it at /admin/structure/block), you have to load it this way:

    // Load Instance of custom block with variables
    $example_block = \Drupal::entityManager()->getStorage('block')->load('example_block_machine_name');
    if (!empty($example_block)){
      $example_block_content = \Drupal::entityManager()
        ->getViewBuilder('block')
        ->view($example_block);
      if ($example_block_content) {
        // Add block content to build array
        $variables['content']['custom_block_output'] = $example_block_content;
      }
    }
1
  • 1
    This was the solution for me and by far the easiest one. Commented May 27, 2016 at 11:49
9

You can use Twig tweak module for that, then you can use the following syntax:

  <dd>{{ drupal_block('myblock') }}</dd>

Related: How do I programmatically place a block?

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