-1

I have a submenu based on the main navigation menu system. This Plugin Block builds the submenu on every page. The links of course change based on the route.

Every hour around the same time, the menu block will disappear and then will only reappear quickly when I hard reset the route and link cache. Otherwise it takes a few minutes for it to come back. By disappear, I mean the block as a whole doesnt appear AT ALL on any pages; no container div, no data, nothing.

Im wondering if its this return logic, a caching issue, or both:

    <?php

class SubMenuBlock extends BlockBase {

  /**
   * {@inheritdoc}
   */
  public function build() {
    $menu_tree = \Drupal::menuTree();
    $menu_names = array('main', 'eyebrow');
    foreach($menu_names as $menu_name){
      $parameters = $menu_tree->getCurrentRouteMenuTreeParameters($menu_name);
      $default_parameters = $parameters;
      //Get the default menu id
      $default_menu_id = reset($parameters->expandedParents);
      $nos_parent = count($parameters->expandedParents);
      $currentLinkId = reset($parameters->activeTrail);
      $parameters->setRoot($currentLinkId);
      $tree = $menu_tree->load($menu_name, $parameters);
       //Check if the current menu item has children
      $has_children = reset($tree)->hasChildren;
      $current_level = reset($tree)->depth;
      //If the current menu item level is >= 3 show the second level parent and siblings in the navigation
      if ($menu_name == 'main') {
        if ($current_level >= 3) {
          $parameters = $menu_tree->getCurrentRouteMenuTreeParameters($menu_name);
          $level2_parent_id = end($parameters->activeTrail);
          $level2_parent_id = prev($parameters->activeTrail);
          $level2_parent_id = prev($parameters->activeTrail);
          $parameters->setRoot($level2_parent_id);
          $parameters->onlyEnabledLinks();
          $tree = $menu_tree->load($menu_name, $parameters);

        }

        else {
          if (empty($has_children) ) {
            $parameters_current = $menu_tree->getCurrentRouteMenuTreeParameters($menu_name);
            $directParent = next($parameters->activeTrail);
            $parameters_current->setRoot($directParent);
            $parameters_current->onlyEnabledLinks();
            $tree = $menu_tree->load($menu_name, $parameters_current);


          } 
        }
      }
      else {
       if ($current_level >= 2) {
          $parameters = $menu_tree->getCurrentRouteMenuTreeParameters($menu_name);
          $level2_parent_id = end($parameters->activeTrail);
          $level2_parent_id = prev($parameters->activeTrail);
          $parameters->setRoot($level2_parent_id);
          $parameters->onlyEnabledLinks();
          $tree = $menu_tree->load($menu_name, $parameters);

        }

        else {
          if (empty($has_children) ) {
            $parameters_current = $menu_tree->getCurrentRouteMenuTreeParameters($menu_name);
            $directParent = next($parameters->activeTrail);
            $parameters_current->setRoot($directParent);
            $parameters_current->onlyEnabledLinks();
            $tree = $menu_tree->load($menu_name, $parameters_current);


          } 
        }
      }


      //The following loop is for hding menu items that has the field(do_not_show_on_subnavigation) value as '1'
      foreach ($tree as $menu_key => $sub_parent_menu){
        $menu_uuid = str_replace('menu_link_content:', '', $menu_key);
        $menu_content = current(\Drupal::entityManager()->getStorage('menu_link_content')->loadByProperties(array('uuid' => $menu_uuid)));
        $dont_show = $menu_content->do_not_show_on_subnavigation->getValue();
        if(!empty($dont_show[0]['value'])) {
          $tree = array();
        }
        else {
          foreach ($sub_parent_menu->subtree as $sub_menu_key => $sub_menu_array){
            $sub_menu_uuid = str_replace('menu_link_content:', '', $sub_menu_key);
            $sub_menu_content = current(\Drupal::entityManager()->getStorage('menu_link_content')->loadByProperties(array('uuid' => $sub_menu_uuid)));
            $sub_menu_dont_show = $sub_menu_content->do_not_show_on_subnavigation->getValue();
            if (!empty($sub_menu_dont_show)){
              if(!empty($sub_menu_dont_show[0]['value'])) {
                unset($tree[$menu_key]->subtree[$sub_menu_key]);
              }
            }
          }
        }

      }

      // Transform the tree using the manipulators you want.
      $manipulators = array(
        // Only show links that are accessible for the current user.
        array('callable' => 'menu.default_tree_manipulators:checkAccess'),
        // Use the default sorting of menu links.
        array('callable' => 'menu.default_tree_manipulators:generateIndexAndSort'),
      );
      $tree = $menu_tree->transform($tree, $manipulators);
      // Finally, build a renderable array from the transformed tree.
      $menu = $menu_tree->build($tree);

      $markup = '<nav>' . \Drupal::service('renderer')->render($menu) . '</nav>';
      //Show only on the page under main navigation
      if ($default_menu_id != '' && $nos_parent > 1) {
        return array(
          '#type' => 'markup',
          '#markup' => $markup,
        );
      }
    }
  }

  public function getCacheTags() {
    //With this when your node change your block will rebuild
      //gets node id
    if ($node = \Drupal::routeMatch()->getParameter('node')) {
      //if there is node add its cachetag
        // array b is set to 'node:<id>'
      return Cache::mergeTags(parent::getCacheTags(), array('node:' . $node->id()));
    } else {
      //Return default tags instead.
      return parent::getCacheTags();
    }
  }

  public function getCacheContexts() {
    //if you depends on \Drupal::routeMatch()
    //you must set context of this block with 'route' context tag.
    //Every new route this block will rebuild
    return Cache::mergeContexts(parent::getCacheContexts(), array('route'));
  }
}

Caching is being enabled in my Plugin Block based on this drupalexchange link found here. Im wondering if I should just remove the getCacheTags function as I have a breadcrumb hook in the same module that only runs on context route like so:

$breadcrumb->addCacheContexts(['route']);

This accomplishes the same goal of being route dependent and the breadcrumb block doesn't disappear on me.

Im also concerned that something about the $default_menu_id or $nos_parent are being cached and causing the menu to not render at all for any of the children pages unless I clear the cache.

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.

Browse other questions tagged or ask your own question.