1

Didn't thought I would have to ask this question. But yes, it's true. It seems you can't have a separate child menu in Wordpress?

I'm absolutely not a beginner on Wordpress. Have worked and developed in it for years.

However, it might be possible to do a big walkaround to get the separate child/sub menu. But what I would like to get an answer of here is more like;

Is it really true there's no simple built-in solution?

I have really searched on this site and other sites for answers but struggled to find an answer. It seems to be all about drop downs. I'm soooo tired of drop downs now!

Can say I'm running Woocommerce as well. But no, there was no answer in their's documentation either. A lot about "secondary menus". But that's not the same. I need the parent child relationship.

EDIT:

Following code example and output example has been added/changed to work as an example of a case scenario:

Here is my code:

    <nav class="parent">
        <?php
        wp_nav_menu(
            array(
                'theme_location'  => 'primary',
                'container_class' => 'primary-navigation',
                )
        );
        ?>
    </nav><!-- #parent -->

    // Following menu should only be shown if the selected menu item from the above menu has child items. Show them here below. How do I make these two menus to have a connection to each other?
    <nav class="child">
        <?php
        wp_nav_menu(
            array(
                'theme_location'  => 'primary',
                'container_class' => 'primary-child-navigation',
                )
        );
        ?>
    </nav><!-- #child -->



The output result would be something like this:


Home | Bags | Shoes | Hats

Backpacks | Weekend Bags | Travel Cases | Handhelds



And now we are on the Weekend Bag page!




Simple as that!

Edit 2:

First problem is that depth attribute doesn't seems to work for wp_nav_menu(). Can't have just top level?

2

Found the solution. Put this in your function.php file:

// add hook
add_filter( 'wp_nav_menu_objects', 'my_wp_nav_menu_objects_sub_menu', 10, 2 );
// filter_hook function to react on sub_menu flag
function my_wp_nav_menu_objects_sub_menu( $sorted_menu_items, $args ) {
  if ( isset( $args->sub_menu ) ) {
    $root_id = 0;

    // find the current menu item
    foreach ( $sorted_menu_items as $menu_item ) {
      if ( $menu_item->current ) {
        // set the root id based on whether the current menu item has a parent or not
        $root_id = ( $menu_item->menu_item_parent ) ? $menu_item->menu_item_parent : $menu_item->ID;
        break;
      }
    }

    // find the top level parent
    if ( ! isset( $args->direct_parent ) ) {
      $prev_root_id = $root_id;
      while ( $prev_root_id != 0 ) {
        foreach ( $sorted_menu_items as $menu_item ) {
          if ( $menu_item->ID == $prev_root_id ) {
            $prev_root_id = $menu_item->menu_item_parent;
            // don't set the root_id to 0 if we've reached the top of the menu
            if ( $prev_root_id != 0 ) $root_id = $menu_item->menu_item_parent;
            break;
          } 
        }
      }
    }
    $menu_item_parents = array();
    foreach ( $sorted_menu_items as $key => $item ) {
      // init menu_item_parents
      if ( $item->ID == $root_id ) $menu_item_parents[] = $item->ID;
      if ( in_array( $item->menu_item_parent, $menu_item_parents ) ) {
        // part of sub-tree: keep!
        $menu_item_parents[] = $item->ID;
      } else if ( ! ( isset( $args->show_parent ) && in_array( $item->ID, $menu_item_parents ) ) ) {
        // not part of sub-tree: away with it!
        unset( $sorted_menu_items[$key] );
      }
    }

    return $sorted_menu_items;
  } else {
    return $sorted_menu_items;
  }
}

Then use it this way:

<?php
wp_nav_menu(
    array(
        'theme_location'    => 'primary',
        'container_class'   => 'primary-navigation',
        'depth' => 1

        )
);
wp_nav_menu(
    array(
        'theme_location'    => 'primary',
        'container_class'   => 'primary-child-navigation',
        'sub_menu'       => true

        )
);
?>
1

What exactly do you mean by separate child menu? Could you provide a use case?

The way I understand your question at this point is that you want to inject a separate menu into your main menu without the items being added as child items in the back-end.

I have done something similar a few years back if I understand your question correctly, so it's most likely possible. There is a way to add a menu in combination with the main menu, you would need to reconstruct the menu though.

See the following:

https://codex.wordpress.org/Class_Reference/Walker

  • I have edited my post now. Please take a look at that again. Would it really be necessary to use the walker class? WP don't have a more simple way to do it? I mean, it's not an uncommon thing I want to achieve. – Peter Westerlund Mar 7 '17 at 11:54
  • Why don't you just use one menu with child items? – Svartbaard Mar 7 '17 at 12:56
  • Because you can't get the kind of output layout I want then. That the submenu is on the row below. I guess it would be possible if the submenu had absolute positioning with css. But it wouldn't be the best and most neat solution. – Peter Westerlund Mar 7 '17 at 13:07
  • I think you can definitely get the kind of output you require. Just add floats to the child menu items and clear after. But you would most likely need to use absolute positioning on the sub menu itself. My point is, the functionality is there, its the front end that's the problem. If you are not keen on writing the css yourself take a look at a plugin like: wordpress.org/plugins/megamenu – Svartbaard Mar 7 '17 at 13:24
  • I claim the opposite. I have good knowledge in CSS but this situation is a functionality problem. Let's say I want the child menu as a left column/sidebar then? That's not uncommon either. How do I do then? – Peter Westerlund Mar 7 '17 at 13:28
0

I had a similar problem, and was equally surprised that WP doesn't make this easy. I tried various 'functions scripts' but all had issues. Peter - I thought your script here was what I needed but it seemed to ignore the 'order' option WP offers for every page.

I ended doing most of it with CSS, with just a small piece of PHP in page.php

<?php if(!$post->post_parent){
$children = wp_list_pages("title_li=&child_of=".$post->ID."&echo=0");
}else{
if($post->ancestors)
{
$ancestors = end($post->ancestors);
$children = wp_list_pages("title_li=&child_of=".$ancestors."&echo=0");
}
}
if ($children) {
?>
<ul> <?php echo $children; ?></ul>
<?php } ?>

This is based on a post made by Mike Lee . Very simple and works perfectly for me.

0

Hello i have two functions for you:

1) Using this function you can get navigation menu children by post id:

function get_the_nav_menu_children_by_post_id($post_id)
{
    global $wpdb;
    $results = $wpdb->get_results("SELECT post_id FROM `wp_posts` p join wp_postmeta m ON p.ID = m.post_id WHERE post_type = 'nav_menu_item' and meta_key = '_menu_item_object_id' and meta_value = $post_id");

    if (count($results)) {
        $result = $results[0];
        if($result->post_id){
            $menu_id = $result->post_id;
            $items = $wpdb->get_results("select * from wp_posts where ID in (SELECT meta_value FROM `wp_posts` p join wp_postmeta m on p.ID = m.post_id  WHERE p.ID in (SELECT post_id from wp_postmeta where meta_key = '_menu_item_menu_item_parent' and meta_value = $menu_id) and meta_key = '_menu_item_object_id')");
            return $items;
        }
    }
    return false;
}

2) Or by menu_id of item in navigation:

function get_the_nav_children($menu_id){
    global $wpdb;
    $items = $wpdb->get_results("select * from wp_posts where ID in (SELECT meta_value FROM `wp_posts` p join wp_postmeta m on p.ID = m.post_id  WHERE p.ID in (SELECT post_id from wp_postmeta where meta_key = '_menu_item_menu_item_parent' and meta_value = $menu_id) and meta_key = '_menu_item_object_id')");
    return $items;
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.