Hi all...

I'm learning to write modules and it's fun :)
I got to a point where google is not helping - so here goes a question:

My module is controlling access to nodes and it's working quite nicely :)
I implemented hook_node_access() and this is where I do my checking before allow/deny the access.

The problem is in the menus... I need to hide the menus for the user if he is not allowed to access the menu item. Since I do my access checks on the fly for each node - menu items are unaffected.

I need some help in going about this in the correct way.
Just to be safe let me state the obvious: I am learning and I do not need a suggestion for what module to install :)

Thanks in advance!

Comments

jaypan’s picture

You can do the access check in hook menu like this:

function hook_menu()
{
  // note: make sure to set the wildcard as %node and not just %.
  $menu['my_menu/%node'] = array
  (
    'title' => 'Some title',
    'page callback' => 'my_page_callback',
    // the next part is the relevant part:
    'access callback' => 'node_access',
    'access arguments' => array('view', 1), // 1 is the wildcard in the path, and will pass a fully loaded node object
  );
  return $menu;
}

This should do what you want.

Contact me to contract me for D7 -> D10/11 migrations.

onetwo’s picture

This looks great...

Thing is that I can't get the node_access to fire... I might have a wrong path?

Urls look like this:
http://localhost/node/5
http://localhost/node/6
http://localhost/node/7
etc...

I changed your example to:
$menu['node/%node'] = array (

Shouldn't this work? :)

---- EDIT ----
However, if I do this:
$menu['node/5'] = array

It fires (not passing the node object, but it fires)...

jaypan’s picture

I didn't realize you were trying to alter the default node path. And actually, I just went back and looked at your original post, and I realized where the problem lies. hook_node_access() only kicks in when trying to view the full node. It doesn't prevent the rendering of menu items, nor does it prevent teasers and any other views than the full node view.

What you need to do is implement hook_node_access_records() and hook_node_grants(). This will prevent both the menu items from being rendered, as well as prevent teasers and any other views being rendered, including views created by the Views module and any other modules.

Contact me to contract me for D7 -> D10/11 migrations.

onetwo’s picture

Ok after some trial&error I think that the concept is done. :)

Got one more question...

Like you suggested, the current solution uses hook_node_access_records() to write to the node_access table and hook_node_grants() to grant or deny access. However, solution might actually end up in a big commercial system with several thousands of nodes and users. This would create very large number of rows in the node_access table.

How much of an impact would this have on the system?

Once again, thanks for your help!

jaypan’s picture

It adds some overhead. But, databases are made to handle millions of records. That being said, if you get to the point of millions of nodes, you should be getting a server that can handle that. Drupal.org has over one million nodes now, and it runs off the same grant system (it's on D6), and stuff still works fine.

The reason that the grants system is used instead of hook_node_access() for access permissions is that it is less overhead on the system.

Contact me to contract me for D7 -> D10/11 migrations.

onetwo’s picture

That's a good news :)

Again, thanks for the help!