Overriding core's User module menu behaviour
Hello everybody.
I am kinda new to Drupal, so I appologize in advance if my question seems stupid, but I have not found any other post which helped, nor succeeded in solving this problem myself by hacking the core module.
The thing is I am developing a new where I need to change the way the User module displays it's data. I am using the hook_form_alter() and hook_user() hooks to catch the events I need and change the way forms are displayed (i.e add/remove fields to them), but I also need to change the menu hierarchy...!
I want to change the menus so that the View tab (local task) would not appear, since I have no need for it, and to add other tabs which I do need.
I looked for a hook_menu_alter(), but there is no such function. The closest I found was hook_link_alter() but that didn't solve my problem. Thinking about it, I decided to create such a hook, and added the following code to the user.module file just before thereturn $items; at end of the user_menu() hook function:
<?php
// allow altering the module's menus
foreach (module_implements('menu_alter') as $module) {
$function = $module .'_menu_alter';
$function( 'user', $items );
}
?>Then, I created the following function in my code to try changing the menu:
<?php
/**
* Catch User's menus and alter them.
*/
function myuser_menu_alter( $module, &$menu ) {
if ( $module == 'user' ) {
// ...
}
}
?>The strange thing was that none of the changes I made (even unsetting the whole menu tree) affected the display of the View and Edit tabs, nor any other items.
This leads me to believe that I'm either not changing the menus in the right place (althought it seems the ONLY right place to do it) or that the menus are cached or defined elsewhere.
What am I doing wrong, or better yet - How should I do it right?!?!
Any help from you guys, would be highly appreciated!!
Thanks in advance,
Roi

