hook_menu($may_cache)
mactable - July 18, 2006 - 20:15
i have read the documents but i cannot fully understand what it for, could anyone explain this parameter in other words?
thx a lot!
i have read the documents but i cannot fully understand what it for, could anyone explain this parameter in other words?
thx a lot!
may_cache
I think alot of the confusion comes from the fact that the menu system controls both the traditional "menu" shown to users for navigation as well as the translation from almost any URL to working code.
To give an example - the path "node/2" points to my "About Us" page on my website. I added "node/2" to my Navigation Menu with the title "About Us" so that users can easily find it. The path "admin/modules" allows you to turn on/off modules. It is located in the Navigation Menu under administer/settings/modules. These are both STATIC menu items - the "path" will never change. Because the path will never change, they may be added to the Drupal caching system for faster processing.
Think about when you are editing a node for a minute. The path is "node/2/edit". This path brings up the web page to make changes to your node. The "2" could be replaced by any valid node number in the system and should still work. This is a DYNAMIC menu item - the "path" may change. Also note there is no link from the Navigation Menu to this path - there is a link from "node/2" to "node/2/edit" via a tab for those that are authorized to edit nodes. Becuase the path may change, the processing of these "menu items" cannot be cached.
I usually think of the hook_menu() as the following
if ($may_cache) {
put Navigation Menu items that the module is adding here
} else {
put general module functionality here
}
Hope that helps
@BoatDaddy million thx for
@BoatDaddy
million thx for your explanation, it helps me so much and made me more clear.
can cachable menu items can be variables?
It really clears out the issue a bit. This explanation should be included in the api documentation.
Here's a development of the issue:
Say I have a module that lists content by type. So I want to have few paths like:
http://example.com/types/story
http://example.com/types/page
http://example.com/types/content_x
Those will list all nodes of a certain type in a page (BTW - it's weird this functionality isn't already part of the core... it seem too easy to implement...)
Now - the hook_menu function could look like this:
<?phpfunction myFunctions_menu($may_cache) {
if ($may_cache) {
if (arg(0)=='types' && arg(1)){
$items[] = array('path' => 'types/'.arg(1),
'title' => t(check_plain(arg(1))),
'access' => user_access('access content'),
'callback' => myFunctions_types_page() );
}
}
return $items;
}
?>
The question is: Since each link will be fixed, but new content types can be added, is it possible to use the above definition, where the content type name is a variable, but still cached?
======================
Z.Stolar
http://drupal.org.il
http://linnovate.net
Only Static URLs Please
The menu caching system is probably one of the least understood but frequently programmed pieces of a Drupal module. You should rarely, if ever, include a variable in the path of menu item to be cached. The reason for this the cache system is only called once per visitor (all anonymous users share the same cache). The cache is built entirely upon the URL of the page the visitor first visits.
In your case, if the user were to visit 'http://example.com/types/story' as the first page of their visit, then 'story' would be cached for the menu item and subsequent calls to 'http://example.com/types/story' would be loaded from cache rather than on a per-request basis. All other calls to the 'http://example.com/types' directory are loaded normally, since they are not included in the cache at all.
For the sake of consistency, include all dynamic paths in a (!may_cache) block.
Now... there's also something else you should know about the menu system. If ONLY the last item in the path changes, then it is NOT considered a dynamic path and may be cached. For example:
'node/'.arg(1).'/subitem'Should NOT be cached'node/'Should be cachedThe rest of the path is automatically passed to the menu callback as individual arguments, no need to specify them. So in your example above your menu item would look like:
<?phpfunction myFunctions_menu($may_cache) {
if ($may_cache) {
$items[] = array('path' => 'types',
'title' => t('Types')),
'access' => user_access('access content'),
'callback' => 'myFunctions_types_page' );
}
return $items;
}
?>
Your callback function would then include
<?phpfunction myFunctions_types_page($type) {
// Preform checks on passed in arguments here instead of in the hook_menu function
if (!empty($type)) {
drupal_set_title($type);
return $type;
} else {
// Code to present a list of types?
}
}
?>
Even though you didn't pass any arguments to the callback function, the menu system automatically passes in the rest of the path as arguments. So a trip to 'http://example.com/types/story' would pass in 'story'. If you had multiple levels like 'http://example.com/types/story/list', then the first argument would be 'story' and the second would be 'list' and so on.
Nathan Haug
creative graphic design w: quicksketch.org
& software development e: nate@quicksketch.org
This was a wonderful explanation!
Thanks Nathan!
There's one thing I didn't understand fully:
If I do use
<?phpif ($may_cache) {
if (arg(0)=='types' && arg(1)){
$items[] = array('path' => 'types/'.arg(1),
...
);
}
}
?>
And a user goes first to 'http://example.com/types/story', what will happen when he surfs to 'http://example.com/types/page'?
Will Drupal go to the cache and find 'http://example.com/types/story'?
Will it not even search for it and return a page not found?
Or will the path 'http://example.com/types/page' get cached besides/instead of 'http://example.com/types/story'?
======================
Z.Stolar
http://drupal.org.il
http://linnovate.net
Well, I'm glad you asked!
So, what happens if you DO cache dynamic items anyway? In the example you presented, Drupal would try to find a menu item for the closest parent it knows of. So if you had a menu item for 'http://example.com/types', it would go there when you requested 'http://example.com/types/page', since Drupal doesn't have any idea where 'page' is, since it's not in the cache and it's not in the list of dynamic menu items.
To get even messier let's present a scenerio where a dynamic menu item can cause really strange problems. What if your hook_menu function looked like this:
<?phphook_menu ($may_cache) {
if (arg(0)=='types' && arg(1)){
$items[] = array('path' => 'types/'.arg(1),
...
);
}
}
?>
Okay, notice the LACK of an
if ($may_cache)block. What can happen here is the first time the page is called, Drupal builds the menu cache. Then, it goes through again and tries to find all the menu items that are not meant to be cached. Now it's found TWO menu items with the same name and menu path. So what happens? Sometimes it uses the the cached result, but sometimes it will not render the menu item at all! It just disappears from all menu lists and tabs, though you may still access it directly through the URL.So I hope that answers all your menu questions. I'm hoping to get this information posted in the handbook soon.
Nathan Haug
creative graphic design w: quicksketch.org
& software development e: nate@quicksketch.org
Yet another one!
Just when you thought things were all clear and no more lines are needed to explain this cahce stuff, here I go again with my questions, enriching your handbook entry...
When you say "dynamic menu item", does it have anything to do with the menu item's type MENU_DYNAMIC_ITEM ?
Is it the same thing?
Thanks again for a lovely explanation!
That was bad terminology on
That was bad terminology on my part. I was refering to any menu item with a variable in it's path, which can include all kinds of menus (MENU_CALLBACK, MENU_NORMAL_ITEM, MENU_LOCAL_TASK, etc). The specific menu type 'MENU_DYNAMIC_ITEM' means that (1) The item is present in a menu list, just like MENU_NORMAL_ITEM and (2) the position of this item changes so frequently, that there is no option for the administrator to customize the position of the item in 'admin/menu', since it moves around too much. You should always put MENU_DYNAMIC_ITEM's in the (!$may_cache) block.
Nathan Haug
creative graphic design w: quicksketch.org
& software development e: nate@quicksketch.org
Yet another one!
Just when you thought things were all clear and no more lines are needed to explain this cahce stuff, here I go again with my questions, enriching your handbook entry...
When you say "dynamic menu item", does it have anything to do with the menu item's type MENU_DYNAMIC_ITEM ?
Is it the same thing?
Thanks again for a lovely explanation!