Score:0

theme_preprocess_menu is not seeing main menu

in flag

Background: I have an event website where I want to hide the event registration menu item when registration for the event is closed.

theme_preprocess_menu is not triggering on anything except 'menu__toolbar'. The code:

function myTheme_preprocess_menu(&$variables, $hook) {
  dpm($hook);
}

merely gives the result "menu__toolbar" on any page where my theme is active. My theme is based on Bartik.

How do I get it to trigger on the main menu?

leymannx avatar
ne flag
It's just `hook_preprocess_menu(&$variables)` without `$hook` and then `dpm($variables);`. Theme name must only contain lower case letters and underscores. Did you flush cache? Does the same hook get triggered from a custom module? Where exactly did you place the hook? Is the main menu currently visible on the page you are checking? Update your question for clarification.
No Sssweat avatar
ua flag
Try with **[hook_menu_links_discovered_alter](https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Menu%21menu.api.php/function/hook_menu_links_discovered_alter/9.3.x)**
No Sssweat avatar
ua flag
But the more appropriate solution would be to deny access with **[hook_entity_access](https://www.prometsource.com/blog/how-manage-hook-entity-access-with-drupal)**, as when access is forbidden, it hides the link automatically.
apaderno avatar
us flag
Preprocess functions receive three arguments from [`ThemeManager::render()`](https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Theme%21ThemeManager.php/function/ThemeManager%3A%3Arender/9.3.x), which calls them as `$preprocessor_function($variables, $hook, $info);`. The value of `$hook` is also stored in `$variables['theme_hook_original']`, though; there isn't any need to use the second parameter, and that's why preprocess functions don't usually use it.
apaderno avatar
us flag
To hide a menu item, it's better to change its #access value, as @NoSssweat said. A preprocess function would be too late for this, and it would be the wrong hook to use, since its purpose is changing how an element is rendered.
in flag
Thanks very much. hook_entity_access solves one of my problems neatly (the one I described above). There is one other menu item I would like to hide but not disable: 'login'. Once the event is closed, nobody except admin needs to login, so I would like to hide it, but still allow admin to use /user/login to access the site.
Score:0
us flag

What you get in $hook doesn't say for which menu the preprocess function is called. It's simple a suggestion Drupal is picking up in ThemeManager::render().

  // Invoke hook_theme_suggestions_HOOK().
  $suggestions = $this->moduleHandler->invokeAll('theme_suggestions_' . $base_theme_hook, [
    $variables,
  ]);

  // If the theme implementation was invoked with a direct theme suggestion
  // like '#theme' => 'node__article', add it to the suggestions array before
  // invoking suggestion alter hooks.
  if (isset($info['base hook'])) {
    $suggestions[] = $hook;
  }

  // Invoke hook_theme_suggestions_alter() and
  // hook_theme_suggestions_HOOK_alter().
  $hooks = [
    'theme_suggestions',
    'theme_suggestions_' . $base_theme_hook,
  ];
  $this->moduleHandler->alter($hooks, $suggestions, $variables, $base_theme_hook);
  $this->alter($hooks, $suggestions, $variables, $base_theme_hook);

  // Check if each suggestion exists in the theme registry, and if so,
  // use it instead of the base hook. For example, a function may use
  // '#theme' => 'node', but a module can add 'node__article' as a suggestion
  // via hook_theme_suggestions_HOOK_alter(), enabling a theme to have
  // an alternate template file for article nodes.
  foreach (array_reverse($suggestions) as $suggestion) {
    if ($theme_registry->has($suggestion)) {
      $info = $theme_registry->get($suggestion);
      break;
    }
  }

olivero_theme_suggestions_menu_alter() is one of the hooks that alter the suggestions for the menu template file. There could be a module doing a similar suggestion, in your case.

function olivero_theme_suggestions_menu_alter(&$suggestions, array $variables) {
  if (isset($variables['attributes']['region'])) {
    $suggestions[] = 'menu__' . $variables['attributes']['region'];
  }
}

What you are looking for is the menu machine name, stored in $variables['menu_name'] as documented in menu.html.twig.

If the purpose is hiding a menu item, using that preprocess hook is not the solution. To hide a menu item is sufficient, for example, to avoid the currently logged-in user has access to the route used for that menu item. In that case, Drupal won't show the menu item.

mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.