$conf, $runtime; function_exists('chdir') AND chdir(APP_PATH); $r = 'mysql' == $conf['cache']['type'] ? website_set('runtime', $runtime) : cache_set('runtime', $runtime); } function runtime_truncate() { global $conf; 'mysql' == $conf['cache']['type'] ? website_set('runtime', '') : cache_delete('runtime'); } register_shutdown_function('runtime_save'); ?>How to get a separate child menu?|Programmer puzzle solving
最新消息:Welcome to the puzzle paradise for programmers! Here, a well-designed puzzle awaits you. From code logic puzzles to algorithmic challenges, each level is closely centered on the programmer's expertise and skills. Whether you're a novice programmer or an experienced tech guru, you'll find your own challenges on this site. In the process of solving puzzles, you can not only exercise your thinking skills, but also deepen your understanding and application of programming knowledge. Come to start this puzzle journey full of wisdom and challenges, with many programmers to compete with each other and show your programming wisdom! Translated with DeepL.com (free version)

How to get a separate child menu?

matteradmin8PV0评论

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?

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?

Share Improve this question edited Mar 7, 2017 at 16:50 Peter Westerlund asked Mar 7, 2017 at 6:59 Peter WesterlundPeter Westerlund 1,0775 gold badges14 silver badges31 bronze badges
Add a comment  | 

4 Answers 4

Reset to default 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

        )
);
?>

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;
}

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/Class_Reference/Walker

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.

Articles related to this article

Post a comment

comment list (0)

  1. No comments so far