I am working on a module that allows authenticated users to store information in a node (for versioning and future expansion). By default, these nodes should not visible to other authenticated users (only to an administrative role). This is done via two module permissions "view own mynodetype" and "view any mynodetype". However, since most sites have "access content" permission set for the anonymous role, the "view" operation is never checked via hook_access() (because all roles have "view" permission for all nodes).
I know that the Content Access module (along with a few other modules) would allow finer control, but I would rather implement this directly in the module (to avoid unnecessary dependencies, and to keep things simple).
My solution thusfar has been to hide the custom fields via checks for "view own mynodetype" or "view any mynodetype" permissions in my module's hook_load() and hook_view(). This ensures that only users with proper permissions can see the custom node fields.
Example hook_load() -- if the user does not have permission, the custom fields will never even load into the node (this avoids any accidental passing of this data to other modules, views, etc.):
function example_load($node) {
// Did the currently logged in user create this content?
$is_author = $account->uid == $node->uid;
// Check for view access before loading.
if (!(user_access('view any mynodetype', $account) ||
(user_access('view own mynodetype', $account) && $is_author))) {
return NULL;
} else {
// Do normal db_fetch_object() stuff here and return the complete node
}
}
Example hook_view() -- if the user does not have permission, the custom fields will never be sent for view theming (this avoids any accidental passing of this data via theme templates or functions):
function example_view($node,$teaser = FALSE, $page = FALSE) {
// Did the currently logged in user create this content?
$is_author = $account->uid == $node->uid;
$node = node_prepare($node,$teaser); // Prepare for display
// Check for view access before displaying.
if (!(user_access('view any mynodetype', $account) ||
(user_access('view own mynodetype', $account) && $is_author))) {
$node->content['example_view'] = array(
'#value' => 'You are not authorized to access this content.',
'#weight' => -1,
);
} else {
// Do normal field cleaning, and $node->content[] building here...
}
return $node;
}
This method successfully hides the custom fields. However, it would be better if there were a way to completely hide these nodes entirely, not just the custom fields (as if they were unpublished).
Does anyone have any suggestions on how to implement this? Or should I break down and either depend on Content Access, or not make this content a node at all?
Thank you,
Eric
Comments
hook_access
is there a reason not to use hook_access?
I misunderstood...
It was my understanding that hook_access() is not called for a node "view" operation if the role has "access content" permission. This is NOT the case. The "view" operation can be tested via hook_access() regardless.
So long as the module's hook_access() implementation specifically returns FALSE for the operation, it works as expected.
hook_access 'view'
I'm having the same problem. I implemented hook_access to deny viewing my custom nodes under certain condition (i.e. hook_access('view', $node) returns false under these conditions. This works if the user tries to open such a node. However, these nodes are displayed on my home page (recent posts?) as the viewing permissions are not checked in that case. This seems to be a bug in drupal 6.
I can hide the recent posts from the home page, but I'm worrying that they can be found via the search function or some other way.
Any ideas?
I could modify hook_load so that the private info is not displayed and I may end up doing that if I can't find a better solution.
Thanks.
You take care of this by
You take care of this by implementing hook_node_access_records() and hook_node_grants().
Contact me to contract me for D7 -> D10/11 migrations.