By Beltanin on
I have read all the documentation I can find on hook_menu(). I understand the normal menu system fine, but somehow I just can't get it through my thick skull how to implement the local tasks.
Is there a good online tutorial that someone could point me to? Or could someone please explain this in simple terms from beginning to end. The regular menu system is very logical, I'm just not sure what I'm missing here. Every built-in module seems a little to complicated for me to understand.
- Martin
Comments
Brief explanation
2 simple steps to understanding local tasks.
1. DONT PANIC.
2. Steal the code you need from somewhere else ... like the user module for example.
Local tasks are displayed in the tabs across the top of the page. A good example of an implementation of local tasks is the login screen - by default you see 3 tabs login, register and forgot password.
The code for this is below
So you can see that everything is exactly like defining a normal menu item, but just by setting the type to be MENU_LOCAL_TASK drupal will display the menu items as tabs.
Not sure if thats such a good explanation - but hopefully the code will paint a thousand words :)
cool cool,
Mike
Like books? Check out booktribes the new (Drupal based) community for book lovers
from Computerminds
Mike,
Computerminds offer Drupal development, consulting and training
Follow Up
Thanks for the input, it allowed me to make some great strides. A couple of follow up questions if I may...
(BTW, I have read and read and read the documentation, but I'm getting lost in it.)
1. When using the standard view/edit node screen [xxx_form()], is it possible to add another local task? It doesn't really appear to be working for me if it does.
2. If the above is not possible, I figure I can make up my own custom forms, etc. In this case then, how do I determine what action is being taken on the form. How do I know if it's a new record, an edit, or a deletion? This may sound a little naive but I'm also not sure where to put the code to execute the proper action.
Any help would be greatly appreciated.
- Martin
...
Yes, it's possible. You use the same code mdixoncm provided, but the trick is to find out the correct path. Let's say we want to add a 'bozo' tab besides the 'view' and 'edit' ones. Drupal knows tabs are siblings by examining their paths. So the 'bozo' tab must have a 'node/1234/bozo' path for Drupal to know it's a sibling to 'view' (node/1234) and 'edit' (node/1234/edit).
Here's how to do it:
Note the
arg(1)thing. It extracts the node ID from the URL. If we're browsing node #234, our bozo 'path' will be 'node/234/bozo'.Web programming is event-based. It's not the old-style programming we learned at high-school, where we were the ones to hand control to each procedure (aka 'function') ourselves. Event-based programming is somewhat different.
And we don't program the application from scratch. We use some framework. Drupal is such a framework. There are others as well.
Don't fret when you don't understand code you see. You're not supposed to understand it as long as you haven't learned the basics of the Drupal framework.
let's return to my code above. When I handed the
$itemsarray to Drupal, I described to him what piece of code it should hand control to when the 'node/123/bozo' path is accessed. That's event-based programming. It's different from traditional programming.Start at the beginning. the handbooks contain some tutorials.
Thank you.
Thank you moofie.
This has provided that last little bit of understanding that I needed. After your additional notes and some more reading I've got exactly what I needed now. Thank you for all your time.
- Martin
I am not able to add local tasks
Hi,
I read your reply I follow the same instructions. Still local tasks are not displayed.
code in mymodule_menu
$items[] = array(
'path' => 'node/add/edit',
'title' => t('Bozo this node'),
'callback' => 'mymodule_bozo',
'type' => MENU_IS_LOCAL_TASK,
);
I check in menu.inc following condition is not returning true.
menu.inc
if (($_menu['items'][$mid]['type'] & MENU_IS_LOCAL_TASK) && _menu_item_is_accessible($mid)) {
Can u please help me
...
What are you trying to achieve here?
'node/add/edit' seems weird to me.
It is eg
I want to give path for different modules like amazon search
Yeah but why would you want
Yeah but why would you want to ADD and EDIT content at the same time ? It doesn't make sense.
Caroline
A coder's guide to file download in Drupal
Who am I | Where are we
11 heavens
MENU_LOCAL_TASK gotcha!
If you are just starting building your first local task, keep in mind that you need at least two local tasks for them to show up!
From: http://api.drupal.org/api/drupal/includes--menu.inc/function/menu_local_...
Adding tabs
I'm not sure if this applies or will help anyone... but I was looking for a way to just add items to the local tasks tabs and only for specific nodes. I added this to my page.tpl.php file before the $tabs variable is called.
if ( !empty($tabs) && $_GET['q'] == 'node/' ) : $tabs = ereg_replace("</ul>", '<li><a href="?q=node/" target="_blank">Tab Title</a></li></ul>', $tabs); endif;You can use this for as many items as you want and also have it apply to all pages by removing
&& $_GET['q'] == 'node/'in the if statement
Note entirely sure that this is the best way
Adding functional stuff like this to the template it generally considered bad practice... A better method would be to create a module and in hook_menu do...
That example will check the path and, if there is a node on this path (eg node/5) then it will load the node (eg, 5) and then check its type (eg, blog). If it IS a 'blog' then it will add a new tab to the list and it will also handle the callback AND the access permissions (so if your user does not have a role with that permission set then you will NOT see the tab).
Just noticed (a few weeks
Just noticed (a few weeks later) that there needs to be a type => MENU_LOCAL_TASK on the example menu item.
VERY helpful...
VERY helpful... thanks.
There is one other minor typo... You need one more ")" at the end of your first conditional.
Here is the re-written code with the extra ) and the MENU_LOCAL_TASK edit implemented.
I cannot figure this out to
I cannot figure this out to save my life. When I tried to use this code, it definitely produced the local task as a tab. However, when I click on the tab, the callback does not get executed. Instead, the node reloads with node/nid/example in the url.
Any thoughts as to why this is happening?
Something similar
My code was calling the parent item too but for a different situation. Perhaps this will help someone.
In my case it was because on the second time through (i.e. after the user had clicked the local link), the test for whether the user was allowed to access the local menu failed. The test depended on a specific form (the form of the parent url) which was different from the child url, so of course it would fail.
With that failed test, the local menu wasn't inserted into the menu table. All Drupal would find is the parent, which it promptly displayed.
Recrafting the test so that it could handle the URL form of both the parent AND the local menu did the trick.
A better way... for D6
All this techniques are very interesting, but checking the hook_menu documentations I think I came up with a way of creating local tasks depending on arbitrary conditions.
In my case, I was trying to add a local task to nodes of certain type, and noticed two very powerful properties of a menu entry, those are %placeholders and the 'access callback' property.
Using a custom 'access callback' function, we can create a menu entry that can be cached and that can be present on arbitrary conditions. Here's what I did:
Hope this helps!
Actually...
The proper way to conditionally create a menu item in Drupal 6 is to use a loader function. For example:
The menu processor looks at whatever appears after the %, adds "_load" and uses that to validate the argument. It's weird, but it works. See http://drupal.org/node/103114 for more info.
But unlike the last posters
But unlike the last posters method, your method will add the local task whether it's the proper node type or not.
Contact me to contract me for D7 -> D10/11 migrations.
It works, I swear!
I have this in a production environment, and the local task (i.e. tab) is only added if the node type is "mymodule_type", as per the example. Naturally I had to adapt the code so that it would be appropriate for an example. Did I miss something?
Well, you didn't show your
Well, you didn't show your access callback, which is what will decide whether or not the tab will be rendered.
Contact me to contract me for D7 -> D10/11 migrations.
Menu Local Tasks
There is a module called Tab Tamer that gives you access to work with the menu local tasks. You can change the order, hide some, change the titles, etc. Very, very handy!
Also, to add tabs, I followed WorldFalz's advice and it worked beautifully! See it here at http://drupal.org/node/370859.
In my case, I used the 'me aliases' module so I can name my pages (created with views) with just user/me/xxx and they appear in the list in Tab Tamer so I can order them there. I haven't tried it yet with Panel Pages. For the view pages to work, you have to select the Menu option: Menu Tab. You also have to set the argument to UID. The idea is that anything with user/% will appear in the local tasks menu so this gives you a lot more control over most things related to it.
Another thing I figured out has an impact are the Display Settings in the Content Profile Tab of your Content Profile content type. Play around with them to have View and Edit appear and disappear under the Tab Tamer Tabs. (Profile tabs have the names View and Edit in the user/% section of Tab Tamer - View shows the Profile and Edit is to edit the account).
Now if I could just figure out how to have all of my Profile-related tabs be grouped with a parent tab (Profile)and children (Account, View Profile, Edit Profile, Apply for Role), I'm in business! lol
I hope this saves someone time.
Hélène