6

I need to attach meta data to every menu item, with a key 'foo'. Is it possible to do that, without editing core WP?

A quick look at the nav-menu files showed that no hooks exist near the place I want to add the input box (below Description, here - http://cl.ly/0v2Z0X1n2e1L431t0h1G)

4
  • As far as I know, it's totally not possible, however would be great if you elaborate your escenario so we can know exactly what are you trying to achieve ;) Commented Nov 13, 2011 at 4:16
  • My use case is something close to the 'class' option, but I need to provide a <select> item, instead of having users enter the class names.
    – Dogbert
    Commented Nov 13, 2011 at 7:46
  • You could add it per Javascript. There seems to be no other way.
    – fuxia
    Commented Nov 13, 2011 at 12:06
  • I'm gonna CRY!!!!11one
    – frnhr
    Commented Jan 22, 2013 at 0:13

2 Answers 2

5

here is a quick code that should do the job, paste this in your theme's functions.php file

basically what it does is hide all regular class input boxes and adds a new select dropdown which changes the value of the hidden input based on the selected value.

and it looks like this;

enter image description here

function menu_item_class_select(){
    global $pagenow;
    if ($pagenow == "nav-menus.php"){
    ?>
    <script>
    jQuery(document).ready(function(){
        function create_dd(v){
            //create dropdown
            var dd = jQuery('<select class="my_class"></select>');
            //create dropdown options
            //array with the options you want
            var classes = ["","class1","class2","class3"];
            jQuery.each(classes, function(i,val) {
                if (v == val){
                    dd.append('<option value="'+val+'" selected="selected">'+val+'</option>');
                }else{
                    dd.append('<option value="'+val+'">'+val+'</option>');
                }
            });
            return dd;
        }

        jQuery(".edit-menu-item-classes").each(function() {
            //add dropdown
            var t = create_dd(jQuery(this).val());
            jQuery(this).before(t);
            //hide all inputs
            jQuery(this).css("display","none");

        });
        //update input on selection
        jQuery(".my_class").bind("change", function() {
            var v = jQuery(this).val();
            var inp = jQuery(this).next();
            inp.attr("value",v);
        });
    });


    </script>
    <?php
    }
}
add_action('admin_footer','menu_item_class_select');
-1

this answer in here is little bit of overdoing. I prefer to do not interfere with walkers in this case so I did my job with more jquery involved.

add_action('wp_update_nav_menu_item', 'custom_nav_update', 10, 3);
function custom_nav_update($menu_id, $menu_item_db_id, $args)
{
    if (is_array($_REQUEST['menu-item-icon'])) {
        $custom_value = $_REQUEST['menu-item-icon'][$menu_item_db_id];
        update_post_meta($menu_item_db_id, '_menu_item_icon', $custom_value);
    }
}

function menu_item_class_select()
{
    global $pagenow;
    if ($pagenow == "nav-menus.php") {
        ?>
        <script>
            (function ($) {
                $(document).ready(function () {
                    var menu_item_collection = {};
                    var item_holder = $("#menu-to-edit");
                    menu_item_collection.items = item_holder.find("li");

                    // extract id of a menu item from this pattern (menu-item-109)
                    // which 109 is the id
                    function getId(item_id) {
                        var arrayed = item_id.split("-");
                        return arrayed[2];
                    }

                    // return template wrapped in jquery object
                    function extra_field(id, value) {
                        if (value === null) {
                            value = "";
                        }
                        var template = '<p class="field-title-attribute description description-wide">' +
                            '<label for="edit-menu-item-attr-title-108">' +
                            'icon' +
                            '<input type="text" class="widefat edit-menu-item-attr-title" name="menu-item-icon[' + id + ']" value="' + value + '">' +
                            '</label>' +
                            '</p>';

                        return $(template);
                    }

                    // ajax out to get metadata
                    function getMetaData(id, callback) {
                        $.ajax({
                            method: "POST",
                            url: "/wp-admin/admin-ajax.php",
                            data: {id: id, post_type: "menu", action: "menu_metadata"}
                        }).done(function (msg) {
                            callback(msg);
                        }).fail(function (msg) {
                            console.log("failed : " + msg);
                        });
                    }

                    // these lines of codes initialize menus with their custom attributes values
                    if (menu_item_collection.items.length > 0) {
                        var id;
                        menu_item_collection.items.each(function () {
                            id = getId($(this).attr("id"));
                            var _this = $(this);
                            getMetaData(id, function (msg) {
                                var attribute = (_this.find(".field-title-attribute"));
                                if (msg._menu_item_icon === 'undefined') {
                                    msg._menu_item_icon = "";
                                }
                                attribute.after(extra_field(getId(_this.attr('id')), msg._menu_item_icon[0]));
                                _this.addClass("icon-link-was-added");
                            });
                        });
                    }

                    // this listener interact with adding live menus
                    item_holder.on('DOMNodeInserted', function (e) {
                        try {
                            // sortable script code that they used made me to check upon whether our intended child is li or not
                            // yet i wrap this code into try catch because some nodes was`nt inserted to the dome
                            // and null pointer would cause undefined error some times
                            if (
                                !$(e.target).hasClass("icon-link-was-added") &&
                                $(e.target).is("li") &&
                                $(e.target).attr("id").search(/menu\-item\-[0-9]+/) !== -1) {

                                var attribute = ($(e.target).find(".field-title-attribute"));
                                attribute.after(extra_field(getId($(e.target).attr('id'))));
                                $(e.target).addClass("icon-link-was-added");
                            }
                        } catch (e) {
                            // silent
                        }
                    });
                });
            })(jQuery);
        </script>
        <?php
    }
}

add_action('admin_footer', 'menu_item_class_select');
0

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.