This module and the Block Reference module work fine together provided you’re doing the normal theme rendering, but I had a need to obtain the unrendered menu block tree like that returned by menu_tree_page_data(). This module’s menu_tree_build() function will provide a rendered menu block tree, but not the tree data.

This patch adds two API functions to this module:
menu_block_tree_build($config) - build tree data from a configuration
menu_block_get_delta($bid) - return block delta, given block ID

Comments

StatusFileSize
new5.25 KB

Correction to previous patch.

Status:Active» Postponed (maintainer needs more info)

The patch doesn't apply to HEAD (7.x-3.x) or to 6.x-2.x, so I'm not sure which branch you mean.

It doesn't align with any specific source right now, except my own, which is 6-x with the patch at #898616. I'll post something normal in a day or so.

Do you have a preference as to 7-x or 6-x?

Version:7.x-3.x-dev» 7.x-2.x-dev
Status:Postponed (maintainer needs more info)» Needs review
StatusFileSize
new5.03 KB

Patch for 7.x-2.x-dev attached

Status:Needs review» Postponed (maintainer needs more info)

If you actually look at the existing code in the menu_block 7.x-2.x/7.x-3.x, you'll see that menu_tree_build() doesn't return HTML; it returns a renderable array like all good d7 modules should.

There's also hook_menu_block_tree_alter() which allows you to get at the data you say you want. Have you tried that? Its documented in menu_block.api.php. There's also a boat load of theme hook suggestions documented in the README.

The patch looks redundant to me.

Status:Postponed (maintainer needs more info)» Active

Although it’s not obvious in the diff patch, menu_block_tree_build() is really just hooking in to the original version of menu_tree_build() before it does its rendering work. Yes, I suppose I could create a hook_menu_block_tree_alter() hook, invoke menu_tree_build() and then pull the data out at the hook, but then menu_tree_build() would proceed to repeat what else I needed to do to the data, namely:

<?php
 
// Prune the tree along the active trail to the specified level.
 
if ($config['level'] > 1 || $config['parent_mlid']) {
    if (
$config['parent_mlid']) {
     
$parent_item = menu_link_load($config['parent_mlid']);
     
menu_tree_prune_tree($tree, $config['level'], $parent_item);
    }
    else {
     
menu_tree_prune_tree($tree, $config['level']);
    }
  }
 
// Prune the tree to the active menu item.
 
if ($config['follow']) {
   
menu_tree_prune_active_tree($tree, $config['follow']);
  }
 
// If the menu-item-based tree is not "expanded", trim the tree to the active path.
 
if ($config['parent_mlid'] && !$config['expanded']) {
   
menu_tree_trim_active_path($tree);
  }
 
// Trim the branches that extend beyond the specified depth.
 
if ($config['depth'] > 0) {
   
menu_tree_depth_trim($tree, $config['depth']);
  }
 
// Sort the active path to the top of the tree.
 
if ($config['sort']) {
   
menu_tree_sort_active_path($tree);
  }
?>

The value of $tree at the end of this code fragment is what I’m after, and it’s what menu_block_tree_build() returns.

Perhaps this is a very unusual need, but I don't think so. Perhaps instead of what I wrote, a hook could go here in the original code and accept a return value to tell menu_tree_build() to not bother to proceed with its rendering:

<?php
 
// Render the tree.
 
$data = array();
 
$title = menu_block_get_title($config['title_link'], $config);
 
$data['subject_array'] = $title;
 
$data['subject'] = drupal_render($title);
 
$data['content']['#content'] = menu_block_tree_output($tree, $config);
  if (!empty(
$data['content']['#content'])) {
   
$data['content']['#theme'] = array(
     
'menu_block_wrapper__' . $config['delta'],
     
'menu_block_wrapper__' . str_replace('-', '_', $config['menu_name']),
     
'menu_block_wrapper'
   
);
   
$data['content']['#config'] = $config;
   
$data['content']['#delta'] = $config['delta'];
  }
  else {
   
$data['content'] = '';
  }
?>

But such a hook seems a lot more complicated than adding a new function that simply returns the needed data at the point that it’s already prepared.

Status:Active» Postponed (maintainer needs more info)

Although it’s not obvious in the diff patch, menu_block_tree_build() is really just hooking in to the original version of menu_tree_build() before it does its rendering work. Yes, I suppose I could create a hook_menu_block_tree_alter() hook, invoke menu_tree_build() and then pull the data out at the hook, but then menu_tree_build() would proceed to repeat what else I needed to do to the data,

I still don't understand the use-case. What data do you need out of menu_tree_build() that you aren't getting with the existing hooks?

A use-case for this feature can be seen in accordion_menu module which is looking for an array of links as would be returned by menu_tree_build prior to the render tree code (as mentioned by the OP in #6). I also believe that jquerymenu has a similar requirement.

@Daniel Norton thanks for the patch.

Title:Need unrendered menu tree from Block Reference CCK block ID dataAdd API to obtain raw menu data (not the render element)
Status:Postponed (maintainer needs more info)» Needs review
StatusFileSize
new8.83 KB

Ok. I understand what you want now. You want access to the raw menu data, like core's menu_tree_all_data() and menu_tree_page_data(). And you don't want the render element that menu_tree_build() returns because you want to create your own decorated render element from the raw menu data.

What about this patch?

Status:Needs review» Fixed

I've commited the patch. Let me know if you feel something needs to be tweaked in order to make 3rd party module integrate better with the new API.

Status:Fixed» Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

Status:Closed (fixed)» Active

@john, in response to #11, the patch could definitely be tweaked "to make 3rd party module integrate better."

The patch committed split up menu_tree_build() into:
- menu_block_get_current_page_menu() and
- menu_tree_block_data()
but left code that should have been moved.

So, for a 3rd party module to use the "new API," it needs to duplicate the code in menu_tree_build() before the renderable array is created, to wit:

  // Retrieve the active menu item from the database.
  if ($config['menu_name'] == MENU_TREE__CURRENT_PAGE_MENU) {
    $config['menu_name'] = menu_block_get_current_page_menu();
    $config['parent_mlid'] = 0;
    // If no menu link was found, don't display the block.
    if (empty($config['menu_name'])) {
      return array(
        'subject' => t('The menu selected by the page'),
        'subject_array' => array(),
        'content' => array(),
      );
    }
  }
  // Get the default block name.
  $menu_names = menu_block_get_all_menus();
  menu_block_set_title($menu_names[$config['menu_name']]);
  // Get the raw menu tree data.
  $tree = menu_tree_block_data($config);
  $title = menu_block_get_title($config['title_link'], $config);

This is not a robust API to latch onto.

Compare this to the simple patch for version 2.3 suggested on #1452660: Support a sub-menu API by separating code for tree building and tree rendering and included here. All that was and is needed is to split menu_tree_build() at the point it generates the renderable array. The latter approach allows a contributed module to write:

  $menu_block_config = menu_block_get_config($config['block_source']);
  $tree = menu_tree_build($menu_block_config);

and go off and render the tree as it sees fit.

Please consider this approach.