1

Editing question based on information from @NoSssweat

The book module uses the same hook for the book tree block and the rendered index view in the book page.

I have used the below code to return file name suggestions, so that I can override the html output for the book tree block in a specific region - "sidebar-first". I expected the below code would spit out something like book-tree--book-toc-180--sidebar-first.html.twig. Instead, it just spits out a file name suggestion that is already being suggested:

<!-- FILE NAME SUGGESTIONS:
   * book-tree--book-toc-180.html.twig
   * book-tree--book-toc-180.html.twig
   x book-tree.html.twig
-->

This file name suggestion is the same for the main content on the book page. How can I target any book tree blocks within the sidebar-first region?

// Add a region variable to a block.
// http://kristiankaa.dk/article/drupal8-region-specific-menu-theme-hook-suggestion
function uswds_subtheme_preprocess_book_tree__book_toc_180(&$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 uswds_subtheme_theme_suggestions_book_tree__book_toc_180_alter(array &$suggestions, array $variables) {
    if (isset($variables["attributes"]["region"])) {
        $suggestions[] = $variables["theme_hook_original"] . "__" . $variables["attributes"]["region"];
    }
}

2nd attempt I did the below, and it works but it only works for the book module default block, although any other book module block plugin all mostly use book-tree.html.twig

// Add a region variable to a block.
function uswds_subtheme_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
function uswds_subtheme_theme_suggestions_alter(array &$suggestions, array $variables, $hook) {
  if (isset($variables["attributes"]["region"])) {
    $suggestions[] = $variables["theme_hook_original"] . "__" . $variables["attributes"]["region"];
  }
}
5
  • 2
    Does this answer your question? Determine which region a menu block is rendered in
    – No Sssweat
    Nov 9 '21 at 8:22
  • @NoSssweat - not quite, as I'm looking for if it's possible within twig
    – Jason
    Nov 9 '21 at 14:20
  • @NoSssweat - further question: I attempted to add this via my subtheme by creating my_subtheme.theme file, but this didn't appear to work (my guess is that inheritance doesn't work that way?).
    – Jason
    Nov 12 '21 at 17:46
  • Assuming your sub theme is set as the current theme, it should've worked, perhaps you didn't flush the cache so the hooks get pickedup?
    – No Sssweat
    Nov 12 '21 at 18:20
  • @NoSssweat - see updated. Cache cleared.
    – Jason
    Nov 12 '21 at 20:56
1

Nice try, since this is a book and not menu, the process is similar, but not exactly the same. I was hoping you would figure it out.

But anyways, here you go:

/**
 * Implements hook_preprocess_HOOK().
 *
 * Pass block region value to content so this can be used in
 * uswds_subtheme_theme_suggestions_menu_alter() since $variables['elements']
 * is not available there.
 */
function uswds_subtheme_preprocess_block(&$variables) {
  if (isset($variables['elements']['#id']) && $variables['base_plugin_id'] === 'book_navigation') {
    $region = \Drupal\block\Entity\Block::load($variables['elements']['#id'])->getRegion();
    $content = $variables['content'];
    foreach ($content as $content_key => $content_info) {
      if (is_numeric($content_key)) {
        $variables['content'][$content_key]['#attributes']['region'] = $region;
      }
    }
  }
}

/**
 * Implements hook_theme_suggestions_HOOK_alter().
 *
 * Provide region based book suggestions.
 */
function uswds_subtheme_theme_suggestions_book_tree_alter(&$suggestions, array $variables) {
  if (isset($variables['attributes']['region'])) {
    $suggestion = 'book__' . $variables['theme_hook_original'] . '__' . $variables['attributes']['region'];
    $suggestion = str_replace('-', '_', $suggestion);
    $suggestions[] = $suggestion;
  }
}

/**
 * Implements hook_preprocess_HOOK().
 *
 * Get rid of the region attribute added in uswds_subtheme_preprocess_block() as it's
 * not a valid HTML attribute.
 */
