I've worked with twig and have overriden most of elements in my application. However, I it is not clear to me how I can overwrite the menu template for specific node-types. The suggestions I get from the theming debug are too general and not node specific. Any ideas on how to register a twig template for menu for specific node types?
2 Answers
Menus do things a little differently then, so you have an option or two...
/**
* Implementation of hook_theme_suggestions_alter().
*/
function mymodule_theme_suggestions_alter(array &$suggestions, array $variables, $hook) {
if ($hook == 'menu' && ($node = \Drupal::routeMatch()->getParameter('node'))) {
$content_type = $node->bundle();
$suggestions[] = 'menu__node_type__%';
$suggestions[] = 'menu__node_type__'.$content_type;
}
}
This will give you give you the following suggestion in this order:
- menu--MENU-NAME.html.twig
- menu--node-type--page.html.twig
- menu--node-type--%.html.twig
- menu.html.twig
With this the menu--MENU-NAME
template still takes preference over the node type, so we need a trick to add suggestions after.
/**
* Implementation of hook_theme_suggestions_HOOK_alter().
*/
function mymodule_theme_suggestions_menu_alter(array &$suggestions, array $variables) {
$key = array_search('menu__'.$variables['menu_name'], $suggestions);
if ($key !== FALSE && ($node = \Drupal::routeMatch()->getParameter('node'))) {
$content_type = $node->bundle();
array_splice($suggestions, ++$key, 0, array('menu__node_type__%', 'menu__node_type__'.$content_type));
}
}
- menu--node-type--page.html.twig
- menu--node-type--%.html.twig
- menu--main.html.twig
- menu.html.twig
Targeting your placement within the array of suggestions can be helpful, but it can be over kill, so you may just want to keep it simple and place your new suggestion at the end of the list and have the highest override
/**
* Implementation of hook_theme_suggestions_HOOK_alter().
*/
function mymodule_theme_suggestions_menu_alter(array &$suggestions, array $variables) {
if ($node = \Drupal::routeMatch()->getParameter('node')) {
$content_type = $node->bundle();
$suggestions[] = 'menu__node_type__%';
$suggestions[] = 'menu__node_type__'.$content_type;
}
}
You can even throw $variables['menu_name']
into the mix with:
$suggestions[] = 'menu__'.$variables['menu_name'].'__node_type__%';
$suggestions[] = 'menu__'.$variables['menu_name'].'__node_type__'.$content_type;
I did not try it myself, but the tip described in https://www.drupal.org/node/2521876 explains how to add a custom suggestion based on the node type, using the hook_theme_suggestions_HOOK_alter hook:
/**
* Implements hook_theme_suggestions_HOOK_alter().
*/
function THEME_NAME_theme_suggestions_page_alter(array &$suggestions, array $variables) {
if ($node = \Drupal::routeMatch()->getParameter('node')) {
$content_type = $node->bundle();
$suggestions[] = 'page__'.$content_type;
}
}
The solution above seems to work for adding page suggestions. You might want to adapt it to add menu suggestions instead, with THEME_NAME_theme_suggestions_menu_alter
as the function name.