background image
Eric's picture

I've been working on an intranet site that needed to have typical intranet permissions: unauthenticated users can see a handful of pages and the rest of the nodes are only visible to authenticated users. Instead of having the user specify permissions for every page, I figured it would be more usable to have them specify a list of pages available to unauth users.

I created an admin settings page callback to generate the form with a single textarea input. Users will enter a list of URLs in the textarea, one per line:

<?php
function MYMODULE_menu() {
 
$items = array();

 
$items['admin/settings/MYMODULE'] = array(
   
'title' => 'MYMODULE Settings',
   
'page callback' => 'drupal_get_form',
   
'page arguments' => array('_MYMODULE_callback_admin_settings'),
   
'type' => MENU_NORMAL_ITEM,
   
'access arguments' => array('administer site configuration'),
  );

  return
$items;
}

function
_MYMODULE_callback_admin_settings() {
 
$form = array();

 
$form['MYMODULE_unauth_pages'] = array(
   
'#type' => 'textarea',
   
'#title' => 'Unauth Pages',
   
'#default_value' => variable_get('MYMODULE_unauth_pages',''),
  );
   
  return
system_settings_form($form);
}
?>

For this example, I entered the following URLs in the textarea:

<front>
about-us
contact-us

I then added a menu_alter hook function to override the access control for viewing nodes:

<?php
function MYMODULE_menu_alter(&$items) {
 
// per unauth pages, replace the callback function
 
if (function_exists('_MYMODULE_node_access')) {
   
// note: access callback function was previously: node_access
   
$items['node/%node']['access callback'] = '_MYMODULE_node_access';
  }
}
?>

And, then added a new access control function:

<?php
function _MYMODULE_node_access($op, $node) {

 
// check if user is unauth
 
if (in_array('anonymous user', array_values($GLOBALS['user']->roles))) {

   
// get a list of unauth pages
   
$unauth = variable_get('MYMODULE_unauth_pages','');
   
$unauth = explode("\r\n", trim($unauth));
       
   
// replace <front> with empty string
   
if (in_array('<front>', $unauth)) {
     
$unauth[array_search('<front>',$unauth)] = '';
    }
       
   
// check for unauth entries
   
if (is_array($unauth) && count($unauth)) {
     
// check if current url is allowed
     
if (!in_array($_REQUEST['q'], $unauth)) {
        return
false;
      }           
    }
  }
   
 
// default to node_access function result
 
return node_access($op, $node);
   
}
?>

Now, unauth users have access ONLY to the pages you define and the rest of the node viewing permissions default to the node_access function.

Missing Arguments

I could be missing a trick here, but when I run this code, I receive no argument passed to the callback warnings.

Eric's picture

which

which callback & argument?

Great Module

This is great. I need to limit node access but didn't want to use a "full blown" node access module either. Thanks for posting this.

An unrelated side question: For your blog, what is your method for displaying your PHP code in such a readable, code-colored format? I'd love to start using this on my own blog.

-Mark W. Jarrell (attheshow)

Eric's picture

thanks

Thanks Mark. I use the Code Filter module: http://drupal.org/project/codefilter

Awesome. Thanks for the tip.

Awesome. Thanks for the tip. Both this and the post are extremely valuable to me.

I'm having a problem in my

I'm having a problem in my _MYMODULE_node_access function where if I'm logged in with an administrator account, everything appears as expected. But, if I'm in with a non-administrator level account, the $node object appears to be empty. Any ideas what might be causing this?

Eric's picture

permissions

What permissions does your non-admin account have assigned related to processing nodes?