function uswds_subtheme_preprocess_book_tree(&$variables) {
  if (isset($variables['attributes']['region'])) {
    unset($variables['attributes']['region']);
  }
}
2
  • Unfortunately, I'm not seeing any change in suggestions for the book-tree.html.twig
    – Jason
    Nov 15 '21 at 3:16
  • Looking further, I don' believe the second function is executing, as I can change some of the values - such as 'book__' to 'books__' and that change never occurs.
    – Jason
    Nov 15 '21 at 4:17
1

or how can I do something in twig, like {% if region == 'sidebar-first' %} and just override book-tree.html.twig

// Adds a region attribute to a block.
function uswds_subtheme_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();
    }
  }
}

/**
 * Implements hook_preprocess_HOOK().
 *
 * Creates region variable
 *
 * Gets rid of the region attribute added in uswds_subtheme_preprocess_block() as it's
 * not a valid HTML attribute.
 */
function uswds_subtheme_preprocess_book_tree(&$variables) {
  if (isset($variables['attributes']['region'])) {
    // creates region variable for book-tree.html.twig
    $variables['region'] = $variables['attributes']['region'];
    // unset invalid html attribute.
    unset($variables['attributes']['region']);
  }
}
2
  • Unfortunately, this never gets called - uswds_subtheme_preprocess_book_tree.
    – Jason
    Nov 16 '21 at 4:10
  • It should be, did you flush the cache? If yes, check to see if it's failing the isset conditional.
    – No Sssweat
    Nov 16 '21 at 4:58
1

Using all of the help from @NoSssweat and I was able get this working:

// Add a region variable to a block.
function uswds_subtheme_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
function uswds_subtheme_theme_suggestions_alter(array &$suggestions, array $variables, $hook) {
  if (isset($variables["attributes"]["region"])) {
    $suggestions[] = $variables["theme_hook_original"] . "__" . $variables["attributes"]["region"];
  }
}

Which outputs (the second suggestion including the region):

<!-- FILE NAME SUGGESTIONS:
   * book-tree--book-toc-180.html.twig
   * book-tree--book-toc-180--sidebar-first.html.twig
   x book-tree.html.twig
-->

Update to working version:

<?php
// Add a region variable to a block. Only applies to some versions of plugins that use book-tree.html.twig 
function uswds_subtheme_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();
      }
    }
  }

// Adds template suggestion to blocks. Seems to work everywhere, but doesn't target the book tree
function uswds_subtheme_theme_suggestions_block_alter(array &$suggestions, array $variables){
    if (!empty($variables['elements']['#id'])) {
        $block = \Drupal\block\Entity\Block::load($variables['elements']['#id']);
        $region = $block->getRegion();
        // adds suggestion with region and block id
        $suggestions[] = 'block__' . $region . '__' . $variables['elements']['#id'];
        // adds suggestion with region id
        $suggestions[] = 'block__' . $region;
    }
}


// add a template suggestion based on region name
function uswds_subtheme_theme_suggestions_alter(array &$suggestions, array $variables, $hook) {
  if (isset($variables["attributes"]["region"])) {
    $suggestions[] = $variables["theme_hook_original"] . "__" . $variables["attributes"]["region"];
  }
}
4
  • 1
    I used Bartik when I wrote my code, you should add my last hook function; otherwise, you end up with an illegal HTML attribute.
    – No Sssweat
    Nov 15 '21 at 5:56
  • @NoSssweat - one more question (and thanks for all of the help) - my above code only seems to work specifically with the block provided by the book module. It does not provide suggestions for any other plugin, although the other plugins are also dependent on book-tree.html.twig. How do I get additional suggestions for ANY block that is using book-tree.html.twig and is already outputting book-tree--book-toc-180.html.twig?
    – Jason
    Nov 15 '21 at 21:47
  • @NoSssweat or how can I do something in twig, like {% if region == 'sidebar-first' %} and just override book-tree.html.twig?
    – Jason
    Nov 15 '21 at 22:08
  • see my newest answer
    – No Sssweat
    Nov 15 '21 at 22:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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