Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 26 You must be signed in to star a gist
  • Fork 10 You must be signed in to fork a gist
  • Save kucrut/3804376 to your computer and use it in GitHub Desktop.
Save kucrut/3804376 to your computer and use it in GitHub Desktop.
Proof of concept for how to add new fields to nav_menu_item posts in the WordPress menu editor.
<?php
/**
* Proof of concept for how to add new fields to nav_menu_item posts in the WordPress menu editor.
* @author Weston Ruter (@westonruter), X-Team
*/
add_action( 'init', array( 'XTeam_Nav_Menu_Item_Custom_Fields', 'setup' ) );
class XTeam_Nav_Menu_Item_Custom_Fields {
static $options = array(
'item_tpl' => '
<p class="additional-menu-field-{name} description description-thin">
<label for="edit-menu-item-{name}-{id}">
{label}<br>
<input
type="{input_type}"
id="edit-menu-item-{name}-{id}"
class="widefat code edit-menu-item-{name}"
name="menu-item-{name}[{id}]"
value="{value}">
</label>
</p>
',
);
static function setup() {
if ( !is_admin() )
return;
$new_fields = apply_filters( 'xteam_nav_menu_item_additional_fields', array() );
if ( empty($new_fields) )
return;
self::$options['fields'] = self::get_fields_schema( $new_fields );
add_filter( 'wp_edit_nav_menu_walker', function () {
return 'XTeam_Walker_Nav_Menu_Edit';
});
//add_filter( 'xteam_nav_menu_item_additional_fields', array( __CLASS__, '_add_fields' ), 10, 5 );
add_action( 'save_post', array( __CLASS__, '_save_post' ), 10, 2 );
}
static function get_fields_schema( $new_fields ) {
$schema = array();
foreach( $new_fields as $name => $field) {
if (empty($field['name'])) {
$field['name'] = $name;
}
$schema[] = $field;
}
return $schema;
}
static function get_menu_item_postmeta_key($name) {
return '_menu_item_' . $name;
}
/**
* Inject the
* @hook {action} save_post
*/
static function get_field( $item, $depth, $args ) {
$new_fields = '';
foreach( self::$options['fields'] as $field ) {
$field['value'] = get_post_meta($item->ID, self::get_menu_item_postmeta_key($field['name']), true);
$field['id'] = $item->ID;
$new_fields .= str_replace(
array_map(function($key){ return '{' . $key . '}'; }, array_keys($field)),
array_values(array_map('esc_attr', $field)),
self::$options['item_tpl']
);
}
return $new_fields;
}
/**
* Save the newly submitted fields
* @hook {action} save_post
*/
static function _save_post($post_id, $post) {
if ( $post->post_type !== 'nav_menu_item' ) {
return $post_id; // prevent weird things from happening
}
foreach( self::$options['fields'] as $field_schema ) {
$form_field_name = 'menu-item-' . $field_schema['name'];
// @todo FALSE should always be used as the default $value, otherwise we wouldn't be able to clear checkboxes
if (isset($_POST[$form_field_name][$post_id])) {
$key = self::get_menu_item_postmeta_key($field_schema['name']);
$value = stripslashes($_POST[$form_field_name][$post_id]);
update_post_meta($post_id, $key, $value);
}
}
}
}
// @todo This class needs to be in it's own file so we can include id J.I.T.
// requiring the nav-menu.php file on every page load is not so wise
require_once ABSPATH . 'wp-admin/includes/nav-menu.php';
class XTeam_Walker_Nav_Menu_Edit extends Walker_Nav_Menu_Edit {
function start_el(&$output, $item, $depth, $args) {
$item_output = '';
parent::start_el($item_output, $item, $depth, $args);
// Inject $new_fields before: <div class="menu-item-actions description-wide submitbox">
if ( $new_fields = XTeam_Nav_Menu_Item_Custom_Fields::get_field( $item, $depth, $args ) ) {
$item_output = preg_replace('/(?=<div[^>]+class="[^"]*submitbox)/', $new_fields, $item_output);
}
$output .= $item_output;
}
}
// Somewhere in config...
add_filter( 'xteam_nav_menu_item_additional_fields', 'mytheme_menu_item_additional_fields' );
function mytheme_menu_item_additional_fields( $fields ) {
$fields['color'] = array(
'name' => 'color',
'label' => __('Color', 'xteam'),
'container_class' => 'link-color',
'input_type' => 'color',
);
return $fields;
}
@westonruter
Copy link

@kucrut great use of filters for providing the additional fields.

@gokul357
Copy link

Great Tutorial ....

How do i get the custom filed value?

Is this right way?

$a = get_post_meta($item->object_id,'custom_field',true);

or any other ..?

@native-apps
Copy link

Hmm. This didn't work for me either. Is there any other sources online about adding new input fields to the wordpress menu editor?

@lenanghai
Copy link

how to get additional fileds value bro ?

@folbert
Copy link

folbert commented Oct 1, 2015

For anyone else coming here wondering how to get the value:

You need to prepend your field name with "_menu_item". So if you have a field name "anchor":

get_post_meta($item->ID, '_menu_item_anchor', true)

@JacobDB
Copy link

JacobDB commented Aug 5, 2016

Would you be able to help me figure out how to make this work for a checkbox? Also a trimmed down version for a single field would be awesome (but I can probably figure that out on my own).

@Blackbam
Copy link

For anyone who wonders how to use on the frontend:

add_filter( 'nav_menu_link_attributes', 'my_nav_menu_attribs', 10, 3 );

function my_nav_menu_attribs( $atts, $item, $args ) {
  $atts['data-mydata'] = get_post_meta($item->ID, '_menu_item_mydata', true);
  return $atts;
}

@diegoversiani
Copy link

@kucrut, thanks for sharing!

Does anyone know how to display the additional fields in the menu editor inside Customizer?

@BramPeerlings
Copy link

@JacobDB: Did you get the checkbox to work? I've managed to convert the fields, but haven't yet been succesful in saving (and retrieving) them to/from the database.

@Nisha9219
Copy link

If anyone here - how to add checkbox and/or select input ?

@hughc
Copy link

hughc commented Mar 20, 2018

if anyone gets to here, this is now packaged into a library that you can use

@joefrey
Copy link

joefrey commented Mar 26, 2018

How to do when there's two or more fields 'item_tpl', 'item_tpl2', 'item_tpl3'

I got an error when I do this code below.

$new_fields .= str_replace(
array_map(function($key){ return '{' . $key . '}'; }, array_keys($field)),
array_values(array_map('esc_attr', $field)),
self::$options['item_tpl', 'item_tpl2', 'item_tpl3']
);

Please help Thanks!

Copy link

ghost commented May 13, 2019

Hi friends,how to add checkbox and/or select input ?
and how to get values ??

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment