I had a request to hide menu tabs created by a view I created called "newsroom" with multiple displays in it if a specific display was empty. That way a user doesn't have to click a tab just to see the empty view results message.

As a disclaimer this code may be able to be enhanced for performance reasons and I'm open to suggestions.

// $Id: newsroom_tabs_hide.module

/**
* Implementation of hook_menu_alter().
* Remember to clear the menu cache after adding/editing this function.
*/
function newsroom_tabs_hide_menu_alter(&$items) {
  // Local function calls for passing variables for each menu item to be hidden.
  // Passes:
  // - $items from hook_menu_alter
  // - $section in the form of the tab path (specific to your view/tab menu)
  // - $display which is the display in the view (specific to your view->displays)
  newsroom_tabs_hide_check($items, 'newsroom/testimonies', 'page_6');
  newsroom_tabs_hide_check($items, 'newsroom/press_releases', 'page_5');
  newsroom_tabs_hide_check($items, 'newsroom/newsletters', 'page_4');
  newsroom_tabs_hide_check($items, 'newsroom/advisories', 'page_2');
  newsroom_tabs_hide_check($items, 'newsroom/job_announcements', 'page_3');
}

function newsroom_tabs_hide_check(&$items, $section, $display) {
  // Load your view (specific to your view name)
  $view = views_get_view('newsroom') or die('no such view');
  // Load a specific display of that view
  $view->set_display($display);
  // I was told this was required from searching.
  $view->args = array('myarg');
  // Run/execute the view
  $view->pre_execute();
  $view->execute();
  // If the view is empty (no result), set the tab path ($section var) type to MENU_CALLBACK.
  // This hides the menu tab but doesn't unset/remove the path all together.
  if(!$view->result) {
  	$items[$section]['type'] = MENU_CALLBACK;
  }
}

Helpful links:
http://www.braahm.be/posts/how-hide-existing-menu-links-and-menu-tabs-dr...
http://www.alligatorsneeze.com/drupal-alters-and-overrides-hookmenualter

Definitely open to better ways of doing this but from searching I couldn't find this done anywhere else before.

Also, as an additional note:
The modules list itself is weighted as far as the run order. In looking in my local database, views has a weight of 10. If you expect this to run correctly it has to run after views creates the menu first. That means the weight of this module needs to be set to a bigger number (I chose 30. Too big a number and it won't work.)

The only way I saw to do this was to modify the "system" table in your database. In the row corresponding to your custom module, modify the "weight" field to be 30 or something bigger that the weight of views.

Comments

kholloway’s picture

BTW, performance hit isn't bad. Almost hard to see any at all.

No Module (Cached)
- Docs 55ms
- Stylesheets 462ms
- Images 1.14s
- Scripts 33ms
- Total 2.35s, 2.72s, 3.12s, 2.71s

No Module (Not Cached)
- Docs 53ms
- Stylesheets 602ms
- Images 1.65s
- Scripts 420ms
- Total 7.18s

Module (Cached)
- Docs 58ms
- Stylesheets 596ms
- Images 1.42s
- Scripts 376ms
- Total 2.62s, 2.12s, 2.31, 2.95s, 2.05s

Module (Not Cached)
- Docs 52ms
- Stylesheets 629ms
- Images 1.59s
- Scripts 407ms
- Total 4.00s

Canadaka’s picture

this doesn't seem to work with view tabs that use arguments.

example:
user/%/photos

Drupal caches the menu once so after the menu is generated if you visit another users profile all the same menu tabs will be hidden or not. The hook_menu_alter is not run on each pageview.

Is there a way to make this work?

kholloway’s picture

You are correct. I have a view that has arguments as well and ran into this issue. I will update when I find a solution.