I've to dynamically generate the menu and I've the feeling that just adding items in menu_hook and trial&error won't take me far reasonably efficiently.
eg. I'm interested in obtaining effects similar to "Login" turning into "My account" even for menu created from the admin interface.
I'm reading drupal source but I'd hope there is a faster way to get the rough picture and some examples.
thanks
what u want here,...
On Mon, Jul 28, 2008 at 3:47 PM, Ivan Sergio Borgonovo <mail@webthatworks.it
wrote:
I've to dynamically generate the menu and I've the feeling that just adding items in menu_hook and trial&error won't take me far reasonably efficiently.
eg. I'm interested in obtaining effects similar to "Login" turning into "My account" even for menu created from the admin interface.
I'm reading drupal source but I'd hope there is a faster way to get the rough picture and some examples.
thanks
-- Ivan Sergio Borgonovo http://www.webthatworks.it
-- [ Drupal support list | http://lists.drupal.org/ ]
For your example, this is not a switch, but 2 modules with differents ACL. The block 'login' is displayed for 'Anonymous' and the menu is displayed for 'Authenticated user' (block Navigation).
For the element's visibility in the menu, this is with the user_access method defined in the function 'hook_menu' for each module.
Florent JOUSSEAUME,
Ivan Sergio Borgonovo a écrit :
I've to dynamically generate the menu and I've the feeling that just adding items in menu_hook and trial&error won't take me far reasonably efficiently.
eg. I'm interested in obtaining effects similar to "Login" turning into "My account" even for menu created from the admin interface.
I'm reading drupal source but I'd hope there is a faster way to get the rough picture and some examples.
thanks
This is one way, (and in fact the only way in D6).
It's important to understand in D5 and before that the truly dynamic menus must be in the if (!$may_cache) section of hook menu.
In D5 this is possible: function mymodule_menu($may_cache) { if ($may_cache ) { $items[] = array(....... Normal static menus go here } else { if (some conditional logic here) { $items[] = array (.... } $items = array( path => path_generated_by_func ) } }
But it isn't possible in drupal 6, so not really advised. In d6:
function (mymodule_menu) { $menu['path/to/menu'] = array( ..... Other menu items ommited for clarity. 'access callback' => 'mymodule_function', 'access arguments' => array( 'myarg1') ) }
function (mymodule_menu) { .... Function that returns false or tru based on whether the menu should show up .... }
-----Original Message----- From: support-bounces@drupal.org [mailto:support-bounces@drupal.org] On Behalf Of Florent JOUSSEAUME Sent: Monday, July 28, 2008 7:08 AM To: support@drupal.org Subject: Re: [support] tutorial on dynamically generating menu in D5
For your example, this is not a switch, but 2 modules with differents ACL. The block 'login' is displayed for 'Anonymous' and the menu is displayed for 'Authenticated user' (block Navigation).
For the element's visibility in the menu, this is with the user_access method defined in the function 'hook_menu' for each module.
Florent JOUSSEAUME,
Ivan Sergio Borgonovo a écrit :
I've to dynamically generate the menu and I've the feeling that just adding items in menu_hook and trial&error won't take me far reasonably efficiently.
eg. I'm interested in obtaining effects similar to "Login" turning into "My account" even for menu created from the admin interface.
I'm reading drupal source but I'd hope there is a faster way to get the rough picture and some examples.
thanks
-- [ Drupal support list | http://lists.drupal.org/ ]
On Mon, 28 Jul 2008 16:07:50 +0200 Florent JOUSSEAUME florent.jousseaume@makina-corpus.com wrote:
For your example, this is not a switch, but 2 modules with differents ACL. The block 'login' is displayed for 'Anonymous' and the menu is displayed for 'Authenticated user' (block Navigation).
For the element's visibility in the menu, this is with the user_access method defined in the function 'hook_menu' for each module.
It looks a bit hakish. And I still can't get it completely.
1) path user points to user_login if(uid) otherwise it should point to something else... but what is the alternative? In user_menu all paths are user/[something else] or admin/user/... I can't understand why once the user is logged in and the path user/[uid] becomes available the path /user reaches user_view
2) I can't yet understand the magic that make -My account appear in the Menu admin pages as locked. I still haven't had the time to read the code.
3) I miss how I can *render* menu with the admin interface and/or in modules. I'd expect that if I build up a $items hierarchy I could build up a menu from the "admin" interface adding a path and the menu system will take care of rendering children once I eg. put the menu in a block. What if I'd like to render the menu inside my code? I think I should use menu_tree... but well I bet there are a lot of tricks I could learn without guessing them from the API.
4) I haven't seen any tutorial, handbook... on any of the menu_ family of function. There is nothing on "Pro Drupal development" book.
thanks
The reason that these menus is because a.) they appear in the if (!$may_cache) section of the hook_menu and b.) thay are wrapped in an if ($user !== FALSE) condition.
Note that there is also a separate /user path registered in the if ($may_cache) section of the hook_menu. This is the "default" path for /user and what shows up in the admin/menu screen.
You may be grappling with one of the core troubles with Drupal 5. Only menus that are in the if ($may_cache) section of the module may be moved around with the admin/menu user interface. If it's a dynamic menu, you just don't see it there. So if you make a dynamic menu item, you can't turn around and move it into a block. Although you may be able to move a the static parent menu item (defined in the if ($may_cache) section of the menu into a separate menu and menu block. This took me a little time to grok.
Finally you can't have the code define a new menu, but only create a menu tree section in code and then move it later using the admin menu interface.
Is that clearing any of this up for you?
Here's the relavent chunk of user_menu code for understanding. if ($may_cache) { $items[] = array('path' => 'user', 'title' => t('User account'), 'callback' => 'drupal_get_form', 'callback arguments' => array('user_login'), 'access' => !$user->uid, 'type' => MENU_CALLBACK);
$items[] = array('path' => 'user/autocomplete', 'title' => t('User autocomplete'), 'callback' => 'user_autocomplete', 'access' => $view_access, 'type' => MENU_CALLBACK); ... Bunch of code ommitted....
} else { ... Some code ommitted. if ($user !== FALSE) { // Always let a user view their own account $view_access |= $user->uid == arg(1); // Only admins can view blocked accounts $view_access &= $account->status || $admin_access;
$items[] = array('path' => 'user/'. arg(1), 'title' => t('User'), 'type' => MENU_CALLBACK, 'callback' => 'user_view', 'callback arguments' => array(arg(1)), 'access' => $view_access);
$items[] = array('path' => 'user/'. arg(1) .'/view', 'title' => t('View'), 'access' => $view_access, 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10);
$items[] = array('path' => 'user/'. arg(1) .'/edit', 'title' => t('Edit'), 'callback' => 'drupal_get_form', 'callback arguments' => array('user_edit'), 'access' => $admin_access || $user->uid == arg(1), 'type' => MENU_LOCAL_TASK); $items[] = array('path' => 'user/'. arg(1) .'/delete', 'title' => t('Delete'), 'callback' => 'user_edit', 'access' => $admin_access, 'type' => MENU_CALLBACK);
if (arg(2) == 'edit') { if (($categories = _user_categories($account)) && (count($categories) > 1)) { foreach ($categories as $key => $category) { $items[] = array( 'path' => 'user/'. arg(1) .'/edit/'. $category['name'], 'title' => $category['title'], 'type' => $category['name'] == 'account' ? MENU_DEFAULT_LOCAL_TASK : MENU_LOCAL_TASK, 'weight' => $category['weight'], 'access' => ($admin_access || $user->uid == arg(1))); } } } } } -----Original Message----- From: support-bounces@drupal.org [mailto:support-bounces@drupal.org] On Behalf Of Ivan Sergio Borgonovo Sent: Monday, July 28, 2008 8:43 AM To: support@drupal.org Subject: Re: [support] tutorial on dynamically generating menu in D5
On Mon, 28 Jul 2008 16:07:50 +0200 Florent JOUSSEAUME florent.jousseaume@makina-corpus.com wrote:
For your example, this is not a switch, but 2 modules with differents ACL. The block 'login' is displayed for 'Anonymous' and the menu is displayed for 'Authenticated user' (block Navigation).
For the element's visibility in the menu, this is with the user_access
method defined in the function 'hook_menu' for each module.
It looks a bit hakish. And I still can't get it completely.
1) path user points to user_login if(uid) otherwise it should point to something else... but what is the alternative? In user_menu all paths are user/[something else] or admin/user/... I can't understand why once the user is logged in and the path user/[uid] becomes available the path /user reaches user_view
2) I can't yet understand the magic that make -My account appear in the Menu admin pages as locked. I still haven't had the time to read the code.
3) I miss how I can *render* menu with the admin interface and/or in modules. I'd expect that if I build up a $items hierarchy I could build up a menu from the "admin" interface adding a path and the menu system will take care of rendering children once I eg. put the menu in a block. What if I'd like to render the menu inside my code? I think I should use menu_tree... but well I bet there are a lot of tricks I could learn without guessing them from the API.
4) I haven't seen any tutorial, handbook... on any of the menu_ family of function. There is nothing on "Pro Drupal development" book.
thanks
-- Ivan Sergio Borgonovo http://www.webthatworks.it
-- [ Drupal support list | http://lists.drupal.org/ ]
I thing This code enough for u,
Just copy this module into your site/module....
On Mon, Jul 28, 2008 at 10:46 PM, Metzler, David metzlerd@evergreen.eduwrote:
The reason that these menus is because a.) they appear in the if (!$may_cache) section of the hook_menu and b.) thay are wrapped in an if ($user !== FALSE) condition.
Note that there is also a separate /user path registered in the if ($may_cache) section of the hook_menu. This is the "default" path for /user and what shows up in the admin/menu screen.
You may be grappling with one of the core troubles with Drupal 5. Only menus that are in the if ($may_cache) section of the module may be moved around with the admin/menu user interface. If it's a dynamic menu, you just don't see it there. So if you make a dynamic menu item, you can't turn around and move it into a block. Although you may be able to move a the static parent menu item (defined in the if ($may_cache) section of the menu into a separate menu and menu block. This took me a little time to grok.
Finally you can't have the code define a new menu, but only create a menu tree section in code and then move it later using the admin menu interface.
Is that clearing any of this up for you?
Here's the relavent chunk of user_menu code for understanding. if ($may_cache) { $items[] = array('path' => 'user', 'title' => t('User account'), 'callback' => 'drupal_get_form', 'callback arguments' => array('user_login'), 'access' => !$user->uid, 'type' => MENU_CALLBACK);
$items[] = array('path' => 'user/autocomplete', 'title' => t('User autocomplete'), 'callback' => 'user_autocomplete', 'access' => $view_access, 'type' => MENU_CALLBACK); ... Bunch of code ommitted....
} else { ... Some code ommitted. if ($user !== FALSE) { // Always let a user view their own account $view_access |= $user->uid == arg(1); // Only admins can view blocked accounts $view_access &= $account->status || $admin_access;
$items[] = array('path' => 'user/'. arg(1), 'title' =>t('User'), 'type' => MENU_CALLBACK, 'callback' => 'user_view', 'callback arguments' => array(arg(1)), 'access' => $view_access);
$items[] = array('path' => 'user/'. arg(1) .'/view', 'title' =>t('View'), 'access' => $view_access, 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10);
$items[] = array('path' => 'user/'. arg(1) .'/edit', 'title' =>t('Edit'), 'callback' => 'drupal_get_form', 'callback arguments' => array('user_edit'), 'access' => $admin_access || $user->uid == arg(1), 'type' => MENU_LOCAL_TASK); $items[] = array('path' => 'user/'. arg(1) .'/delete', 'title' => t('Delete'), 'callback' => 'user_edit', 'access' => $admin_access, 'type' => MENU_CALLBACK);
if (arg(2) == 'edit') { if (($categories = _user_categories($account)) &&(count($categories) > 1)) { foreach ($categories as $key => $category) { $items[] = array( 'path' => 'user/'. arg(1) .'/edit/'. $category['name'], 'title' => $category['title'], 'type' => $category['name'] == 'account' ? MENU_DEFAULT_LOCAL_TASK : MENU_LOCAL_TASK, 'weight' => $category['weight'], 'access' => ($admin_access || $user->uid == arg(1))); } } } } } -----Original Message----- From: support-bounces@drupal.org [mailto:support-bounces@drupal.org] On Behalf Of Ivan Sergio Borgonovo Sent: Monday, July 28, 2008 8:43 AM To: support@drupal.org Subject: Re: [support] tutorial on dynamically generating menu in D5
On Mon, 28 Jul 2008 16:07:50 +0200 Florent JOUSSEAUME florent.jousseaume@makina-corpus.com wrote:
For your example, this is not a switch, but 2 modules with differents ACL. The block 'login' is displayed for 'Anonymous' and the menu is displayed for 'Authenticated user' (block Navigation).
For the element's visibility in the menu, this is with the user_access
method defined in the function 'hook_menu' for each module.
It looks a bit hakish. And I still can't get it completely.
path user points to user_login if(uid) otherwise it should point to something else... but what is the alternative? In user_menu all paths are user/[something else] or admin/user/... I can't understand why once the user is logged in and the path user/[uid] becomes available the path /user reaches user_view
I can't yet understand the magic that make -My account appear in the Menu admin pages as locked. I still haven't had the time to read the code.
I miss how I can *render* menu with the admin interface and/or in modules. I'd expect that if I build up a $items hierarchy I could build up a menu from the "admin" interface adding a path and the menu system will take care of rendering children once I eg. put the menu in a block. What if I'd like to render the menu inside my code? I think I should use menu_tree... but well I bet there are a lot of tricks I could learn without guessing them from the API.
- I haven't seen any tutorial, handbook... on any of the menu_ family
of function. There is nothing on "Pro Drupal development" book.
thanks
-- Ivan Sergio Borgonovo http://www.webthatworks.it
-- [ Drupal support list | http://lists.drupal.org/ ] -- [ Drupal support list | http://lists.drupal.org/ ]
On Mon, 28 Jul 2008 10:16:37 -0700 "Metzler, David" metzlerd@evergreen.edu wrote:
The reason that these menus is because a.) they appear in the if (!$may_cache) section of the hook_menu and b.) thay are wrapped in an if ($user !== FALSE) condition.
Note that there is also a separate /user path registered in the if ($may_cache) section of the hook_menu. This is the "default" path for /user and what shows up in the admin/menu screen.
did you mean swap($may_cache,!$may_cache)?
I didn't notice the (!may_cache) section since what I'd expect to be a $items[] = array('path' => 'user' ... is actually written as if ($_GET['q'] == 'user' Why?
You may be grappling with one of the core troubles with Drupal 5. Oif ($_GET['q'] == 'user'nly menus that are in the if ($may_cache) section of the module may be moved around with the admin/menu user interface. If it's a dynamic menu, you just don't see it there. So if you make a
The "My account" hook is defined as MENU_DYNAMIC_ITEM in the $may_cache section... Does it works as expected because once a user is logged in cache can't be used?
dynamic menu item, you can't turn around and move it into a block. Although you may be able to move a the static parent menu
Do you mean "I can't put it into a block with the admin interface"? If I had a path=>'root' in $may_cache and a path=>'root/otherstuff' in !$may_cache do you mean I won't see the later? Wouldn't it be enough to just define path=>'root/otherstuff' as MENU_DYNAMIC_ITEM and place it in the $may_cache section?
That should just make it "locked" (MENU_MODIFIABLE_BY_ADMIN = 0)
item (defined in the if ($may_cache) section of the menu into a separate menu and menu block. This took me a little time to grok.
I didn't get what I can and what I can't do. eg. I can't add a menu with the admin interface and place it into a block if it is defined in the !$may_cache
Finally you can't have the code define a new menu, but only create a menu tree section in code and then move it later using the admin menu interface.
What does it mean I can't have code defining a new menu? I can actually define conditionally a menu tree even in the $may_cache section. I didn't see user.module calling menu_rebuild but eg. taxonomy_menu rebuild the menu when the taxonomy hook is fired. When does the menu_rebuild have to be called if I have dynamic menu?
I won't just have to deal with menu appearing and disappearing according to access but also on other conditions. eg. if I'd like to dynamically create a menu "See this list" just when the user (even anonymous user) has some item in the list? What if I want to change at which depth I want to start to render a menu in a block? eg. a a1 a11 a111
->
a11 a111
or
a1 a11 a111 or
a1 a11
etc...
Then what is the difference between defining a menu DYNAMIC or placing it in the !$may_cache section?
MENU_DYNAMIC_ITEM is used just 2 times in core.
Is that clearing any of this up for you?
Not completely.
I can't yet understand the magic that make -My account appear in the Menu admin pages as locked. I still haven't had the time to read the code.
grep -R locked | grep menu solved partially the mystery. A DYNAMIC menu is not MENU_MODIFIABLE_BY_ADMIN. But still it doesn't explain what is the difference between !$may_cache and MENU_DYNAMIC_ITEM
I miss how I can *render* menu with the admin interface and/or in modules. I'd expect that if I build up a $items hierarchy I could build up a menu from the "admin" interface adding a path and the menu system will take care of rendering children once I eg. put the menu in a block. What if I'd like to render the menu inside my code? I think I should use menu_tree... but well I bet there are a lot of tricks I could learn without guessing them from the API.
Still didn't get it. As you said... if at least a parent is in the $may_cache system I could use the admin interface to add a block that contain a hierarchy even if some sub menu may be dynamic or in the !$may_cache section. Is it? What if all my menu is dynamic? How can I place a menu in a block?
- I haven't seen any tutorial, handbook... on any of the menu_
family of function. There is nothing on "Pro Drupal development" book.
Still reading the api... but it seems that this part of Drupal lack tutorials, examples or books that explain how to use it. I checked twice "Pro Drupal Dev" and I didn't find anything interesting about dynamic menu, there is nothing even in the cache section. I gave a quick look to "Learning D6 module development" but it doesn't seem to contain any useful info on this topic.
thanks
did you mean swap($may_cache,!$may_cache)?
No I don't think so, but maybe I didn't word that sentence well enough.
I didn't notice the (!may_cache) section since what I'd expect to be a
$items[] = array('path' => 'user' ...
is actually written as if ($_GET['q'] == 'user' Why?
That chunk of code is really wrapping a a redirect. It's saying if you're on the 'user' page (not subpages) and we're logged in then goto user/{uid}. The code that builds the $items array is a few lines down and incidently is not hit if you just goto yousite/user. If you visit the yoursite/user page and watch the url line you'll see the redirect that's happening. But this isn't really part of building menus at all.
The "My account" hook is defined as MENU_DYNAMIC_ITEM in the $may_cache
section... Does it works as expected because
once a user is logged in cache can't be used?
No that's not true. Cache can be used whether or not a user is logged in, but the $items array in the if (!$maycache) section may register new menu paths that weren't available when you're logged in. Menu items are cached for anonymous users as well. But MENU_DYNAMIC_ITEMS are never cached.
Note that the tabs for that page are rendered later, in the if (!may_cache) section
Do you mean "I can't put it into a block with the admin interface"? If I had a path=>'root' in $may_cache and a path=>'root/otherstuff' in !$may_cache do you mean I won't see the later? Wouldn't it be enough to just define path=>'root/otherstuff' as MENU_DYNAMIC_ITEM and place it in the $may_cache section?
I really just meant that you can't manipulate root/otherstuff in the admin interface at all. I'm not really familiar with MENU_DYNAMIC_ITEM. I think it's historical. The same kind of dynamic menu items appear in the if (!may_cache ). Either way your menu items can't be altered in the admin interface.
What does it mean I can't have code defining a new menu? I can actually define conditionally a menu tree even in the $may_cache
section.
I didn't see user.module calling menu_rebuild but eg. taxonomy_menu
rebuild the menu when the taxonomy hook is fired.
I mean that you can't define something that is in its own block by default. All menus in code start out in the "Navigation Menu".
When does the menu_rebuild have to be called if I have dynamic menu?
It doesn't because items in this sections are built at every page load, and not stored in the database at all. The menu_rebuild functioin is simply a cache clearing mecahnism.
I won't just have to deal with menu appearing and disappearing
according to access but also on other conditions.
eg. if I'd like to dynamically create a menu "See this list" just when
the user (even anonymous user) has some item in
the list?
You may find DYNAMIC_MENU_ITEM to be enough, but I have never used it, so can't attest to the differences. I really do think it's an older way of achieving the same thing.
What if I want to change at which depth I want to start to render a
menu in a block? As you hinted at in your root example, the starting point simply needs to be a static menu (meaning that it is in the if ($may_cache) section of hook menu, and hence movable by the admin interface.
Then what is the difference between defining a menu DYNAMIC or placing
it in the !$may_cache section? I think MENU_DYNAMIC_ITEM is a hold-over from the past, but I'm not sure. As I've said, I didn't use it much and I've always been told to put dynamic menus in the if (!may_cache) section.
Still didn't get it. As you said... if at least a parent is in the $may_cache system I could
use the admin interface to add a block that
contain a hierarchy even if some sub menu may be dynamic or in the
!$may_cache section. Is it?
I think that this is doable, yes.
What if all my menu is dynamic? How can I place a menu in a block?
You can't. If all your menu is dynamic you can't place it in another block.
Still reading the api... but it seems that this part of Drupal lack
tutorials, examples or books that explain how to use >it.
I checked twice "Pro Drupal Dev" and I didn't find anything interesting
about dynamic menu, there is nothing even in the >cache section.
I gave a quick look to "Learning D6 module development" but it doesn't
seem to contain any useful info on this topic.
In D6 the menu system was completely overhauled and is very different from D5. In those you simply write a and access function and have it get called. IF the access function returns true, then you're menu item gets displayed. Don't think of the access function as simply being about permissions. In d6, dynamic paths are achieved with wild_cards. You register user/%/edit to get the user edit page where the uid passed as a parameter.
In D5 this approach will not work because the user_access function is not called on every page_load. It's results get cahced at login, so you have to use the if (!may_cache) section in order to achieve truly dynamic menus.
thanks
-- Ivan Sergio Borgonovo http://www.webthatworks.it
-- [ Drupal support list | http://lists.drupal.org/ ]