I've searched around the issues but didn't find anything.
This sounds weird, but my hook_menu is only being called with !$may_cache !! How is it possible?

I've checked again and again, refreshed the cache_menu table, revisited admin/build/menu... nothing. My hook_menu is simply not being passed TRUE in $may_cache.

Here's my hook_menu, very simple (using Drupal 5.1):

<?php
function takeit_menu($may_cache){
  $items = array();
  // I've watchdoged here - only got results for !$may_cache
  if($may_cache){
    // I've watchdoged here - no results!
    if(arg(0)=='takeit' && is_numeric(arg(1))){
      $items[] = array(
        'path'=>'takeit',
        'title'=>t('Take Thread'),
        'callback'=>'takeit_take_thread',
        'access'=>TRUE,
        'type'=>MENU_CALLBACK
      );
    }
  }
  return $items;
}

?>

Comments

webchick’s picture

Category: bug » support
Status: Active » Closed (works as designed)

This is by design.

$may_cache == TRUE is for static menu items, such as 'admin/settings/foo'. These paths are predictable and always point to the same place, so they are stored in the menu_cache table. The only time code in a $may_cache block is run is when a menu_rebuild() is executed, which is when new modules are enabled/disabled and after the cache is cleared.

$may_cache == FALSE is for dynamic menu items, such as 'user/1/edit'. Because you don't know ahead of time which path you'll actually be looking at, you stick these in a if (!$may_cache) so they check the current page and determine whether they need to activate or not.

Because your path is dymanic (takeit/[some number]), it belongs in a (!$may_cache) block.

z.stolar’s picture

So maybe the documentation is wrong? Here's a quote from http://api.drupal.org/api/5/function/hook_menu :

Drupal will call this hook twice: once with $may_cache set to TRUE, and once with it set to FALSE.

I understand from this line that each module that implements hook_menu, will get visited twice during a page load.
But it doesn't.

In the code above, the path is not dynamic. it is 'path'=>'takeit', I only do a check, to verify I'm looking at the right page, so the path won't be declared where it is not needed. I understand this might be a mistake, since cached items are always present, regardless of the current url.

However, I also mentioned I erased the cache, and visited admin/build/menu, and nothing helped - my hook was not called with $may_cache == TRUE (notice the watchdog position), that's why I suspect it's a bug, and not the usual behavior of Drupal.

I should put some watchdogs elsewhere to see what happens in other modules. This would be smarter than just shouting Drupal is broken. I'll report my findings here.

jjweiner’s picture

I wonder if the "if" statement is causing the problem:

<?php
if(arg(0)=='takeit' && is_numeric(arg(1))){
?>

Perhaps a work-around is to put the business logic in the "takeit_take_thread" function and pass it arg(1):

<?php
function takeit_menu($may_cache){
  $items = array();
 
  if($may_cache){
      $items[] = array(
        'path'=>'takeit',
        'title'=>t('Take Thread'),
        'callback'=>'takeit_take_thread',
        'callback arguments' => array(arg(1)),
        'access'=>TRUE,
        'type'=>MENU_CALLBACK
      );
  }
  return $items;
}
?>

Then the function could determine if arg(1) is numeric:

<?php
function takeit_take_thread($arg = NULL){

if (is_numeric($arg))){
   //do something
  }
}
?>
nevets’s picture

hook_menu is only called with $may_cache set to TRUE when a module is enabled or the admin page for menu is visited. During a page load $may_cache is always false.

jjweiner’s picture

If you empty the cache (I usually do this with the devel module) if should force the menu $items array to reload when $may_cache is TRUE.