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

Daniel Norton’s picture

FileSize
5.25 KB

Correction to previous patch.

JohnAlbin’s picture

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.

Daniel Norton’s picture

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?

Daniel Norton’s picture

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

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

JohnAlbin’s picture

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.

Daniel Norton’s picture

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:

  // 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:

  // 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.

JohnAlbin’s picture

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?

tklawsuc’s picture

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.

JohnAlbin’s picture

Title: Need unrendered menu tree from Block Reference CCK block ID data » Add API to obtain raw menu data (not the render element)
Status: Postponed (maintainer needs more info) » Needs review
FileSize
8.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?

gmclelland’s picture

JohnAlbin’s picture

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.

solotandem’s picture

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.

rooby’s picture

Issue summary: View changes

Is #13 likely to be considered?

zmove’s picture

Wow, 5 years old issue that became active again 2 years ago...

Any chance to see that implemented (or do you have another module to suggest to generate menu tree that would be compatible with third parti module ? (example jquery Menu)) ?

  • JohnAlbin committed 79ee780 on 8.x-1.x
    Issue #907292: Add API to obtain raw menu data (not the render element)