menu access callback per role I'm trying to implement an access callback per role for a specific menu item, but other roles can view that menu item also. Any tip is welcome.

/**
 * Implements hook_menu();
 */
function MODULENAME_menu() {

  global $user;

  $items['admin/backoffice/production/taxonomie'] = array(
    'title' =&gt; 'Taxonomie',
    'type' =&gt; MENU_LOCAL_TASK,
    'weight' =&gt; 0,
    'page callback' =&gt; 'MODULENAME_backoff_taxonomy',
    'access callback' =&gt; 'MODULENAME_user_has_role',   
    'access arguments' =&gt;  array($user, array('éditeur taxonomie', 'administrator')),
    );

  return $items;
}

function MODULENAME_backoff_taxonomy(){
  module_load_include('inc', 'taxonomy', 'taxonomy.admin');
  $form = drupal_get_form('taxonomy_overview_vocabularies');
  drupal_set_title('Backoffice - Taxonomie');
  return drupal_render($form);
}

function MODULENAME_user_has_role($user,$roles) { 
  foreach ($roles as $role) {
    if (in_array($role, $user-&gt;roles)) {
      return TRUE;
    }
  }
  return FALSE; 
}
To have a single access callback handle a dynamic number of roles which varies per menu link, try something like this in hook_menu()...

// hook_menu()
$items['foo'] = array(
  /* ... */
  'access callback' =&gt; 'MODULENAME_user_has_role',   
  'access arguments' =&gt;  array('éditeur taxonomie', 'administrator'),
);
$items['bar'] = array(
  /* ... */
  'access callback' =&gt; 'MODULENAME_user_has_role',   
  'access arguments' =&gt;  array('some other role'),
);


Then your access callback implementation:

function MODULENAME_user_has_role() { 
  global $user;
  $roles = func_get_args();
  foreach ($roles as $role) {
    if (in_array($role, $user-&gt;roles)) {
      return TRUE;
    }
  }
  return FALSE; 
}


That should do it.

Some alternatives

Remove the global $user and access arguments from hook_menu().

Then change your access callback function implementation to this:

function MODULENAME_user_has_role() { 
  global $user;
  $roles = array('éditeur taxonomie', 'administrator');
  foreach ($roles as $role) {
    if (in_array($role, $user-&gt;roles)) {
      return TRUE;
    }
  }
  return FALSE; 
}


Since hook_menu() is invoked only when the menu router is being rebuilt (e.g. a cache clear, typically done by an admin or drush), global $user is not usually very useful from within that function. Instead, an access callback function is invoked at a more appropriate time (i.e. when the page is being viewed, or a menu link is about to be shown [or not] in a menu), at this point it is much easier to make a decision about the current user's context.

To make the access callback more generic, and be able to handle multiple menu link paths, I'll typically use a switch/case on an arg() to further curate the context:

switch (arg(3)) {
  case 'taxonomie':
    // do stuff...
    break;
}