2

I'm creating a custom walker menu where I'm adding custom fields to the menu items, but I would like the fields to be specific to menu locations. I can get all the menu locations with the menu ID's assigned to them from:

$menu_locations = get_nav_menu_locations();

This outputs an array like:

array:2 [
  "main_nav" => 27
  "footer_nav" => 29
]

Or you can get all the menus but they don't have the theme locations with:

$menus = get_terms('nav_menu');

This outputs an an object list like:

array:3 [
  0 => {#762
    +"term_id": "28"
    +"name": "Footer Menu"
    +"slug": "footer-menu"
    +"term_group": "0"
    +"term_taxonomy_id": "28"
    +"taxonomy": "nav_menu"
    +"description": ""
    +"parent": "0"
    +"count": "1"
  }
  1 => {#761
    +"term_id": "27"
    +"name": "Menu 1"
    +"slug": "menu-1"
    +"term_group": "0"
    +"term_taxonomy_id": "27"
    +"taxonomy": "nav_menu"
    +"description": ""
    +"parent": "0"
    +"count": "11"
  }
]

My question is: Can you get the menu location of a specific menu by ID / name / slug? Or can you get the menu location by menu ID?

4 Answers 4

1

You'll find it much easier to control which fields are shown, by controlling which walker is used. Rather than trying to 'toggle' the fields inside the walker.

I also wanted to show a bunch of custom fields, and only show them on a menu at a particular menu location. So I used the following...

add_filter( 'wp_edit_nav_menu_walker', function( $walker, $menu_id ) {

    $menu_locations = get_nav_menu_locations();

    if ( $menu_locations['main_menu'] == $menu_id ) {
        return 'Walker_Nav_Menu_Custom';
    } else {
        return $walker;
    }

}, 10, 2); 
0

I found the solution for this issue and I'm going to post it here maybe someone else needs to add custom fields to the backend menu themselves. The best way of doing this as i found out is to call a different walker class for each backend menu.

This will be a long answer and i couldn't post all the code because of characters limitations but if you follow it closely you'll see that it's only missing the second Walker class which is exactly the same as the first one but with the differences posted here

The answer is based on this answer

https://wordpress.stackexchange.com/a/33495/75163

First create the two (or moore) menu locations:

register_nav_menus([
      'main_nav' => __('Main nav menu', 'textdomain'),
      'footer_nav' => __('Footer nav menu', 'textdomain'),
]);

Then Create your nav menus which you're going to use on your menu locations:

            $args = array(
                'theme_location' => 'main_nav',
                'menu' => '',
                'container' => 'div',
                'container_id' => '',
                'menu_class' => 'menu',
                'menu_id' => '',
                'echo' => true,
                'fallback_cb' => 'wp_page_menu',
                'before' => '',
                'after' => '',
                'link_before' => '',
                'link_after' => '',
                'items_wrap' => '<ul role="navigation" id="nav-primary" class="nav">%3$s</ul>',
                'depth' => 3,
            );

            wp_nav_menu($args);

AND:

$args = array(
                    'theme_location' => 'footer_nav',
                    'menu' => '',
                    'container' => '',
                    'container_id' => '',
                    'menu_class' => 'menu',
                    'menu_id' => '',
                    'echo' => true,
                    'fallback_cb' => 'wp_page_menu',
                    'before' => '',
                    'after' => '',
                    'link_before' => '',
                    'link_after' => '',
                    'items_wrap' => '%3$s',
                    'depth' => 2,
                );

                wp_nav_menu($args);

Select them in the menu locations section in Appearance -> Menus -> Manage Locations.

Now start creating your walker based on the example on top (this goes in your functions.php file):

/**
 * Saves new field to postmeta for navigation
 */
