Skip to content

Instantly share code, notes, and snippets.

@rahulsprajapati
Created August 5, 2016 10:23
Show Gist options
  • Save rahulsprajapati/72bab405f29ed7b7b1ad19d4328d3073 to your computer and use it in GitHub Desktop.
Save rahulsprajapati/72bab405f29ed7b7b1ad19d4328d3073 to your computer and use it in GitHub Desktop.
<?php
/**
* Created by PhpStorm.
* User: rahul
* Date: 5/8/16
* Time: 3:16 PM
*
* @ref https://gist.github.com/kucrut/3804376
*/
require_once ABSPATH . 'wp-admin/includes/nav-menu.php';
class Nav_Menu_Item_Meta_Fields {
/**
* @var array $options Fields templates for meta box of menu items
*/
static $options = array(
'item_tpl' => '<p class="nav-country-meta-field-{name} description description-wide">
<label for="edit-menu-item-{name}-{id}">{label}<br>
{tpl_type}
</label>
</p>',
'select_tpl' => '<select name="menu-item-{name}[{id}]" class="widefat">
<option value="">--Select--</option>
{options}
</select>',
'input_tpl' => '<input
type="{field_type}"
id="edit-menu-item-{name}-{id}"
class="widefat edit-menu-item-{name}"
name="menu-item-{name}[{id}]"
value="{value}">',
);
/**
* Setup all meta fields from $options['fields'] for nav menu items.
*/
static function setup() {
if ( ! is_admin() ) {
return;
}
$meta_fields = apply_filters( 'nav_menu_item_meta_fields', array() );
if ( empty($meta_fields) )
return;
self::$options['fields'] = $meta_fields;
add_filter( 'wp_edit_nav_menu_walker', function () {
return 'Custom_Fields_Walker_Nav_Menu_Edit';
} );
add_action( 'save_post', array( __CLASS__, '_save_post' ), 10, 2 );
}
/**
* @param string $name Meta field name
*
* @return string Nav Menu Item metabox-key ( post-meta key )
*/
static function get_menu_item_postmeta_key($name) {
return '_menu_item_' . $name;
}
/**
* @param object $item Menu item data object.
*
* @return string
*/
static function get_field( $item ) {
$meta_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;
$item_tpl_key = "item_tpl";
$item_field_tpl_key = "input_tpl";
if ( $field[ "field_type" ] == "select" ) {
$item_field_tpl_key = "select_tpl";
}
$field_tpl = str_replace(
'{tpl_type}',
self::$options[$item_field_tpl_key],
self::$options[$item_tpl_key]
);
if ( isset( $field[ 'options' ] ) && ! empty( $field[ 'options' ] ) && is_array( $field[ 'options' ] ) ) {
$options = "";
foreach ( $field['options'] as $val => $name ) {
$selected = "";
if( $field["value"] == $val ) {
$selected = "selected=selected";
}
$options .= "<option value=$val $selected>$name</option>";
}
$field['options'] = $options;
}
$meta_fields .= str_replace(
array_map(function($key){ return '{' . $key . '}'; }, array_keys($field)),
array_values(array_map('esc_attr', $field)),
$field_tpl
);
}
return html_entity_decode( $meta_fields );
}
/**
* Save the newly submitted fields
*
* @hook {action} save_post
*
* @param int $post_id Menu item id
* @param object $post Menu item data object.
*
* @return mixed
*/
static function _save_post( $post_id, $post ) {
if ( $post->post_type !== 'nav_menu_item' ) {
return $post_id;
}
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);
}
}
}
}
add_action( 'init', array( 'Nav_Menu_Item_Meta_Fields', 'setup' ) );
class Custom_Fields_Walker_Nav_Menu_Edit extends Walker_Nav_Menu_Edit {
/**
* Start the element output.
*
* @ref wp-admin/includes/class-walker-nav-menu-edit.php
*
* @see Walker_Nav_Menu::start_el()
*
*
* @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 $args Not used.
* @param int $id Not used.
*/
function start_el( &$output, $item, $depth, $args, $id = 0 ) {
$item_output = '';
parent::start_el( $item_output, $item, $depth, $args, $id );
if ( $meta_fields = Nav_Menu_Item_Meta_Fields::get_field( $item ) ) {
// Inject $new_fields before: <div class="menu-item-actions description-wide submitbox">
$item_output = preg_replace( '/(?=<div[^>]+class="[^"]*submitbox)/', $meta_fields, $item_output );
}
$output .= $item_output;
}
}
@rahulsprajapati
Copy link
Author

Add fields using this filter

add_filter( 'nav_menu_item_meta_fields', 'custom_nav_menu_item_meta_fields' );

function custom_nav_menu_item_meta_fields( $fields ) {

    $fields[] = array(
        'name' => 'country',
        'label' => __('Country', 'nav_meta_fields'),
        'container_class' => 'country-type',
        'options' => array(
            'in'  => 'India',
            'usa' => 'USA',
        ),
        'field_type' => 'select',
    );

    $fields[] = array(
        'name' => 'sub-title',
        'label' => __('Sub Title', 'nav_meta_fields'),
        'container_class' => 'sub-title',
        'field_type' => 'text',
    );

    return $fields;
}

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