public
Last active

Proof of concept for how to add new fields to nav_menu_item posts in the WordPress menu editor.

  • Download Gist
nav-menu-item-custom-fields.php
PHP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
<?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() {
// @todo we can do some merging of provided options from WP options for from config
self::$options['fields'] = array(
'color' => array(
'name' => 'color',
'label' => __('Color', 'xteam'),
'container_class' => 'link-color',
'input_type' => 'color',
),
);
 
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' ) );
}
 
static function get_fields_schema() {
$schema = array();
foreach(self::$options['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 _add_fields($new_fields, $item_output, $item, $depth, $args) {
$schema = self::get_fields_schema($item->ID);
foreach($schema 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) {
if (get_post_type($post_id) !== 'nav_menu_item') {
return;
}
$fields_schema = self::get_fields_schema($post_id);
foreach($fields_schema as $field_schema) {
$form_field_name = 'menu-item-' . $field_schema['name'];
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);
}
}
}
 
}
 
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);
$new_fields = apply_filters( 'xteam_nav_menu_item_additional_fields', '', $item_output, $item, $depth, $args );
// Inject $new_fields before: <div class="menu-item-actions description-wide submitbox">
if ($new_fields) {
$item_output = preg_replace('/(?=<div[^>]+class="[^"]*submitbox)/', $new_fields, $item_output);
}
$output .= $item_output;
}
}

Hmm. I tried this snippet but it caused a PHP error. Trying the fork next....

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

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.