add_action('wp_update_nav_menu_item', 'custom_nav_update', 10, 3);
function custom_nav_update($menu_id, $menu_item_db_id, $args)
{   
    if (isset($_REQUEST['menu-item-custom']) && is_array($_REQUEST['menu-item-custom'])) {
        if (isset($_REQUEST['menu-item-custom'][$menu_item_db_id])) {
            $custom_value = $_REQUEST['menu-item-custom'][$menu_item_db_id];
            update_post_meta($menu_item_db_id, '_menu_item_custom', $custom_value);
        } else {
            $post_meta = get_post_meta($menu_item_db_id, '_menu_item_custom', true);
            if ($post_meta == "checked") {
                delete_post_meta($menu_item_db_id, '_menu_item_custom');
            }
        }
    }

    if (isset($_REQUEST['menu-item-icon']) && is_array($_REQUEST['menu-item-icon'])) {
        if (isset($_REQUEST['menu-item-icon'][$menu_item_db_id])) {
            $custom_value = $_REQUEST['menu-item-icon'][$menu_item_db_id];
            update_post_meta($menu_item_db_id, '_menu_item_icon', $custom_value);
        } else {
            $post_meta = get_post_meta($menu_item_db_id, '_menu_item_icon', true);
            $icons = lpCustomIconsList();
            foreach($icons as $icon => $icon_name)
            if ($post_meta == $icon) {
                delete_post_meta($menu_item_db_id, '_menu_item_icon');
            }
        }
    }
}

/**
 * Adds values of new field to $item object that will be passed to Walker_Nav_Menu_Edit_Custom
 * @param  int $menu_item item id
 * @return obj            the whole item
 */
add_filter( 'wp_setup_nav_menu_item','custom_nav_item' );
function custom_nav_item($menu_item) {
    $menu_item->custom = get_post_meta( $menu_item->ID, '_menu_item_custom', true );
    $menu_item->icon = get_post_meta( $menu_item->ID, '_menu_item_icon', true );
    return $menu_item;
}

/**
 * Creates a menu walker with custom Checkbox or Select box 
 *
 * @param $walker
 * @param $menu_id
 * @return string
 */
add_filter( 'wp_edit_nav_menu_walker', 'custom_nav_edit_walker',10,2 );
function custom_nav_edit_walker($walker,$menu_id) {
  $menu_locations = get_nav_menu_locations();

  $main_nav_obj = get_term( $menu_locations['main_nav'], 'nav_menu' );
  $footer_nav_obj = get_term( $menu_locations['footer_nav'], 'nav_menu' );
  if($main_nav_obj->term_id == $menu_id) {
    return 'BackendHeader';
  } elseif($footer_nav_obj->term_id == $menu_id) {
    return 'BackendFooter';
  } else {
    return $walker;
  }

}

These wakers are based on the Walker_Nav_Menu_Edit class

class BackendHeader extends Walker_Nav_Menu_Edit
{


