User login

Fixing Menu Block for menu items with the same path (that also have another valid path)

"exanded" elements of a menu-item-rooted tree aren't expanded
http://drupal.org/node/398888

Working modified function (the patch has more):

<?php
/**
 * Get the data structure representing a named menu tree, based on the current page.
 *
 * The tree order is maintained by storing each parent in an individual
 * field, see http://drupal.org/node/141866 for more.
 *
 * @param $menu_name
 *   The named menu links to return
 * @return
 *   An array of menu links, in the order they should be rendered. The array
 *   is a list of associative arrays -- these have two keys, link and below.
 *   link is a menu item, ready for theming as a link. Below represents the
 *   submenu below the link if there is one, and it is a subtree that has the
 *   same structure described for the top-level array.
 */
function menu_tree_page_data($menu_name = 'navigation') {
  static $tree = array();

  // Load the menu item corresponding to the current page.
  if ($item = menu_get_item()) {
    // Generate a cache ID (cid) specific for this page.
    $cid = 'links:'. $menu_name .':page-cid:'. $item['href'] .':'. (int)$item['access'];

    if (!isset($tree[$cid])) {
      // If the static variable doesn't have the data, check {cache_menu}.
      $cache = cache_get($cid, 'cache_menu');
      if ($cache && isset($cache->data)) {
        // If the cache entry exists, it will just be the cid for the actual data.
        // This avoids duplication of large amounts of data.
        $cache = cache_get($cache->data, 'cache_menu');
        if ($cache && isset($cache->data)) {
          $data = $cache->data;
        }
      }
      // If the tree data was not in the cache, $data will be NULL.
      if (TRUE || !isset($data)) {
        // Build and run the query, and build the tree.
        if ($item['access']) {
          // Check whether a menu link exists that corresponds to the current path.
          $href = (isset($item['map'])) ? implode('/', $item['map']) : $item['href'];
          $args = array($menu_name, $href); // $item['href']);
          $placeholders = "'%s'";
          if (drupal_is_front_page()) {
            $args[] = '<front>';
            $placeholders .= ", '%s'";
          }
          $parents = db_fetch_array(db_query("SELECT p1, p2, p3, p4, p5, p6, p7, p8 FROM {menu_links} WHERE menu_name = '%s' AND link_path IN (". $placeholders .")", $args));
drupal_set_message('<pre>'.var_export($args,TRUE).'</pre>'); // @DEBUG
drupal_set_message('<pre>'.var_export($parents,TRUE).'</pre>'); // @DEBUG
          if (empty($parents)) {
            // If no link exists, we may be on a local task that's not in the links.
            // TODO: Handle the case like a local task on a specific node in the menu.
            $parents = db_fetch_array(db_query("SELECT p1, p2, p3, p4, p5, p6, p7, p8 FROM {menu_links} WHERE menu_name = '%s' AND link_path = '%s'", $menu_name, $item['tab_root']));
          }
          // We always want all the top-level links with plid == 0.
          $parents[] = '0';

          // Use array_values() so that the indices are numeric for array_merge().
          $args = $parents = array_unique(array_values($parents));
          $placeholders = implode(', ', array_fill(0, count($args), '%d'));
          $expanded = variable_get('menu_expanded', array());
          // Check whether the current menu has any links set to be expanded.
          if (in_array($menu_name, $expanded)) {
            // Collect all the links set to be expanded, and then add all of
            // their children to the list as well.
            do {
              $result = db_query("SELECT mlid FROM {menu_links} WHERE menu_name = '%s' AND expanded = 1 AND has_children = 1 AND plid IN (". $placeholders .') AND mlid NOT IN ('. $placeholders .')', array_merge(array($menu_name), $args, $args));
              $num_rows = FALSE;
              while ($item = db_fetch_array($result)) {
                $args[] = $item['mlid'];
                $num_rows = TRUE;
              }
              $placeholders = implode(', ', array_fill(0, count($args), '%d'));
            } while ($num_rows);
          }
          array_unshift($args, $menu_name);
        }
        else {
          // Show only the top-level menu items when access is denied.
          $args = array($menu_name, '0');
          $placeholders = '%d';
          $parents = array();
        }
        // Select the links from the table, and recursively build the tree. We
        // LEFT JOIN since there is no match in {menu_router} for an external
        // link.
        $data['tree'] = menu_tree_data(db_query("
          SELECT m.load_functions, m.to_arg_functions, m.access_callback, m.access_arguments, m.page_callback, m.page_arguments, m.title, m.title_callback, m.title_arguments, m.type, m.description, ml.*
          FROM {menu_links} ml LEFT JOIN {menu_router} m ON m.path = ml.router_path
          WHERE ml.menu_name = '%s' AND ml.plid IN (". $placeholders .")
          ORDER BY p1 ASC, p2 ASC, p3 ASC, p4 ASC, p5 ASC, p6 ASC, p7 ASC, p8 ASC, p9 ASC", $args), $parents);
        $data['node_links'] = array();
        menu_tree_collect_node_links($data['tree'], $data['node_links']);
        // Cache the data, if it is not already in the cache.
        $tree_cid = _menu_tree_cid($menu_name, $data);
        if (!cache_get($tree_cid, 'cache_menu')) {
          cache_set($tree_cid, $data, 'cache_menu');
        }
        // Cache the cid of the (shared) data using the page-specific cid.
        cache_set($cid, $tree_cid, 'cache_menu');
      }
      // Check access for the current user to each item in the tree.
      menu_tree_check_access($data['tree'], $data['node_links']);
      $tree[$cid] = $data['tree'];
    }
    return $tree[$cid];
  }

  return array();
}
?>

#

array (
  0 => 'primary-links',
  1 => 'product/34/features',
)

#

array (
  'p1' => '4259',
  'p2' => '115',
  'p3' => '6221',
  'p4' => '0',
  'p5' => '0',
  'p6' => '0',
  'p7' => '0',
  'p8' => '0',
)

Needed an extra check that $item['map'] is an array - actually, that its array elements are strings - because sometimes (on node pages) it has is an ungodly object like the below, which caused a charming "recoverable fatal error". (See, it's not as easy to kill kittens as you might think listening to webchick and others go on about it; they do have nine lives after all.)

recoverable fatal error: Object of class stdClass could not be converted to string in /home/ben/code/example/drupal/sites/all/modules/menu_block/menu_block.module on line 568.

1 =>
    object(stdClass)[10]
      public 'nid' => string '249' (length=3)
      public 'type' => string 'productline' (length=11)
      public 'language' => string '' (length=0)
      public 'uid' => string '1' (length=1)
      public 'status' => string '1' (length=1)
      public 'created' => string '1239718177' (length=10)
      public 'changed' => string '1259578258' (length=10)
      public 'comment' => string '0' (length=1)
      public 'promote' => string '1' (length=1)
      public 'moderate' => string '0' (length=1)
      public 'sticky' => string '0' (length=1)
      public 'tnid' => string '0' (length=1)
      public 'translate' => string '0' (length=1)
      public 'vid' => string '2246' (length=4)
      public 'revision_uid' => string '1' (length=1)
      public 'title' => string 'Sapphire' (length=8)
      public 'body' => string '<div class="field field-type-text field-field-subhead">
    <div class="field-items">
            <div class="field-item odd">
                    <p>The Gold Standard for the Silver Screen.</p>
        </div>
        </div>
</div>
<div class="field field-type-text field-field-features">
    <div class="field-items">
            <div class="field-item odd">
                    <p>The gold standard for visual effects, Sapphire equips digital artists with a collection of more than 200 state-of-the-art image p'... (length=3147)
      public 'log' => string '' (length=0)
      public 'revision_timestamp' => string '1259578258' (length=10)
      public 'format' => string '0' (length=1)
      public 'name' => string 'admin' (length=5)
      public 'picture' => string '' (length=0)
      public 'data' => string 'a:0:{}' (length=6)
      public 'path' => string 'product/sapphire' (length=16)
      public 'field_subhead' =>
        array
          0 =>
            array
              ...
      public 'field_features' =>
        array
          0 =>
            array
              ...
      public 'field_teaser' =>
        array
          0 =>
            array
              ...
      public 'field_lefttear' =>
        array
          0 =>
            array
              ...
      public 'field_footertear' =>
        array
          0 =>
            array
              ...
      public 'taxonomy' =>
        array
          empty
      public 'page_title' => string 'Example Product' (length=15)
      public 'nodewords' =>
        array
          empty
      public 'build_mode' => int 0
      public 'readmore' => boolean false
      public 'content' =>
        array
          'field_subhead' =>
            array
              ...
          'field_features' =>
            array
              ...
          '#pre_render' =>
            array
              ...
          'body' =>
            array
              ...
          '#content_extra_fields' =>
            array
              ...
          'field_teaser' =>
            array
              ...
          'products_node_content_1' =>
            array
              ...
          'group_pagegraphics' =>
            array
              ...
          '#title' => null
          '#description' => null
          '#children' => string '<div class="field field-type-text field-field-subhead">
    <div class="field-items">
            <div class="field-item odd">
                    <p>The Gold Standard for the Silver Screen.</p>
        </div>
        </div>
</div>
<div class="field field-type-text field-field-features">
    <div class="field-items">
            <div class="field-item odd">
                    <p>The gold standard for visual effects, Sapphire equips digital artists with a collection of more than 200 state-of-the-art image p'... (length=3147)
          '#printed' => boolean true
      public 'links' =>
        array
          'flag-reviewed' =>
            array
              ...

boolean true

Searched words: 
menu block not expanding

Comments

Post new comment

The content of this field is kept private and will not be shown publicly.
  • You may post code using <code>...</code> (generic) or <?php ... ?> (highlighted PHP) tags.
  • You can use Markdown syntax to format and style the text. Also see Markdown Extra for tables, footnotes, and more.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <img> <blockquote> <small> <h2> <h3> <h4> <h5> <h6> <sub> <sup> <p> <br> <strike> <table> <tr> <td> <thead> <th> <tbody> <tt> <output>
  • Lines and paragraphs break automatically.

More information about formatting options

By submitting this form, you accept the Mollom privacy policy.