I have a certain number of main menus which need to showcased based on logged in user role. for example user with the role, A can sees few menus and user with the role B, sees another set of few menus.
5 Answers
This can be achieved using the routes to manage the permissions. Take the following example:
mymodule.routing.yml
mymodule.home:
path: '/mymodule'
defaults:
_controller: '\Drupal\mymodule\Controller\MyModuleController::overview'
_title: 'My Module'
requirements:
_role: 'authenticated user'
mymodule.settings:
path: '/admin/mymodule'
defaults:
_form: 'Drupal\mymodule\Form\MyModuleSettingsForm'
_title: 'Settings'
requirements:
_permission: 'administer mymodule'
mymodule.view:
path: '/mymodule/view'
defaults:
_controller: '\Drupal\mymodule\Controller\MyModuleController::view'
_title: 'View'
requirements:
_role: 'authenticated user'
mymodule.edit:
path: '/mymodule/edit'
defaults:
_form: 'Drupal\mymodule\Form\MyModuleEditForm'
_title: 'Edit'
requirements:
_permission: 'edit mymodule'
mymodule.links.menu.yml
mymodule.home:
title: 'My Module'
parent: main
route_name: mymodule.home
weight: 10
mymodule.settings:
title: 'Settings'
parent: mymodule.home
route_name: mymodule.settings
weight: 10
mymodule.view:
title: 'View'
parent: mymodule.home
route_name: mymodule.view
weight: 10
mymodule.edit:
title: 'Edit'
parent: mymodule.home
route_name: mymodule.edit
weight: 10
With this approach you can display the same menu to all users, but because the links take the permissions from the routes, only users with the administer mymodule
permission will be able to see the Settings link for example. You can use roles to manage it as well by using _role: '$rid'
.
-
You can also combine roles with
,
and+
. One means or and the other and. I don't recall which is which. Commented May 15, 2019 at 13:16
In Drupal 8, you can also use the following code in your funky.module
file for a programmatic approach. The approach below allows to have access rules independent of menu visibility:
/**
* Implements hook_preprocess_menu().
*
* @param array[] $variables
*/
function funky_preprocess_menu(&$variables) {
if (in_array('role_b', Drupal::currentUser()->getRoles())) {
// Hide the menu item
unset($variables['items']['the_key_you_used_in_your_menu_links_yml_file']);
}
}
This assumes your module is called funky
. It also assumes you have a funky.links.menu.yml
file containing something similar to this:
the_key_you_used_in_your_menu_links_yml_file:
title: 'Your menu caption'
route_name: your_route
menu_name: account
cache_contexts:
- user.roles
If you only distinguish if a user has a role or not, then you can further tighten the cache_context by that role. For the example above, user.roles:role_b
would be appropriate. The documentation for cache contexts is here: https://www.drupal.org/docs/8/api/cache-api/cache-contexts
-
Thanks. I was creating a link to an existing route (defined by a core module) for users with a certain role, I didn't want that link to be visible for Administrators or other roles. This worked perfectly. Commented Apr 14, 2021 at 11:02
-
I had to configure menus based on groups on our LDAP server, so this was the solution for me. Commented Jul 28, 2022 at 7:19
Note: A solution using route permissions is the best and appropriate solution to avoid repetition and prevent a user to access/view the page using a direct link.
All you gotta do is configure your menu block
Then under Visibility > Roles, check mark ☑ the roles that you want to be able to view this block menu.
-
@Nossweat to add on more, It needs to be achieved for each menu item in the main menu. Something similar to menu_per_role in D7.– SidheesCommented Mar 1, 2017 at 10:22
-
@Sidhees Well, that module isn't going to port itself. I don't think there is anything similar out there for D8, so better start rolling-up the sleeves. Your need is quite a specific and picky need if you ask me. Commented Mar 1, 2017 at 10:47
-
1This will still not solve the problem if one wants to make the link to "/user" depending on the role, either show the menu item or not, and label the menu item "role 1 thing" and another role "role 2 thing"– Raf A.Commented Oct 1, 2018 at 5:57
-
1this answer acts on the whole menu, while question is about a single menu item of a menu– AugustoCommented Aug 12, 2021 at 21:36
-
1@augusto agreed, at the time I wrote this answer, I wasn't as savvy with D8 and its code. A solution using route permissions is the better option to avoid repetition. Commented Aug 13, 2021 at 7:31
For a non-coding approach, the contrib module Menu Per Role may be of use.
This module allows you to restrict access to menu items based on user roles. Just activate the module and edit a menu item as usual. There will be a new fieldset that allows you to restrict access by role.
Just use Menu Item Role Access. It makes it much easier than writing code.
-
That module has a years old unresolved issue saying that uninstalling it results in sql errors site wide so I would proceed with caution. Commented Jan 28, 2022 at 3:28