    /**
     * @see Walker::start_el()
     * @since 3.0.0
     *
     * @param string $output Passed by reference. Used to append additional content.
     * @param object $item Menu item data object.
     * @param int $depth Depth of menu item. Used for padding.
     * @param array|object $args
     * @param int $id
     */
    function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 )
    {        global $_wp_nav_menu_max_depth;
        $_wp_nav_menu_max_depth = $depth > $_wp_nav_menu_max_depth ? $depth : $_wp_nav_menu_max_depth;

        $indent = ($depth) ? str_repeat("\t", $depth) : '';

        ob_start();
        $item_id = esc_attr($item->ID);
        $removed_args = array(
            'action',
            'customlink-tab',
            'edit-menu-item',
            'menu-item',
            'page-tab',
            '_wpnonce',
        );

        $original_title = '';
        if ('taxonomy' == $item->type) {
            $original_title = get_term_field('name', $item->object_id, $item->object, 'raw');
            if (is_wp_error($original_title))
                $original_title = false;
        } elseif ('post_type' == $item->type) {
            $original_object = get_post($item->object_id);
            $original_title = $original_object->post_title;
        }

        $classes = array(
            'menu-item menu-item-depth-' . $depth,
            'menu-item-' . esc_attr($item->object),
            'menu-item-edit-' . ((isset($_GET['edit-menu-item']) && $item_id == $_GET['edit-menu-item']) ? 'active' : 'inactive'),
        );

        $title = $item->title;

        if (!empty($item->_invalid)) {
            $classes[] = 'menu-item-invalid';
            /* translators: %s: title of menu item which is invalid */
            $title = sprintf(__('%s (Invalid)'), $item->title);
        } elseif (isset($item->post_status) && 'draft' == $item->post_status) {
            $classes[] = 'pending';
            /* translators: %s: title of menu item in draft status */
            $title = sprintf(__('%s (Pending)'), $item->title);
        }

        $title = empty($item->label) ? $title : $item->label;
        ?>
    <li id="menu-item-<?php echo $item_id; ?>" class="<?php echo implode(' ', $classes); ?>">
        <dl class="menu-item-bar">
            <dt class="menu-item-handle">
                <span class="item-title"><?php echo esc_html($title); ?></span>
                <span class="item-controls">
                    <span class="item-type"><?php echo esc_html($item->type_label); ?></span>
                    <span class="item-order hide-if-js">
                        <a href="<?php
                        echo wp_nonce_url(
                            add_query_arg(
                                array(
                                    'action' => 'move-up-menu-item',
                                    'menu-item' => $item_id,
                                ),
                                remove_query_arg($removed_args, admin_url('nav-menus.php'))
                            ),
                            'move-menu_item'
                        );
                        ?>" class="item-move-up"><abbr title="<?php esc_attr_e('Move up'); ?>">&#8593;</abbr></a>
                        |
                        <a href="<?php
                        echo wp_nonce_url(
                            add_query_arg(
                                array(
                                    'action' => 'move-down-menu-item',
                                    'menu-item' => $item_id,
                                ),
                                remove_query_arg($removed_args, admin_url('nav-menus.php'))
                            ),
                            'move-menu_item'
                        );
                        ?>" class="item-move-down"><abbr title="<?php esc_attr_e('Move down'); ?>">&#8595;</abbr></a>
                    </span>
                    <a class="item-edit" id="edit-<?php echo $item_id; ?>"
                       title="<?php esc_attr_e('Edit Menu Item'); ?>" href="<?php
                    echo (isset($_GET['edit-menu-item']) && $item_id == $_GET['edit-menu-item']) ? admin_url('nav-menus.php') : add_query_arg('edit-menu-item', $item_id, remove_query_arg($removed_args, admin_url('nav-menus.php#menu-item-settings-' . $item_id)));
                    ?>"><?php _e('Edit Menu Item'); ?></a>
                </span>
            </dt>
        </dl>

        <div class="menu-item-settings" id="menu-item-settings-<?php echo $item_id; ?>">
            <?php if ('custom' == $item->type) : ?>
                <p class="field-url description description-wide">
                    <label for="edit-menu-item-url-<?php echo $item_id; ?>">
                        <?php _e('URL'); ?><br/>
                        <input type="text" id="edit-menu-item-url-<?php echo $item_id; ?>"
                               class="widefat code edit-menu-item-url" name="menu-item-url[<?php echo $item_id; ?>]"
                               value="<?php echo esc_attr($item->url); ?>"/>
                    </label>
                </p>
            <?php endif; ?>
            <p class="description description-thin">
                <label for="edit-menu-item-title-<?php echo $item_id; ?>">
                    <?php _e('Navigation Label'); ?><br/>
                    <input type="text" id="edit-menu-item-title-<?php echo $item_id; ?>"
                           class="widefat edit-menu-item-title" name="menu-item-title[<?php echo $item_id; ?>]"
                           value="<?php echo esc_attr($item->title); ?>"/>
                </label>
            </p>

            <p class="description description-thin">
                <label for="edit-menu-item-attr-title-<?php echo $item_id; ?>">
                    <?php _e('Title Attribute'); ?><br/>
                    <input type="text" id="edit-menu-item-attr-title-<?php echo $item_id; ?>"
                           class="widefat edit-menu-item-attr-title"
                           name="menu-item-attr-title[<?php echo $item_id; ?>]"
                           value="<?php echo esc_attr($item->post_excerpt); ?>"/>
                </label>
            </p>

            <p class="field-link-target description">
                <label for="edit-menu-item-target-<?php echo $item_id; ?>">
                    <input type="checkbox" id="edit-menu-item-target-<?php echo $item_id; ?>" value="_blank"
                           name="menu-item-target[<?php echo $item_id; ?>]"<?php checked($item->target, '_blank'); ?> />
                    <?php _e('Open link in a new window/tab'); ?>
                </label>
            </p>

            <p class="field-css-classes description description-thin">
                <label for="edit-menu-item-classes-<?php echo $item_id; ?>">
                    <?php _e('CSS Classes (optional)'); ?><br/>
                    <input type="text" id="edit-menu-item-classes-<?php echo $item_id; ?>"
                           class="widefat code edit-menu-item-classes" name="menu-item-classes[<?php echo $item_id; ?>]"
                           value="<?php echo esc_attr(implode(' ', $item->classes)); ?>"/>
                </label>
            </p>

            <p class="field-xfn description description-thin">
                <label for="edit-menu-item-xfn-<?php echo $item_id; ?>">
                    <?php _e('Link Relationship (XFN)'); ?><br/>
                    <input type="text" id="edit-menu-item-xfn-<?php echo $item_id; ?>"
                           class="widefat code edit-menu-item-xfn" name="menu-item-xfn[<?php echo $item_id; ?>]"
                           value="<?php echo esc_attr($item->xfn); ?>"/>
                </label>
            </p>

            <p class="field-description description description-wide">
                <label for="edit-menu-item-description-<?php echo $item_id; ?>">
                    <?php _e('Description'); ?><br/>
                    <textarea id="edit-menu-item-description-<?php echo $item_id; ?>"
                              class="widefat edit-menu-item-description" rows="3" cols="20"
                              name="menu-item-description[<?php echo $item_id; ?>]"><?php echo esc_html($item->description); // textarea_escaped
                        ?></textarea>
                    <span
                        class="description"><?php _e('The description will be displayed in the menu if the current theme supports it.'); ?></span>
                </label>
            </p>
            <?php
            /*
             * This is the added field
             */
            ?>
            <p class="field-custom description description-wide">
                <label for="edit-menu-item-custom-<?php echo $item_id; ?>">
                    <?php _e('Checkbox'); ?><br/>
                    <input type="checkbox" id="edit-menu-item-custom-<?php echo $item_id; ?>"
                           class="widefat code edit-menu-item-custom"
                           name="menu-item-custom[<?php echo $item_id; ?>]" <?php if ($item->custom == 'checked') {
                        echo "checked";
                    } ?> value="checked"/>
                </label>
            </p>
            <?php
            /*
             * end added field
             */
            ?>
            <div class="menu-item-actions description-wide submitbox">
                <?php if ('custom' != $item->type && $original_title !== false) : ?>
                    <p class="link-to-original">
                        <?php printf(__('Original: %s'), '<a href="' . esc_attr($item->url) . '">' . esc_html($original_title) . '</a>'); ?>
                    </p>
                <?php endif; ?>
                <a class="item-delete submitdelete deletion" id="delete-<?php echo $item_id; ?>" href="<?php
                echo wp_nonce_url(
                    add_query_arg(
                        array(
                            'action' => 'delete-menu-item',
                            'menu-item' => $item_id,
                        ),
                        remove_query_arg($removed_args, admin_url('nav-menus.php'))
                    ),
                    'delete-menu_item_' . $item_id
                ); ?>"><?php _e('Remove'); ?></a> <span class="meta-sep"> | </span> <a class="item-cancel submitcancel"
                                                                                       id="cancel-<?php echo $item_id; ?>"
                                                                                       href="<?php echo esc_url(add_query_arg(array('edit-menu-item' => $item_id, 'cancel' => time()), remove_query_arg($removed_args, admin_url('nav-menus.php'))));
                                                                                       ?>#menu-item-settings-<?php echo $item_id; ?>"><?php _e('Cancel'); ?></a>
            </div>

            <input class="menu-item-data-db-id" type="hidden" name="menu-item-db-id[<?php echo $item_id; ?>]"
                   value="<?php echo $item_id; ?>"/>
            <input class="menu-item-data-object-id" type="hidden" name="menu-item-object-id[<?php echo $item_id; ?>]"
                   value="<?php echo esc_attr($item->object_id); ?>"/>
            <input class="menu-item-data-object" type="hidden" name="menu-item-object[<?php echo $item_id; ?>]"
                   value="<?php echo esc_attr($item->object); ?>"/>
            <input class="menu-item-data-parent-id" type="hidden" name="menu-item-parent-id[<?php echo $item_id; ?>]"
                   value="<?php echo esc_attr($item->menu_item_parent); ?>"/>
            <input class="menu-item-data-position" type="hidden" name="menu-item-position[<?php echo $item_id; ?>]"
                   value="<?php echo esc_attr($item->menu_order); ?>"/>
            <input class="menu-item-data-type" type="hidden" name="menu-item-type[<?php echo $item_id; ?>]"
                   value="<?php echo esc_attr($item->type); ?>"/>
        </div>
        <!-- .menu-item-settings-->
        <ul class="menu-item-transport"></ul>
        <?php
        $output .= ob_get_clean();
    }
}
/**
* The same as the one on top but with a different fiel
*/
class BackendFooter extends Walker_Nav_Menu_Edit
{

