Index: views.module =================================================================== --- views.module (revision 687) +++ views.module (working copy) @@ -183,7 +183,7 @@ function views_menu_alter(&$callbacks) { $views = views_get_applicable_views('uses hook menu'); foreach ($views as $data) { list($view, $display_id) = $data; - $result = $view->execute_hook_menu($display_id); + $result = $view->execute_hook_menu($display_id, $callbacks); if (is_array($result)) { // The menu system doesn't support having two otherwise // identical paths with different placeholders. So we Index: plugins/views_plugin_display_page.inc =================================================================== --- plugins/views_plugin_display_page.inc (revision 687) +++ plugins/views_plugin_display_page.inc (working copy) @@ -46,8 +46,11 @@ class views_plugin_display_page extends /** * Add this display's path information to Drupal's menu system. + * + * @param $callbacks + * A menu callback array passed from hook_menu_alter(). */ - function execute_hook_menu() { + function execute_hook_menu($callbacks) { $items = array(); // Replace % with the link to our standard views argument loader // views_arg_load -- which lives in views.module @@ -83,8 +86,27 @@ class views_plugin_display_page extends if (empty($menu)) { $menu = array('type' => 'none'); } + // When overriding existing menu items, apply inheritance rules to any + // child items. + if ($menu['type'] == 'existing') { + // Grep all callbacks for router items below the target path. + $children = preg_grep('@' . preg_quote($path, '@') . '/.+@', array_keys($callbacks)); + foreach ($children as $child_path) { + // Only inherit properties from parent, if the child is not a default + // local task. + if (!isset($callbacks[$child_path]['type']) || $callbacks[$child_path]['type'] != MENU_DEFAULT_LOCAL_TASK) { + // Add child to our stack of items to replace. + $items[$child_path] = $callbacks[$child_path]; + // Ensure that the parent path really exists and inherit its + // properties to the child (not replacing existing properties). + if (isset($callbacks[$path])) { + $items[$child_path] += $callbacks[$path]; + } + } + } + } // Set the title and description if we have one. - if ($menu['type'] != 'none') { + elseif ($menu['type'] != 'none') { $items[$path]['title'] = $menu['title']; $items[$path]['description'] = $menu['description']; } @@ -98,14 +120,24 @@ class views_plugin_display_page extends default: $items[$path]['type'] = MENU_CALLBACK; break; + + case 'existing': + // If the path really exists, copy over its remaining properties. + if (isset($callbacks[$path])) { + $items[$path] += $callbacks[$path]; + } + break; + case 'normal': $items[$path]['type'] = MENU_NORMAL_ITEM; // Insert item into the proper menu $items[$path]['menu_name'] = $menu['name']; break; + case 'tab': $items[$path]['type'] = MENU_LOCAL_TASK; break; + case 'default tab': $items[$path]['type'] = MENU_DEFAULT_LOCAL_TASK; break; @@ -218,9 +250,15 @@ class views_plugin_display_page extends default: $menu_str = t('No menu'); break; + + case 'existing': + $menu_str = t('Existing menu'); + break; + case 'normal': $menu_str = t('Normal: @title', array('@title' => $menu['title'])); break; + case 'tab': case 'default tab': $menu_str = t('Tab: @title', array('@title' => $menu['title'])); @@ -282,6 +320,7 @@ class views_plugin_display_page extends '#type' => 'radios', '#options' => array( 'none' => t('No menu entry'), + 'existing' => t('Existing menu entry'), 'normal' => t('Normal menu entry'), 'tab' => t('Menu tab'), 'default tab' => t('Default menu tab') @@ -434,7 +473,7 @@ class views_plugin_display_page extends } } - if ($form_state['values']['menu']['type'] != 'none' && empty($form_state['values']['menu']['title'])) { + if ($form_state['values']['menu']['type'] != 'none' && $form_state['values']['menu']['type'] != 'existing' && empty($form_state['values']['menu']['title'])) { form_error($form['menu']['title'], t('Title is required for this menu type.')); } break; @@ -465,7 +504,7 @@ class views_plugin_display_page extends $errors = parent::validate(); $menu = $this->get_option('menu'); - if (!empty($menu['type']) && $menu['type'] != 'none' && empty($menu['title'])) { + if (!empty($menu['type']) && $menu['type'] != 'none' && $menu['type'] != 'existing' && empty($menu['title'])) { $errors[] = t('Display @display is set to use a menu but the menu title is not set.', array('@display' => $this->display->display_title)); } Index: includes/view.inc =================================================================== --- includes/view.inc (revision 687) +++ includes/view.inc (working copy) @@ -965,10 +965,14 @@ class view extends views_db_object { } /** - * Called to get hook_menu information from the view and the - * named display handler. + * Called to get hook_menu() information from the view and the named display handler. + * + * @param $display_id + * A display id. + * @param $callbacks + * A menu callback array passed from views_menu_alter(). */ - function execute_hook_menu($display_id = NULL) { + function execute_hook_menu($display_id = NULL, $callbacks = array()) { // Prepare the view with the information we have. // This was probably already called, but it's good to be safe. @@ -978,7 +982,7 @@ class view extends views_db_object { // Execute the view if (isset($this->display_handler)) { - return $this->display_handler->execute_hook_menu(); + return $this->display_handler->execute_hook_menu($callbacks); } }