Submenutree hook which allow other modules to process any page callback and display it through Submenutree

wojtha - January 19, 2009 - 18:36
Project:Submenu Tree
Version:6.x-1.3
Component:Code
Category:feature request
Priority:normal
Assigned:Unassigned
Status:needs work
Description

Hi, I'm starting new issue about support of other callbacks than node_page_view as I've written here: #333202: Submenu Tree Doesn't seem to allow View menu items in any mode other than Menu

My new module NodeSymlinks allows that nodes can appear on multiple different places of the website navigation and has different menu driven breadcrumbs and active menu trails.

Because my module uses other page callback than node_page_view, NodeSymlink menu items are not listed on the SubmenuTree pages. Only type which is working now is a Menu view.

You have written that I can override SubmenTree in nodeapi. At first, I tried to do it in this way, but then I needed to copy two or three functions which generated the menu trees and overwrite some parts of them in my module. But I didn't like doing it this way, because it is duplicate computing of the same thing. So I begun to think about simple API which will allow to process different page callbacks with other modules before it is rendered in SubmenuTree.

Invoking API callback in your module:

<?php
function _submenutree_menutree_view(&$node, $type, $tree) {

    ...

   
$items = array();
    foreach (
$tree as $k => $v) {
     
// use page_callback == node_page_view to detect nodes
     
if ($v['link']['hidden'] == false && $v['link']['page_callback'] == 'node_page_view') {
       
$nid = substr($v['link']['href'], 5);
       
$child = node_load(array('nid' => $nid));
       
$items[] = array(
         
'node' => $child,
         
'weight' => $v['link']['weight'],
         
'title' => check_plain($v['link']['title']),
         
'path' => $v['link']['href'],
        );
      }
     
// launch submenutree hook
     
elseif ($v['link']['hidden'] == false) {
        foreach (
module_implements('submenutree') as $module) {
         
$function = $module . '_submenutree';
         
$item = $function($v);
          if (!empty(
$item)) {
           
$items[] = $item;
          }
        }
      }
    }

  ...

}

// Small change - using $item['path'] allows to use any path, not only hardcoded node/nid
function theme_submenu_tree_titles($items, $title = null) {
 
$list = array();
  foreach (
$items as $item) {
   
//$list[] = l($item['node']->title, 'node/' . $item['node']->nid);
   
$list[] = l($item['node']->title, $item['path']);
  }
  return
theme('item_list', $list, $title);
}
?>

Current implementation of the new hook in NodeSymlinks module

<?php
/**
* Implementation of hook_submenutree
*/
function nodesymlinks_submenutree($menuitem) {
 
$item = array();
  if (
$menuitem['link']['page_callback'] == 'nodesymlinks_page') {
    list(,
$nid) = explode('/',$menuitem['link']['href']);
   
$node = node_load(array('nid' => $nid));
   
$node->path = $menuitem['link']['href'];
   
$item = array(
     
'node' => $node,
     
'weight' => $menuitem['link']['weight'],
     
'title' => check_plain($menuitem['link']['title']),
     
'path' => $menuitem['link']['href'],
    );
  }
  return
$item;
}
?>

Patch against SubmenuTree 1.3 attached.

AttachmentSize
submenutree.patch1.5 KB

#1

bengtan - January 20, 2009 - 03:38

Hi,

Interesting idea. With this post, I have a much better idea of what you are trying to achieve. However, I think the idea needs more thought.

Submenutree only works with nodes. That is by design because submenutree renders menu items as titles, teasers, and full text. Only nodes have an inbuilt teaser and full text view. Hence, submenutree only knows how to work with menu items which are also nodes.

Submenutree tests that a menu item's page callback is node_page_view() as a way to make sure the menu item is a node. Otherwise, there is nothing special about node_page_view().

If you want me to accept a patch for submenutree that generalises the 'things' that submenutree can handle, the patch will need to be able to handle 'things' which have a title, teaser, and full text view. So, your suggested hook_submenutree() will almost certainly need some sort of $op parameter so submenutree can retreive that 'thing's title, teaser and full text view.

However, before going down this generalisation path, I have a suggestion which may be simpler for us both.

As I said earlier, there is nothing special that requires submenutree to check that the page callback is node_page_view(). If there is another way to test that a menu item is a node, which also works for your module, then I will happily change the criteria.

For example, with Drupal 6.x, there is a menu_get_object() function that can be used to retrieve menu item's node (if it exists). If that works for submenutree, and works with your module, then we can use that instead.

#2

wojtha - January 20, 2009 - 19:15

Hi bengtan,

thank you for the fast reply. Yes, you are right with the $op parameter. I knew that something like that will be needed. My code was supposed as an initial concept to start discussion about that and it was also reason to mark this issue with 'code needs work' status.

I will try to test menu_get_object(), but anyway I like the idea to have more generalised SubmenuTree and I think that the implementation of the idea will be easy. And hopefully not much work for you ;-)

We only need to pass an 'abstract' item to submenutree themeing functions. Item will always have title, body and path, so it can be themed in a "universal" way. These values (title, body, path) can be rendered in the submenutree hook. Ordinary node will be always rendered by Submenutree directly so the speed will be same as before for ordinary nodes.

Alternatively in the submenutree can be defined theme functions which override default SubmenuTree item/node themeing functions.

 
 

Drupal is a registered trademark of Dries Buytaert.