            /*
             * This is the added field
             */
            ?>
            <p class="field-icon description description-wide">
                <label for="edit-menu-item-icon-<?php echo $item_id; ?>">
                    <?php _e('Icon'); ?><br/>
                    <select id="edit-menu-item-icon-<?php echo $item_id; ?>" class="widefat code edit-menu-item-icon" name="menu-item-icon[<?php echo $item_id; ?>]">
                            <option <?php if('icon' == $item->icon) { echo "selected='selected'"; } ?> value="icon">Icon One</option>
<option <?php if('icon2' == $item->icon) { echo "selected='selected'"; } ?> value="icon2">Icon Two</option>
<option <?php if('icon3' == $item->icon) { echo "selected='selected'"; } ?> value="icon3">Icon Three</option>
                        <?php } ?>
                    </select>
                </label>
            </p>
            <?php
            /*
             * end added field
             */
            ?>

}
0

Simply transposing the array returned by get_nav_menu_locations() gives you a mapping from menu ID to menu location:

$menu_locations = \array_flip(\get_nav_menu_locations());
$menu_location = $menu_locations[$menu_id] ?? null; 
if ($menu_location === 'main_nav') {
  do_something();
}

This above code includes getting the menu location of a specific menu by ID.

If you don't have a menu ID but instead have the name or slug, you can use wp_get_nav_menu_object() first to get the ID:

$menu_term = \wp_get_nav_menu_object($menu_slug_name_id_or_wpterm);
$menu_id = \is_object($menu_term) ? $menu_term->term_id : null;

Then continue with the code above to get the location from the ID.

(wp_get_nav_menu_object() will also accept an ID or WP_Term, so you can throw whatever you have at it to get a WP_Term to get the ID.)

-1

wp_get_nav_menu_object( $menu );

Returns nav menu object when given a menu id, slug, or name. This is particularly useful for retrieving the name assigned to the custom menu.

http://codex.wordpress.org/Function_Reference/wp_get_nav_menu_object

3
  • 1
    You're right but this object doesn't have the menu location in it, meaning i have no way of comparing my current ID to the locations. {#762 +"term_id": 28 +"name": "Footer Menu" +"slug": "footer-menu" +"term_group": 0 +"term_taxonomy_id": 28 +"taxonomy": "nav_menu" +"description": "" +"parent": 0 +"count": 1 +"filter": "raw" } Jun 25, 2015 at 7:45
  • Is slug not the menu location? Jun 25, 2015 at 7:54
  • no, the menu location is te return of $menu_locations = get_nav_menu_locations(); but this gets me all the menu locations and i have no way of checking against it. I'd rather try to get the menu ID in the walker menu Jun 25, 2015 at 8:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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