"edit" tab removal
Roi,
While you're under the hood, I have to ask if you know anything about eliminating the "Edit" tab, but only on one account? I'm trying to create a generic company employee profile, which grants access to a generic page of outside links. However I don't want the end user to have the ability to edit the generic account info (email, password, etc.).
Is this feasible, or a waste of time?
-Salty
www.saltwatermedia.net
Salty, I assume removing the
Salty,
I assume removing the Edit tab is probably the same as removing the View tab.
However, in my post I described some thoughts on how to solve this, which I'd tried and didn't succeed.
I believe we need an answer from a "higher power" :) on this matter (a Drupal guru or core-developer?!), and that's exactly what I'm waiting for...
As far as your question about feasibility - I hope it is, or else I'll have no choice but to replace the core user module with a new version of my own (something I'm trying to avoid at all costs).
- Roi
I actually think this is
I actually think this is impossible without directly altering the user.module. The view tab is a DEFAULT_LOCAL_TASK which firstly means that all other tasks depend on its existance. Secondly, i'm not sure where you've put the menu_alter hook, but I'm guessing that its not in menu.inc (another core file) where I believe the final step of menu building is (thus the only place you could really alter menus modularly).
My solution was to build user pages on an entirely seperate arg(0) == 'account'; with all instances of 'user' redirecting account. Ideal? Not at all. However, its the best way I have found scrap the 'view" tab.
--
"I'm not concerned about all hell breaking loose, but that a PART of hell will break loose... it'll be much harder to detect." - George Carlin
--
Personal: http://www.nicklewis.org
Work: http://www.onnetworks.com
Sorry, I missed some stuff.
Sorry, I missed some stuff. Rewrote your code to what I'd assume would work:
<?php// ! very end of hook menu, just before return $items !
foreach (module_implements('menu_alter') as $module) {
$function = $module .'_menu_alter';
$function($items);
}
return $items;
?>
Than the function
<?php// name this hook_user_menu_alter -- as other menu items will be unaffected by it ($items are returned and merged somewhere else)
function hook_user_menu_alter(&$items) {
// loop through the items and switch (cringe) because we don't have associative keys for menu items ($#@)%$)
foreach ($items as $item) {
switch ($item['title']) {
case t('View'):
unset($item);
break;
}
}
}
?>
--
"I'm not concerned about all hell breaking loose, but that a PART of hell will break loose... it'll be much harder to detect." - George Carlin
--
Personal: http://www.nicklewis.org
Work: http://www.onnetworks.com
Rewrote user.module
Nick,
Thanks for taking the time to think about my problem!
As I understand, I will have to modify core files anyway I look at it (user.module or another), and besides, I realized that I have many changes to make with the way the user.module works, that using these hooks will only make the code less readable...
I guess I'll have to modify the user.module directly with the changes I want and keep track of updates to it (that I will have to do manually from now on :-S).
Cheers,
- Roi
Don't need to hack user.module
If all you want to do is get rid of the View or Edit tab, you can do this using the theme_menu_item_link template function (at least using the sympal theme you can use the sympal_theme_menu_item_link) function. The final function could look something like this (from a modified sympal theme):
<?phpfunction sympal_theme_menu_item_link($item, $link_item) {
if ($item['title'] == 'View') return;
return _phptemplate_callback('menu_item_link', array('item' => $item, 'link_item' => $link_item));
}
?>
Not thoroughly tested, and didn't work for what I wanted it to: changing the name of the View task to a category name.
YMMV
--
ethan winn
http://www.destratify.com/
Worked for me
Worked for me! I've used your tip to rename the node 'view' tab to something else.
<?phpfunction phptemplate_menu_item_link($item, $link_item) {
if ($item['title'] == t('View')) $item['title']=t('Business Profile');
return theme_menu_item_link($item, $link_item);
}
?>
Notice the "t()" since this is a multilingual site.
Amnon
-
Professional: Drupal Israel | Drupal Development & Consulting
Personal: Hitech Dolphin: Regain Simple Joy :)
Another approach
I don't know if this is really any less hackish but I created a custom_menus module for changing menu types, mostly hiding tabs for users who need a permission but don't want/need to see certain tabs that they get along with a permission. Mostly, I am dealing with the node queue module but I will try to apply it simply to the user module.
I installed my custom_menu module and went in to the database, opened the system table and change the weight of the module to -10. Now the menu settings in this module will take precedence over the heavier weighted modules.
The module could have just these two functions. Use hook_perm to set up a permission so you can see the tabs as an administrator on the site. And then use the hook_menu to set up menu items.
<?php
function custom_menus_perm(){
return array('View superfluous tabs');
}
function custom_menus_menu(){
if (user_access(!'View superfluous tabs')){
if ($may_cache){
//Nix any cached tabs here.
//You would probably have to empty the cache_menu table as well.
}
else {
$items[] = array(
'path' => 'user/'.arg(1).'/view',
'access' => user_access('View superfluous tabs'),
);
$items[] = array(
'path' => 'user/'.arg(1).'/edit',
'access' => user_access('View superfluous tabs'),
);
}
}
return $items;
}
?>
I really don't know if there are any freakish side-effect to this. I am just implementing it now, saw this posting and thought I would add to it. I will repost if anything goes horribly wrong.
It might also be interesting to try this on the theme side.
Some thoughts
Remember, hook_menu_alter is for Drupal 6 only - it's a new hook:
http://api.drupal.org/api/function/hook_menu_alter/6
If only it were available in Drupal 5.5!! :-(
As for tabs, when I wanted to ditch the View tab from my nodeprofile boxes, I over-rode the offending function in my template.php file:
<?php
/**
* Displays the given content in a nodeprofile box, which may have some tabs, that allow
* users to perform some actions on the node
* from nodeprofile.module
*/
function phptemplate_nodeprofile_display_box($element, $content) {
$path = drupal_get_path('module', 'nodeprofile') .'/nodeprofile.css';
drupal_add_css($path, 'module', 'all', FALSE);
$head = isset($element['#title']) ? '<h2 class="nodeprofile-title">'. check_plain($element['#title']) .'</h2>' : '';
$output = '';
//displays tabs above nodes
if (isset($element['#tabs']) && is_array($element['#tabs'])) {
$output .= "<ul class=\"tabs nodeprofile\">\n";
foreach ($element['#tabs'] as $tab_name) {
//added clause to catch the unwanted "view" tab
if (($tab = theme('nodeprofile_display_tab_'. $tab_name, $element['#node'])) && ($tab_name != 'view')) {
$output .= '<li>'. $tab .'</li>';
}
}
$output .= "</ul>\n";
}
return $head .'<div class="nodeprofile-display">'. $output . $content. '</div>';
}
?>
I'm sure a similar approach can be used in other contexts, if required, but I haven't looked at how other modules handle the tabs - my requirement was specific to nodeprofile.
Follow up
theme_menu_local_tasks() is the function in theme.inc which controls tabs elsewhere, btw. It looks like this:
<?php
function theme_menu_local_tasks() {
$output = '';
if ($primary = menu_primary_local_tasks()) {
$output .= "<ul class=\"tabs primary\">\n". $primary ."</ul>\n";
}
if ($secondary = menu_secondary_local_tasks()) {
$output .= "<ul class=\"tabs secondary\">\n". $secondary ."</ul>\n";
}
return $output;
}
?>
So, by way of an example, I made a phptemplate version of the function in my theme's template.php file like this to hide tabs on the edit and view user account pages:
<?php
function phptemplate_menu_local_tasks() {
$output = '';
if (($primary = menu_primary_local_tasks()) && (arg(0) != 'user')) {
$output .= "<ul class=\"tabs primary\">\n". $primary ."</ul>\n";
}
if ($secondary = menu_secondary_local_tasks()) {
$output .= "<ul class=\"tabs secondary\">\n". $secondary ."</ul>\n";
}
return $output;
}
?>
Another approach
You can also achieve "changing" the user menu items with hook_menu and callback functions, as documented here:
http://www.drupaler.co.uk/blog/user-module-menus-revisited/24