How is custom menu hierarchy output handled?

I’m looking to pass custom nav_menus through an RSS feed so I can grab them on other sites to create the same custom menu on multiple sites.

What I can’t figure out by looking through the database is how WP is storing the data it needs to know which items are parent>child related for hierarchy. How does it know to output the “child” pages as a separate ul even if they aren’t “officially” set as parent>child (from edit post screen), only visually in the Menus area?

I can look at just the post type of nav_menu_item in the database and the menu_order column lists the items in top to bottom order but nothing seems to reference the menu>submenu relationship.

Thanks for anything you can tell me.

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

  • Each nav menu item is stored a post type named nav_menu_item.
  • The horizontal position is stored in the column menu_order
  • The vertical position (hierarchy) is stored as post meta field named _menu_item_menu_item_parent holding the parent nav_menu_item ID.

To create nested lists WordPress looks for _menu_item_menu_item_parent on each item, and if there is an item with that ID those posts will be grouped in a new sub list. That is basically what the class Walker_Nav_Menu does.

To illustrate that, use a little plugin:

<?php
/**
 * Plugin Name: Inspect Nav Menu Items
 * Plugin URI:  http://wordpress.stackexchange.com/q/70872
 */

add_filter( 'wp_nav_menu_args', 'wpse_70872_inspect_nav_menu_items' );

function wpse_70872_inspect_nav_menu_items( $dummy = 1 )
{
    if ( 'wp_nav_menu_args' === current_filter() )
    {
        add_action( 'shutdown', __FUNCTION__ );
        return $dummy;
    }

    // If we made it so far this function was called on 'shutdown'.
    $nav_items = get_posts(
        array (
            'numberposts' => -1,
            'post_type'   => 'nav_menu_item'
        )
    );

    $out = array ();

    foreach ( $nav_items as $nav_item )
    {
        $out[] = array (
            // general post data
            'post_data' => $nav_item,
            // meta data
            'meta' => get_post_custom( $nav_item->ID ),
            // Name of the menu
            'terms' => wp_get_object_terms( $nav_item->ID, 'nav_menu' ),
        );
    }

    print '<pre>' . esc_html( var_export( $out, TRUE ) ) . '</pre>';
}

The result might look like this:

array (
  0 => 
  array (
    'post_data' => 
    stdClass::__set_state(array(
       'ID' => 695,
       'post_author' => '1',
       'post_date' => '2012-10-29 23:24:13',
       'post_date_gmt' => '2012-10-29 23:24:13',
       'post_content' => ' ',
       'post_title' => '',
       'post_excerpt' => '',
       'post_status' => 'publish',
       'comment_status' => 'open',
       'ping_status' => 'open',
       'post_password' => '',
       'post_name' => '695',
       'to_ping' => '',
       'pinged' => '',
       'post_modified' => '2012-10-29 23:24:13',
       'post_modified_gmt' => '2012-10-29 23:24:13',
       'post_content_filtered' => '',
       'post_parent' => 0,
       'guid' => 'http://wpse.mu.wp/?p=695',
       'menu_order' => 9,
       'post_type' => 'nav_menu_item',
       'post_mime_type' => '',
       'comment_count' => '0',
       'filter' => 'raw',
    )),
    'meta' => 
    array (
      '_menu_item_type' => 
      array (
        0 => 'taxonomy',
      ),
      '_menu_item_menu_item_parent' => 
      array (
        0 => '693',
      ),
      '_menu_item_object_id' => 
      array (
        0 => '12',
      ),
      '_menu_item_object' => 
      array (
        0 => 'category',
      ),
      '_menu_item_target' => 
      array (
        0 => '',
      ),
      '_menu_item_classes' => 
      array (
        0 => 'a:1:{i:0;s:0:"";}',
      ),
      '_menu_item_xfn' => 
      array (
        0 => '',
      ),
      '_menu_item_url' => 
      array (
        0 => '',
      ),
    ),
    'terms' => 
    array (
      0 => 
      stdClass::__set_state(array(
         'term_id' => '105',
         'name' => 'Test 1',
         'slug' => 'test-1',
         'term_group' => '0',
         'term_taxonomy_id' => '106',
         'taxonomy' => 'nav_menu',
         'description' => '',
         'parent' => '0',
         'count' => '9',
      )),
    ),
  ),
  1 => 
  array (
    'post_data' => 
    stdClass::__set_state(array(
       'ID' => 694,
       'post_author' => '1',
       'post_date' => '2012-10-29 23:24:12',
       'post_date_gmt' => '2012-10-29 23:24:12',
       'post_content' => ' ',
       'post_title' => '',
       'post_excerpt' => '',
       'post_status' => 'publish',
       'comment_status' => 'open',
       'ping_status' => 'open',
       'post_password' => '',
       'post_name' => '694',
       'to_ping' => '',
       'pinged' => '',
       'post_modified' => '2012-10-29 23:24:12',
       'post_modified_gmt' => '2012-10-29 23:24:12',
       'post_content_filtered' => '',
       'post_parent' => 0,
       'guid' => 'http://wpse.mu.wp/?p=694',
       'menu_order' => 8,
       'post_type' => 'nav_menu_item',
       'post_mime_type' => '',
       'comment_count' => '0',
       'filter' => 'raw',
    )),
    'meta' => 
    array (
      '_menu_item_type' => 
      array (
        0 => 'taxonomy',
      ),
      '_menu_item_menu_item_parent' => 
      array (
        0 => '693',
      ),
      '_menu_item_object_id' => 
      array (
        0 => '11',
      ),
      '_menu_item_object' => 
      array (
        0 => 'category',
      ),
      '_menu_item_target' => 
      array (
        0 => '',
      ),
      '_menu_item_classes' => 
      array (
        0 => 'a:1:{i:0;s:0:"";}',
      ),
      '_menu_item_xfn' => 
      array (
        0 => '',
      ),
      '_menu_item_url' => 
      array (
        0 => '',
      ),
    ),
    'terms' => 
    array (
      0 => 
      stdClass::__set_state(array(
         'term_id' => '105',
         'name' => 'Test 1',
         'slug' => 'test-1',
         'term_group' => '0',
         'term_taxonomy_id' => '106',
         'taxonomy' => 'nav_menu',
         'description' => '',
         'parent' => '0',
         'count' => '9',
      )),
    ),
  ),
  // … and so on. It is a long list.


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x