I'm not sure how to use this module. Just think of the following use case:
I'd like to deny node view access to anonymous users depending on a custom node field, implementing hook_node_access. This works fine, but corresponding menu items (e.g. in book pages) aren't removed, giving a 403 access denied.
I think chain_menu_access might help me solve this issue, so I've tried the following code:
function mymodule_menu_alter (&$items) {
chain_menu_access_chain($items['node/%node'], 'mymodule_access_check', array(1));
chain_menu_access_chain($items['node/%node/view'], 'mymodule_access_check', array(1));
}
function mymodule_access_check ($node) {
global $user;
if ($user->uid > 0)
return TRUE;
$node = node_load ($node->nid);
$public = field_get_items('node', $node, 'field_public');
if ($public[0]['value'] != 1)
return FALSE;
return TRUE;
}
Looks fine to me, but doesn't work. Seems the access check function doesn't get called. So what am I doing wrong?
Thx for help,
Boris
Comments
Comment #1
salvisLeave out 'node/%node/view' — it inherits its access from its parent.
Did you clear the menu cache?
Comment #2
drubbYou're right, I forgot to clear the cache. Now the situation is the following;
- my custom access check function is called
- no need to use node_load, the node object is already fully populated
- access to node is denied depending on field_public value, no need to use hook_node_access anymore
But sadly, the corresponding menu item is still displayed, giving the user an "access denied" page.
Any way to remove menu items the user has'nt access to?
At the moment, this module implements just an alternative to hook_node_access, giving some more possibilities as it's not restricted to node paths.
Comment #3
salvisNo, this module is completely unrelated to node access. It can be used to block access to node paths because it can block access to any path, but it's a completely different mechanism and effect.
Forum Access successfully uses CMA to hide the Forum menu item when a user does not have access to any forums. I don't know why it's not working in your case, but I suspect this is beyond the scope of CMA.
You mention book pages — if you're referring to the page-to-page links of the book pages, then this is definitely out of scope for CMA, because these are not menu items. They are artifacts of the book page content type, and you'll have to go to the core queue. If that's what you're after, then you may actually have better luck by implementing hook_node_access(), because the module implementing the book page type is more likely to check node access than menu access.
P.S. Please give this thread a title that would let you find it the next time you're in this situation. The current title is too broad to be useful.
Comment #4
drubbI've just had a quick glance at the forum_access module. Maybe the removal of corresponding menu items does work there because the module is implementing node grants?
Well, this is surely a core issue: there should be a possibility to automatically remove menu items and links to paths the user hasn't access to. As far as I've seen, this ONLY works using the (role-based) permission system, or implementing the node grant system.
Think I'll setup a clean minimal D7 install to do some tests regarding this problem, using node paths and none-node paths, menu items and standard links, and implementing different ways to block access. If you're interested, I'll post the results in some days.
Thanks so far,
Boris
P.S. I've changed the issue title. Better?
Comment #5
salvisNo, the 'Forum' menu item does NOT go away based on node access. Removing the 'Forum' menu item is the very reason for writing CMA in the first place.
That's menu router access, exactly what CMA is using. Whether the decision is taken based on roles (i.e. calling user_access()) or anything else (like your chained function) is completely irrelevant, so please don't call this "role-based".
In the OP you wrote node access wasn't working (which I agree with), and now you write it's working? I'm confused.
Let's get this straight: node access has absolutely no effect on menu paths. It aborts generation of node pages by calling drupal_access_denied() AFTER the menu system has already granted access. There's no way for the menu system to know what node access will do later on in the process. For the user the end result looks the same, but internally it's completely different.
Menu items and links are two completely different things. I think you're mixing up the two. CMA is intended to manage menu items, but there is no mechanism to manage links.
I'm still not completely sure what you want to do. Please post a screenshot and mark in red the things you want to get rid of, so that we both know what we're talking about.
Yes, the new title is better, and I think we'll find that CMA effectively does exactly that.
To investigate this, install Devel module, implement hook_init() and
dpm(menu_get_item());. The 'access' key shows you whether the menu system has decided to grant access or not. This is precisely where CMA intervenes, and I believe that it not only 403's pages (i.e. if you see FALSE you'll get the 403 page), but it also removes the corresponding menu item. If you see TRUE, your user has access to the path and there's no reason for the menu system to remove the menu item, even if some other component may decide later on to deny access. Links are never affected by any of this.Comment #6
drubb- It doesn't work using hook_node_access() (corresponding menu items are not removed)
- It works by implementing hook_node_access_records / hook_node_grants (corresponding menu items are removed)
I agree it can't work with non-menu links, because the generating function (e.g. l() or the book module) would have to check accessibilty, that's not a menu problem. So let's concentrate on real menu items.
I'll do a test setup and post some screenshots!
Comment #7
drubbI did some further investigations now, and I think the described problem is a core issue, not your module's fault. I've set up a site with ten example nodes, all with menu links, and restricted access to half of them using hook_node_access. This works fine, but the corresponding menu items still show up, despite of the value in menu item's 'access'. Have a look at the attached screenshot.
Using the chain_menu_access module, it's possible to change menu access further on, but items aren't removed, too. Look at the following example code:
Access is now denied for ALL items, but the menu items aren't removed. So I think this module just does what it's been designed for, namely chaining menu access functions. And this works fine.
Guess I have to find another way to remove inaccessable menu items, maybe by filing a core issue.
Thx for your patience!
Comment #8
drubbHere's a quick workaround for this problem: it's possible to remove menu items the user hasn't access to using a little theme function in template.php:
This has nothing to do with chain menu access api, just for interest. I've made this a core issue: http://drupal.org/node/1277596
Comment #9
salvisThank you for the follow-up.
I just had an idea; have you tried chaining to 'node/2'? I'm not exactly sure how it works internally, but if you create a menu item for your node, then I'd guess that core creates a menu router item for that nid and it may not look at 'node/%' when it sets up the menu.
Comment #10
salvisFeel free to reopen if necessary.