3

I need to re-use the same menu in two different regions, with slightly different markup. My thought was to simply check which region the block was being rendered in, and use if statements to modify the classes/structure as needed.

I've hit a roadblock; I was able to find a way to get what region a block is in, but I can't figure out how to pass that data to the menu. Here's my current code:

// Add a region variable to a block.
function theme_preprocess_block(&$variables, $hook) {
    $block_id = $variables["elements"]["#id"];
    $block = \Drupal\block\Entity\Block::load($block_id);
    $variables["region"] = $block->getRegion();
}

I can output the region variable just fine in block--system-menu-block.html.twig, but trying the variable doesn't get passed to menu.html.twig, which is where I need it.

I feel like I'm a stones through form an answer for this, if someone could point me in the right direction I'd be greatly appreciative.

Quick side note: I'm very new to Drupal, coming from WordPress development. So far it's been a difficult transition, so please assume I know nothing about themeing :)

2 Answers 2

9

Figured this out with the help of an article!

http://kristiankaa.dk/article/drupal8-region-specific-menu-theme-hook-suggestion

// Add a region variable to a block.
// http://kristiankaa.dk/article/drupal8-region-specific-menu-theme-hook-suggestion
function THEMENAME_preprocess_block(&$variables) {
    if (isset($variables["elements"]["#id"])) {
        $block_id = $variables["elements"]["#id"];
        $block = \Drupal\block\Entity\Block::load($block_id);

        if ($block) {
            $variables["content"]["#attributes"]["region"] = $block->getRegion();
        }
    }
}

// add a template suggestion based on region name
// http://kristiankaa.dk/article/drupal8-region-specific-menu-theme-hook-suggestion
function THEMENAME_theme_suggestions_menu_alter(array &$suggestions, array $variables) {
    if (isset($variables["attributes"]["region"])) {
        $suggestions[] = $variables["theme_hook_original"] . "__" . $variables["attributes"]["region"];
    }
}

That doesn't do exactly what I was trying for, but it does let me use different templates based on which region a block is being rendered in. Close enough for me :)

3
  • You should check that the id exists and that you can load a block for it. Page manager uses the same template to display blocks, but they have no ids and definitely don't exist as blocks, so if you ever end up using page_manager or something else that displays block plugins, your code will result in a fatal error.
    – Berdir
    Commented Oct 26, 2016 at 22:19
  • Ah, so do you mean wrap that first function in if (isset($variables["elements"]["#id"})? Commented Oct 27, 2016 at 13:15
  • 1
    Exactly. And also an if ($block), to be extra sure.
    – Berdir
    Commented Oct 27, 2016 at 14:16
0

The $variables["content"]["#attributes"] seem not to work anymore in all cases. The attribute tag has to be targeted to the specific content within the block.

Hence $variables["content"][0]["#attributes"]["region"] = $block->getRegion(); would work for those the previous answer didn't work.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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