I have one “branch” of my main site’s navigation tree that should only be accessible to a set of registered, logged-in users. I understand how to query a user’s role and capabilities. This question is specifically about what is the best way to leverage the build-in nav menu, but just hide an item conditionally.
Do I need to overload the built-in default navigation and write a custom query and build the navigation structure manually? I’d love to avoid this if possible.
I don’t need full code samples, just your ideas and general framework / approach.
Appreciate the advice!
T
Use your own walker and check the capability before you create an item.
Someone has made a brilliant plugin to do this with no coding. Even has checkboxes in the menu editor interface for selecting the approved roles per menu item.
http://wordpress.org/extend/plugins/nav-menu-roles/
The answer toscho posted is correct but for the few people who know what they are doing and how to do it. 🙂
I’m adding this for the rest of the world as a simpler solution for the less advanced users. The idea would be to have different menus and just displaying them based on the user role.
So say you have 3 menus named editor, author and default:
The trouble with overriding start_el and end_el is that doing so only controls the display of the menu item in question – it doesn’t affect the display of the children. I think you need to override display_element to hide the children as well.
Also, it’s possible to use the description field of the menu item to hold information for each menu item about whether to display it or not.
This code looks in the description of each menu item for a comma delimited list of capabilities such as [capability: this_one, next_one] and if the current user has none of the capabilities won’t display the item (or any of its children). It’s fairly easy to remove the strings from the description if you actually want to use the description for its intended purpose.
I have tried my hand at using the description field to use as to which roles can access which menu items, and based my modifications on code I got from here – Pimp my WP Menu
My modified version:
It is not the cleanest version yet, but it works. I hope someone else can make a good use of it as well.
I’m going to post my solution for others who may happen upon this thread. I’m not 100% happy with it because you shouldn’t couple a template with menu functionality (Toscho’s approach of using metadata or a custom taxonomy is probably more correct). However, it’s a quick and dirty one. I’ve tried to mitigate the tight coupling by providing some constants near the top of functions.php to help future developers maintain the code:
So the protected page template is just a variant of single.php, but it will check to see whether current_user_can(ZG_PROTECTED_PAGE_CAPABILITY) before displaying any content, for security reasons.
Next, I implement a custom walker, as per Toscho’s suggestion. The walker in this case is extremely simple – we override the Walker_Nav_Menu’s public start_el and end_el methods, just intercepting them long enough to ask the question: do we have access to see the menu item?
The rule is simple: if the page is not a “private” page (which in this case is determined by that page using a particular page template) it’s visible. If it IS a “private” page, and the user is authenticated into a role that has the custom capability we’re looking for, then it is visible. Otherwise, it’s not visible.
If we do have access, then we just have to use the Walker_Nav_Menu’s built-in methods without modification, so we call the parent:: method of the same name.