Đưa region block vào trong node templates của Drupal 8

Why would you need to render the content from Drupal’s block layout via a node template file? Normally, that is the territory of page templates. The use-case for me was a page where node-specific fields were mixed in with blocks to the extent that rendering region content in a page template file wasn't going to work.

I needed to be able to render my region content amidst field values in my node template files. Drupal doesn't let you do that out-of-the-box.

Superpower your Nodes

A region defined as ‘Primary Content’ (primary_content) in our theme can be printed in a page template like so:

{{ page.primary_content }}

Try that in a node template and you get a big fat nothing. Using THEME_preprocess_node we can change this, and superpower our node templates to be as capable as page templates.

Replace “THEME” with your theme name below:

/**
* Implements hook_preprocess_node() for NODE document templates.
*/
function THEME_preprocess_node(&$variables) {
  // Allowed view modes
  $view_mode = $variables['view_mode']; // Retrieve view mode
  $allowed_view_modes = ['full']; // Array of allowed view modes (for performance so as to not execute on unneeded nodes)
 
  // If view mode is in allowed view modes list, pass to THEME_add_regions_to_node()
  if(in_array($view_mode, $allowed_view_modes)) {
    // Allowed regions (for performance so as to not execute for unneeded region)
    $allowed_regions = ['primary_content'];
    THEME_add_regions_to_node($allowed_regions, $variables);
  }
}
 
/**
* THEME_add_regions_to_node
*/
 
function THEME_add_regions_to_node($allowed_regions, &$variables) {
  // Retrieve active theme
  $theme = \Drupal::theme()->getActiveTheme()->getName();
 
  // Retrieve theme regions
  $available_regions = system_region_list($theme, 'REGIONS_ALL');
 
  // Validate allowed regions with available regions
  $regions = array_intersect(array_keys($available_regions), $allowed_regions);
 
  // For each region
  foreach ($regions as $key => $region) {
 
    // Load region blocks
    $blocks = entity_load_multiple_by_properties('block', array('theme' => $theme, 'region' => $region));
 
    // Sort ‘em
    uasort($blocks, 'Drupal\block\Entity\Block::sort');
 
    // Capture viewable blocks and their settings to $build
    $build = array();
    foreach ($blocks as $key => $block) {
      if ($block->access('view')) {
        $build[$key] = entity_view($block, 'block');
      }
    }
 
    // Add build to region
    $variables[$region] = $build;
  }
}

After clearing caches, I can now print content specified in Drupal’s block layout using my node template files. For example, if I’ve specified primary_content in $allowed_regions, then I can access it via node--node_type.html.twig with:

{{ primary_content }}