Add Custom Fields to WordPress Menu Items

First a little backstory

A WordPress commit that I am personally very excited to finally see get merged into core is the addition of a wp_nav_menu_item_custom_fields hook!

As the author of the Nav Menu Roles plugin, I’ve needed to display custom fields on menu items. But in the admin, the menu items are displayed by the Walker_Nav_Menu_Edit class and there have never been hooks in there to customize the output. The only 2 options for customizing the output were inserting fields via JavaScript or entirely replacing the Walker with your own customized Walker via the wp_edit_nav_menu_walker filter.

A WordPress Menu item metabox displaying options for hiding or showing this menu item to users based on their role.

The latter is what I did in my plugin, but the problem with the walker filter is that There Can Be Only One!

There Can Be Only One Highlander GIF - Find & Share on GIPHY

So other plugins (and themes…. cough…. soooo many themes!) that also needed to add custom fields would add their own Walkers and we’d duel it out to see whose fields got displayed.

Then WordPress user Shazdeh had the brilliant idea to start inserting a standard hook in our own Walkers… figuring that if we all added that hook to our Walker and then all attached our fields to that hook, it would not matter whose Walker was being used by core all our plugins could be compatible. We essentially established a “community” action hook and it greatly reduced the number of people contacting me wondering why Nav Menu Role’s fields were not displaying.

I expected that to be the permanent solution as the original Trac ticket was opened by @ViperBond back in 2011.

Gaga Thoughts GIF - Find & Share on GIPHY

Originally it was blocked by another ticket concerning the limit of _POST variables… folks with ginormous menus would see their menus disappear when the _POST limit was exceeded and core didn’t want to make it easier for us to add fields. But that was fixed and this hook still languished. It would see a little traction and then nothing.

I actually went to my first contributor day to work on this specifically (it’s a 4 line patch, I thought it would be easy enough). I ended up spending the entire day trying to get VVV setup on my Windows machine so I could have the exact same environment as everyone else. Spoiler: I never did. I forget his name, but there was a gent who was trying so hard to help me and I thanked him, but it was so discouraging to go to a Contributor day and do nothing.

I’d pretty much given up hope on this one, but @MikeSchinkel picked it up and kept advocating for it. And now finally @SergeyBiryukov committed it! Even adding parity with the Customizer (which was another reason the patch had been rejected before). Hurray!!

Big thank you to everyone who has had a part in this over the years!

Leonardo Dicaprio Rap GIF - Find & Share on GIPHY

The Code Parts

Now that wp_nav_menu_item_custom_fields is in WordPress core, here’s a tutorial on how to use that new hook.

First, we’ll attach a callback to the new hook and use it to display a text input. Because the Walker displays multiple menu items we have to make sure the input is keyed with the menu item’s ID.

Since menu items are a WordPress custom post type, dealing with the data is same as adding and retrieving post_meta a regular post or page.

Finally, what do we do with this new data!? While this isn’t what my plugin does, it’s the simplest use-case I could think of… displaying some extra text after the menu title.

The three snippets together make a pretty solid minimal example for how to use this new hook. Full code can be downloaded here. At some point I should come back and do something with the new hooks in the Customizer too as I guess I finally need to update Nav Menu Roles!

Posted in

Leave a Comment