I've been struggling with an issue for the past few days that I'm hoping someone can give me insight on.

Using MENU_LOCAL_TASK, I've created a module that defines a custom tab that appears when viewing my "project" node. I've used my module in combination with CCK, OG, Panels, and Views to create a project management site. I've had no trouble implementing tabs or sub-tabs, so everything appeared to be working correctly.

The problem is that every so often my custom tab disappears when viewing the "project" node. It appears to happen randomly, so it's difficult to troubleshoot.

I can still access the contents if I type it's URL (e.g. '/node/40/status') and it will show the tab by itself with all it's sub-tabs. But it doesn't show along side the other tabs of the node when going to (e.g. '/node/40'). What's even more weird is that I have some Views that define their own tabs ("Discussion" and "Messages") for that node and they appear as normal. It's as if my tab has been disassociated from the node.
Example:
Tabs before = View, Edit, Project Status, Discussion, Messages, Broadcast
Tabs after = View, Edit, Discussion, Messages, Broadcast

It doesn't do it to every node at the same time either. So for some nodes the tab will disappear and for others it won't. It happens most frequently for non-root users, but it happens when logged in as root as well. Also, it doesn't happen to every user at the same time either. One user will experience the missing tab, while another will not.

The tab will usually reappear if I uninstalled and reinstalled my module OR disable and enable one of the associated modules OR sometimes it will just randomly reappear. Though these methods work for development, I need to find a solution.

I've compared my code to other modules for how I've implemented the tabs, and I'm not seeing a difference. Below is an example:

<?php
if (arg(0) == "node" && is_numeric(arg(1))) {
   
$node = node_load(arg(1));
    if (
$node->type == "ecpm_project") {
      
$items[] = array(
       
'path' => 'node/'. arg(1) .'/status',
       
'title' => t('Project Status'),
       
'callback' => 'ecpm_summary',        
       
'access' => user_access('view project status'),
       
'weight' => 1,
       
'type' => MENU_LOCAL_TASK,
       );
     
$items[] = array(
       
'path' => 'node/'. arg(1) .'/status/edit',
       
'callback' => 'ecpm_summary',
       
'title' => 'Status Summary',                                   
       
'access' => user_access('view project status'),
       
'weight' => -10,               
       
'type' => MENU_DEFAULT_LOCAL_TASK,
      );
     
$items[] = array(
       
'path' => 'node/'. arg(1) .'/status/prework',
       
'title' => t('Pre-Work'),       
       
'callback' => 'ecpm_prework',                 
       
'access' => user_access('view project status'),
       
'weight' => -5,
       
'type' => MENU_LOCAL_TASK,
      );
    }
}
?>

Does anyone have any idea what the problem could be? I've read everything I can find and tried everything I can think of to solve the problem, but I've had ZERO luck.

I hope I've explained this thoroughly enough. Please let me know if I need to add more detail.
I'm starting to reach my deadline and the pressure is on, so any help is appreciated! Thank you.

Comments

tonyp001’s picture

Could this be an issue with the Drupal 5 menu system?
I'm considering upgrading to to D6 just to see what happens. It would be a lot of work, so I want to make sure it can't work in D5 first.
Does anyone have any thoughts?
Thanks.

John Morahan’s picture

Sorry to ask the obvious question but since you don't mention it, and it's not clear from the example you pasted: did you remember to put that piece of code in the !$may_cache section of your D5 hook_menu() implementation? i.e.

<?php
function mymodule_menu($may_cache) {
 
$items = array();
  if (
$may_cache) {
   
// do cached stuff
 
}
  else {
   
// Dynamic stuff (e.g. most local tasks) should go here
 
}
  return
$items;
}
?>
tonyp001’s picture

I did. I appreciate the feedback though.

I found out something interesting yesterday while troubleshooting. I use my custom tab in conjunction with an organic group node and my groups use the OG User Roles module. If I assign a user with a role that can manage OG User Roles for that group, and the tab disappears for that user, I can consistently make it reappear by having that user remove any roles assigned to it in that group. But it only happens if the user does this to themselves. If I log in a as root and do it, nothing happens.

It's not much of a solution because the tab disappears again fter a minute or two of use. It made me think that perhaps OG User Roles was causing the issue, but I disabled the module and the tabs never restored. Out of curiosity, I checked the function that OG User Roles calls for removing roles for anything significant, but I couldn't find much. Though it did call menu_rebuild(), so I tried calling the function to see if it would restore the tab, but it didn't. Even if it did, again, it wouldn't be much of a solution.

Weird, I know. You can see why I've been pulling my hair out for the past few days.

John Morahan’s picture

OGUR does some weird things indeed but if you disable it and the problem remains, then it's probably not to blame.

Can you paste in your full hook_menu implementation?

tonyp001’s picture

As requested (comments below):

<?php
/**
 * Implementation of hook_menu().
 */
