Hi
Lets say there is a menu Item called services, and under it there are lot of child menu items. Now i want to get a list of all children of services, possibly by views or custom php snippet.

Please Help

Comments

ankycooper’s picture

Can anyone Help Me Please

brian_c’s picture

I recently had to handle a similar requirement, but was unable to find a way of doing it efficiently with Drupal's various menu_* functions.

After looking at menu_block & submenutree modules, and the _menu_update_parental_status() function to see how they determine menu children (they all directly access the DB), I wrote a couple custom functions in our project's module to help with this, here's what I came up with:


// get menu link children of current page. Assumes current page's path only exists in one menu
function MODULENAME_get_menu_children(){
  $children = array();
  if( ( $current = db_fetch_array(db_query( 'select menu_name, mlid from menu_links where link_path = "%s"', $_GET['q'])) ) ){
    $result = db_query( 'select mlid, plid, link_path, link_title from menu_links where menu_name="%s" and plid=%d and hidden=0 order by weight, link_title', $current['menu_name'], $current['mlid'] );
    while( ( $row = db_fetch_array( $result ) ) ){
      $children[] = $row;
    }
  }
  return $children;
}

// get node IDs of child pages (based on menu children)
function MODULENAME_get_menu_children_nids(){
  $nids = array();
  $children = MODULENAME_get_menu_children();
  foreach( $children as $child ){
    if( substr( $child['link_path'], 0, 5 ) == 'node/' ){
      $nids[] = substr( $child['link_path'], 5 );
    }
  }
  return $nids;
}

The first function returns rows from the menu_links table, with link_path = 'node/123', etc. The second function attempts to extract node IDs from the results of the first.

Then, I wrote a View that accepts NID arguments (with "Allow multiple terms"), setup a "Listing" content-type, then in the node type's template (node-listing.tpl.php) I can embed the View with a single line of code:

  echo views_embed_view( 'my_view_name', 'default', implode( '+', MODULENAME_get_menu_children_nids() ) );
brian_c’s picture

One more thing... I ended up using views_argsort (http://drupal.org/project/views_argsort) to ensure the results came back from the View in the same order as the passed arguments.

Now I can simply create a Listing page, which automatically lists all child pages in the same order as the menu system, backed by the full power of Views for complete control and customization.

jimurl’s picture

Hi Brian,

Thanks, these two functions worked very well for me. Like you, I could not find a function within the menu_* family of standard drupal functions to do this, but your solution addressed the problem very well.

x_v’s picture

Works great!

Here is the Drupal 7 version for the code:

// get menu link children of current page. Assumes current page's path only exists in one menu
function mi_core_get_menu_children(){
  $children = array();

  $current = db_query("select menu_name, mlid from {menu_links} where link_path = :node", array(':node' => $_GET['q']));
  $current_info = array();
  foreach ($current as $value) {
    $current_info[] = $value;
  }

  if($current_info) {
    $result = db_query("select mlid, plid, link_path, link_title from {menu_links} where menu_name=:menu and plid=:mlid and hidden=0 order by weight, link_title", array(':menu' => $current_info[0]->menu_name, ':mlid' => $current_info[0]->mlid));
    foreach ($result as $row) {
      $children[] = $row;
    }
  }
  return $children;
}

// get node IDs of child pages (based on menu children)
function mi_core_get_menu_children_nids(){
  $nids = array();
  $children = mi_core_get_menu_children();
  foreach ($children as $value){
    if( substr( $value->link_path, 0, 5 ) == 'node/' ){
      $nids[] = substr( $value->link_path, 5 );
    }
  }
  return $nids;
}
jannis’s picture

Thanks for the great code x_v -- i wanted to use it from within Drupal (not modifying any files) here's how I used his code with a few additional lines to call it.

Make sure you enable 'PHP filter' module (part of core, and disabled by default). Go to the content, and edit, make sure you select 'PHP Code' from the 'Text Format' options.

Paste this code (it's x_v's code, with the function calls and formatting made):
This will create a list of all the children titles that link to the content! No outside drupal messing required.

// get menu link children of current page. Assumes current page's path only exists in one menu
function mi_core_get_menu_children(){
  $children = array();

  $current = db_query("select menu_name, mlid from {menu_links} where link_path = :node", array(':node' => $_GET['q']));
  $current_info = array();
  foreach ($current as $value) {
    $current_info[] = $value;
  }

  if($current_info) {
    $result = db_query("select mlid, plid, link_path, link_title from {menu_links} where menu_name=:menu and plid=:mlid and 
hidden=0 order by weight, link_title", array(':menu' => $current_info[0]->menu_name, ':mlid' => $current_info[0]->mlid));
    foreach ($result as $row) {
      $children[] = $row;
    }
  }
  return $children;
}

// get node IDs of child pages (based on menu children)
function mi_core_get_menu_children_nids(){
  $nids = array();
  $children = mi_core_get_menu_children();
  foreach ($children as $value){
    if( substr( $value->link_path, 0, 5 ) == 'node/' ){
      $nids[] = substr( $value->link_path, 5 );
    }
  }
  return $nids;
}

$kids = mi_core_get_menu_children();
$kidsnids = mi_core_get_menu_children_nids();

//print_r($kids);
//echo('<br>');

foreach($kids as $kid){
echo("<a href='/");
echo($kid->link_path);
echo("'>");
echo($kid->link_title);
echo("</a>");
echo('<br>');
       }