Custom fields to menu items in WordPress

Custom fields to menu items in WordPress

The wp_nav_menu_item_custom_fields action is called before a nav menu item's move buttons in the menu editor.

Home / Blog / Wordpress / Custom fields to menu items in WordPress

The wp_nav_menu_item_custom_fields action is called before a nav menu item’s move buttons in the menu editor.

Custom fields to menu items in WordPress

Five parameters can be assigned to this hook:

  • $item_id
  • $item
  • $depth
  • $args
  • $id

The custom field will appear beneath every menu item if you use the hook as shown below.

<?php

function pe_menu_item_custom_field() {
	?>

    <div class="pe-mi-custom-field-desc">
        <p class="description">
            <?php esc_html_e( 'Howdy! Custom fields to menu items in WordPress!', 'projectsengine' ); ?>
        </p>
    </div>

    <?php
}
add_action( 'wp_nav_menu_item_custom_fields', 'pe_menu_item_custom_field' );

Before adding the custom field you should check out the screen options tab at the top. The functionality you want to add might already be available, like the ‘open the link in a new tab‘.

We recommend adding this functionality to a plugin or a child theme.

Custom fields to menu items in WordPress

Let’s add our custom field. It can be anything you want, but we will add a simple checkbox and a text field.

<?php

add_action('wp_nav_menu_item_custom_fields', function($item_id, $item) {
	$button = get_post_meta($item_id, '_custom_menu_item', true);
	$text = get_post_meta($item_id, '_custom_menu_item_desc', true);

	?>

    <div class="pe-mi-custom-field-button">
        <p class="description">
            <label for="pe-mi-custom-field-label-button-<?php echo $item_id; ?>" >
                <input type="checkbox"
                       id="pe-mi-custom-field-button-<?php echo $item_id; ?>"
                       name="pe-mi-custom-field-button[<?php echo $item_id; ?>]"
                        <?php checked($button); ?>
                /><?php _e('Disable this menu item', 'luckies'); ?>
            </label>
        </p>
        <p class="description">
            <label for="pe-mi-custom-field-label-text-<?php echo $item_id; ?>" >
                <input type="text"
                       id="pe-mi-custom-field-text-<?php echo $item_id; ?>"
                       name="pe-mi-custom-field-text[<?php echo $item_id; ?>]"
				    value="<?php echo $text; ?>"
                />
            </label>
        </p>
    </div>

	<?php
}, 10, 2);

Our custom fields are not saved yet. We will have to add additional functionality, and that is our next step.

WordPress Version: Remember that at least WordPress version 5.4 is necessary for this hook to work.

To be able to save our custom fields, we will need the wp_update_nav_menu_item hook.

Four parameters can be assigned to this hook:

  • $menu_id
  • $menu_item_db_id
  • $menu_item_data
  • $fire_after_hooks
<?php

add_action('wp_update_nav_menu_item', function($menu_id, $menu_item_db_id) {
	$button = isset($_POST['pe-mi-custom-field-button'][$menu_item_db_id]) && $_POST['pe-mi-custom-field-button'][$menu_item_db_id] == 'on';
	update_post_meta($menu_item_db_id, '_custom_menu_item', $button);

	$text = isset($_POST['pe-mi-custom-field-text'][$menu_item_db_id]) && $_POST['pe-mi-custom-field-text'][$menu_item_db_id] !== '' ? $_POST['pe-mi-custom-field-text'][$menu_item_db_id] : '';
	update_post_meta($menu_item_db_id, '_custom_menu_item_desc', $text);
}, 10, 2);

There are several hooks you can use to tweak the menu items on frontend:

<?php

add_filter('nav_menu_css_class', function($classes, $menu_item) {
	$button = get_post_meta($menu_item->ID, '_custom_menu_item', true);

	if ($button) {
		$classes[] = 'pe-mi-class-disabled';
	}
	return $classes;
}, 10, 2);