function ecpm_menu() {
 
$items = array();

  if (
$may_cache) {
   
$items[] = array(
       
'path' => 'node/add/ecpm-project',
       
'title' => t('eCPM Project'),    
       
'access' => user_access('create ecpm project'),     
    ); 
  }
  else {
     
$items[] = array(
       
'path' => 'node/'. arg(1) .'/rebuild',
       
'title' => t('Rebuild Menu'),
       
'callback' => 'ecpm_menu_rebuild',
       
'access' => TRUE,     
       
'type' => MENU_CALLBACK,
    );
     
$items[] = array(
       
'path' => 'ecpm/user/autocomplete',
       
'title' => t('eCPM User autocomplete'),
       
'callback' => 'ecpm_user_autocomplete',
       
'access' => user_access('access user profiles'),     
       
'type' => MENU_CALLBACK,
    );
   
$items[] = array(
       
'path' => 'node/'. arg(1) .'/more/'. arg(1),
       
'title' => ecpm_get_title(arg(1)) . ' - About',       
       
'callback' => 'ecpm_more',                 
       
'access' => array('access content'),
       
'type' => MENU_CALLBACK,
    );
     
//Provide Tabs only for eCPM project
     
if (arg(0) == "node" && is_numeric(arg(1))) {
       
$node = node_load(arg(1));
        if (
$node->type == "ecpm_project") {
           
/*************TRACK*****************/
           
$items[] = array(
               
'path' => 'node/'. arg(1) .'/status',
               
'title' => t('Project Status'),
               
'callback' => 'ecpm_summary',        
               
'access' => TRUE,
               
'weight' => 1,
               
'type' => MENU_LOCAL_TASK,
            );
           
$items[] = array(
               
'path' => 'node/'. arg(1) .'/status/edit',
               
'callback' => 'ecpm_summary',
               
'title' => 'Status Summary',                                   
               
'access' => TRUE,
               
'weight' => -10,               
               
'type' => MENU_DEFAULT_LOCAL_TASK,
            );
           
$items[] = array(
               
'path' => 'node/'. arg(1) .'/status/prework',
               
'title' => t('Pre-Work'),       
               
'callback' => 'ecpm_prework',                 
               
'access' => TRUE,
               
'weight' => -5,
               
'type' => MENU_LOCAL_TASK,
            );
           
$items[] = array(
               
'path' => 'node/'. arg(1) .'/status/prework/'. arg(4),
               
'title' => t('View Pre-Work Task'),       
               
'callback' => 'ecpm_tasks',                 
               
'access' => TRUE,
               
'weight' => -5,
               
'type' => MENU_LOCAL_TASK,
            );
           
$items[] = array(
               
'path' => 'node/'. arg(1) .'/status/conceptualize',
               
'title' => t('Conceptualize'),       
               
'callback' => 'ecpm_conceptualize',                 
               
'access' => TRUE,
               
'weight' => -4,
               
'type' => MENU_LOCAL_TASK,
            );
           
$items[] = array(
               
'path' => 'node/'. arg(1) .'/status/conceptualize/'. arg(4),
               
'title' => t('View Conceptualize Task'),       
               
'callback' => 'ecpm_tasks',                 
               
'access' => TRUE,
               
'weight' => -5,
               
'type' => MENU_LOCAL_TASK,
            );
           
$items[] = array(
               
'path' => 'node/'. arg(1) .'/status/design',
               
'title' => t('Design & Build'),       
               
'callback' => 'ecpm_design',                 
               
'access' => TRUE,
               
'weight' => -3,
               
'type' => MENU_LOCAL_TASK,
            );
           
$items[] = array(
               
'path' => 'node/'. arg(1) .'/status/design/'. arg(4),
               
'title' => t('View Design & Build Task'),       
               
'callback' => 'ecpm_tasks',                 
               
'access' => TRUE,
               
'weight' => -5,
               
'type' => MENU_LOCAL_TASK,
            );
           
$items[] = array(
               
'path' => 'node/'. arg(1) .'/status/test',
               
'title' => t('Test'),       
               
'callback' => 'ecpm_test',                 
               
'access' => TRUE,
               
'weight' => -2,
               
'type' => MENU_LOCAL_TASK,
            );
           
$items[] = array(
               
'path' => 'node/'. arg(1) .'/status/test/'. arg(4),
               
'title' => t('View Test Task'),       
               
'callback' => 'ecpm_tasks',                 
               
'access' => TRUE,
               
'weight' => -5,
               
'type' => MENU_LOCAL_TASK,
            );
           
$items[] = array(
               
'path' => 'node/'. arg(1) .'/status/release',
               
'title' => t('Release & Transition'),       
               
'callback' => 'ecpm_release',                 
               
'access' => TRUE,
               
'weight' => -1,              
               
'type' => MENU_LOCAL_TASK,
            );
           
$items[] = array(
               
'path' => 'node/'. arg(1) .'/status/release/'. arg(4),
               
'title' => t('View Release & Transition Task'),       
               
'callback' => 'ecpm_tasks',                 
               
'access' => TRUE,
               
'weight' => -5,
               
'type' => MENU_LOCAL_TASK,
            );
           
/*************EDIT STATUS***************/
           
$items[] = array(
               
'path' => 'node/'. arg(1) .'/status/edit/'.arg(4),
               
'callback' => 'drupal_get_form',
               
'title' => 'Task Edit',
               
'callback arguments' => array('ecpm_task_form'),                   
               
'access' => user_access('update project status'),               
               
'type' => MENU_LOCAL_TASK,
            );
        }
    }     
  }

  return
$items;
}
?>

The one thing I do here that could be considered questionable is I push the tabs to a third level that I know Drupal doesn't render (e.g. "node/'. arg(1) .'/status/edit/'.arg(4)"). I did this because I wanted to associate the content underneath it to it's parent for easy navigation. I suspected this of causing an issue, but when I removed all child tabs and left just one, it still disappeared.

John Morahan’s picture

The if/else is correct but where's the $may_cache parameter to ecpm_menu()?

tonyp001’s picture

I mean I really can't believe it! I feel like such a Drupal noob. I can't tell you how may times I must have looked at other people's code trying to figure out the difference. All it takes sometimes is a second pair of eyes (which I desperately need).
Well anyway, that fixed it.
Thanks for the help!!!