2

I have added a MENU_LOCAL_TASK to a node. Within that local task I want to display an admin menu block using system_admin_menu_block_page() however I always get You do not have any administrative items. I have no trouble getting admin menu pages to work as MENU_NORMAL_ITEMS. Any ideas what I am doing wrong? Code below.

function my_module_menu() {
  $items = array();
  $items['node/%node/settings'] = array(
    'title' => 'Account settings',
    'description' => 'Manage your account settings.',
    'page callback' => 'system_admin_menu_block_page',
    'page arguments' => array(1),
    'access arguments' => array(1),
    'access callback' => 'my_module_access_account_settings',
    'type' => MENU_LOCAL_TASK,
    'file path' => drupal_get_path('module', 'system'),
    'file' => 'system.admin.inc',
    'weight' => 1000,
  );
  $items['node/%node/settings/upgrade'] = array(
    'title' => 'Upgrade your account',
    'description' => 'Use this form to upgrade your account.',
    'page callback' => 'my_module_upgrade_account',
    'page arguments' => array(1),
    'access arguments' => array(1),
    'access callback' => 'my_module_access_account_settings',
    'type' => MENU_NORMAL_ITEM,
  );
  $items['node/%node/settings/cancel'] = array(
    'title' => 'Cancel your account',
    'description' => 'Click here to cancel your account and remove all your data.',
    'page callback' => 'my_module_cancel_account',
    'page arguments' => array(1),
    'access arguments' => array(1),
    'access callback' => 'my_module_access_account_settings',
    'type' => MENU_NORMAL_ITEM,
  );
  return $items;
}

function my_module_access_account_settings($node) {
  if ($node->type == 'my_node_type') {
    return TRUE;
  }
  return FALSE;
}
2

After further investigation reading the code here, it appears that this can be done.

For example, admin/tasks has admin menu children in a MENU_LOCAL_TASK however, it appears that it looks at the current local task's parent item and then looks for MENU_NORMAL_ITEM children.

Unfortunately, this doesn't work in my case since I use wildcard urls (%node) and my local task is not the default one. (like the admin/tasks one is).

So I came up with a workaround function that achieves what I need.

The function my_module_account_settings($node) basically queries the DB for the current MENU_LOCAL_TASK's mlid, then queries the database for ALL menu links that have the current MENU_LOCAL_TASK's mlid as their parent.

I then call the theme function for admin_block_content and boom.

Let me know if anyone comes up with either a better, or more correct way of doing this.

function my_module_menu() {
  $items = array();
  $items['node/%node/settings'] = array(
    'title' => 'Account settings',
    'description' => 'Manage your account settings.',
    'page callback' => 'my_module_account_settings',
    'page arguments' => array(1),
    'access arguments' => array(1),
    'access callback' => 'my_module_access_account_settings',
    'type' => MENU_LOCAL_TASK,
    'weight' => 1000,
  );
  $items['node/%node/settings/upgrade'] = array(
    'title' => 'Upgrade your account',
    'description' => 'Use this form to upgrade your account.',
    'page callback' => 'my_module_upgrade_account',
    'page arguments' => array(1),
    'access arguments' => array(1),
    'access callback' => 'my_module_access_account_settings',
    'type' => MENU_NORMAL_ITEM,
  );
  $items['node/%node/settings/cancel'] = array(
    'title' => 'Cancel your account',
    'description' => 'Click here to cancel your account and remove all your data.',
    'page callback' => 'my_module_cancel_account',
    'page arguments' => array(1),
    'access arguments' => array(1),
    'access callback' => 'my_module_access_account_settings',
    'type' => MENU_NORMAL_ITEM,
  );
  return $items;
}

function my_module_account_settings($node) {
  $current =  menu_get_item();

  // get current MENU_LOCAL_TASK mlid
  $current_mlid = db_select('menu_links' , 'ml')
    ->condition('ml.link_path' , $current['path'])
    ->fields('ml' , array('mlid'))
    ->execute()->fetchField();

  // get all menu_links where the parent link id is the current 
  // MENU_LOCAL_TASK
  $rows = db_select('menu_links' , 'ml')
    ->condition('ml.plid' , $current_mlid)
    ->fields('ml' , array('mlid', 'link_path'))
    ->execute()->fetchAllKeyed();

  foreach ($rows as $mlid => $path) {
    // load each of the admin menu items within this local task
    // in my case i replace the placeholder/wildcard with the node nid
    $item = menu_get_item(str_replace('%', $node->nid, $path));
    if ($item['access']) {
      $items[] = $item;
    }
  }

  // return the themed block
  return theme('admin_block_content', array('content' => $items));
}

function my_module_access_account_settings($node) {
  if ($node->type == 'organisation') {
    if (user_access('edit org account settings')) {
      return TRUE;
    }
  }
  return FALSE;
}
  • 1
    The problem in system_admin_menu_block_page() is that for your menu item, if ($item['tab_root'] != $item['path']) { $item = menu_get_item($item['tab_root_href']); } is selecting the parent menu item of node/%/settings (node/%); as consequence of this, the value for mlid is not the value assigned to node/%/settings (your menu item). I tried setting $item['tab_root'], and $item['mlid'] in hook_menu(), but I was still getting the "You do not have any administrative items." message. Your code is probably the only solution. – kiamlaluno Jan 11 '13 at 12:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.