wp_update_nav_menu_item( int $menu_id, int $menu_item_db_id, array $menu_item_data = array() )

Save the properties of a menu item or create a new one.


Description Description

The menu-item-title, menu-item-description, and menu-item-attr-title are expected to be pre-slashed since they are passed directly into wp_insert_post().


Parameters Parameters

$menu_id

(int) (Required) The ID of the menu. Required. If "0", makes the menu item a draft orphan.

$menu_item_db_id

(int) (Required) The ID of the menu item. If "0", creates a new menu item.

$menu_item_data

(array) (Optional) The menu item's data.

Default value: array()


Top ↑

Return Return

(int|WP_Error) The menu item's database ID or WP_Error object on failure.


Top ↑

Source Source

File: wp-includes/nav-menu.php

function wp_update_nav_menu_item( $menu_id = 0, $menu_item_db_id = 0, $menu_item_data = array() ) {
	$menu_id         = (int) $menu_id;
	$menu_item_db_id = (int) $menu_item_db_id;

	// make sure that we don't convert non-nav_menu_item objects into nav_menu_item objects
	if ( ! empty( $menu_item_db_id ) && ! is_nav_menu_item( $menu_item_db_id ) ) {
		return new WP_Error( 'update_nav_menu_item_failed', __( 'The given object ID is not that of a menu item.' ) );
	}

	$menu = wp_get_nav_menu_object( $menu_id );

	if ( ! $menu && 0 !== $menu_id ) {
		return new WP_Error( 'invalid_menu_id', __( 'Invalid menu ID.' ) );
	}

	if ( is_wp_error( $menu ) ) {
		return $menu;
	}

	$defaults = array(
		'menu-item-db-id'       => $menu_item_db_id,
		'menu-item-object-id'   => 0,
		'menu-item-object'      => '',
		'menu-item-parent-id'   => 0,
		'menu-item-position'    => 0,
		'menu-item-type'        => 'custom',
		'menu-item-title'       => '',
		'menu-item-url'         => '',
		'menu-item-description' => '',
		'menu-item-attr-title'  => '',
		'menu-item-target'      => '',
		'menu-item-classes'     => '',
		'menu-item-xfn'         => '',
		'menu-item-status'      => '',
	);

	$args = wp_parse_args( $menu_item_data, $defaults );

	if ( 0 == $menu_id ) {
		$args['menu-item-position'] = 1;
	} elseif ( 0 == (int) $args['menu-item-position'] ) {
		$menu_items                 = 0 == $menu_id ? array() : (array) wp_get_nav_menu_items( $menu_id, array( 'post_status' => 'publish,draft' ) );
		$last_item                  = array_pop( $menu_items );
		$args['menu-item-position'] = ( $last_item && isset( $last_item->menu_order ) ) ? 1 + $last_item->menu_order : count( $menu_items );
	}

	$original_parent = 0 < $menu_item_db_id ? get_post_field( 'post_parent', $menu_item_db_id ) : 0;

	if ( 'custom' === $args['menu-item-type'] ) {
		// If custom menu item, trim the URL.
		$args['menu-item-url'] = trim( $args['menu-item-url'] );
	} else {
		/*
		 * If non-custom menu item, then:
		 * - use the original object's URL.
		 * - blank default title to sync with the original object's title.
		 */

		$args['menu-item-url'] = '';

		$original_title = '';
		if ( 'taxonomy' == $args['menu-item-type'] ) {
			$original_parent = get_term_field( 'parent', $args['menu-item-object-id'], $args['menu-item-object'], 'raw' );
			$original_title  = get_term_field( 'name', $args['menu-item-object-id'], $args['menu-item-object'], 'raw' );
		} elseif ( 'post_type' == $args['menu-item-type'] ) {

			$original_object = get_post( $args['menu-item-object-id'] );
			$original_parent = (int) $original_object->post_parent;
			$original_title  = $original_object->post_title;
		} elseif ( 'post_type_archive' == $args['menu-item-type'] ) {
			$original_object = get_post_type_object( $args['menu-item-object'] );
			if ( $original_object ) {
				$original_title = $original_object->labels->archives;
			}
		}

		if ( $args['menu-item-title'] == $original_title ) {
			$args['menu-item-title'] = '';
		}

		// hack to get wp to create a post object when too many properties are empty
		if ( '' == $args['menu-item-title'] && '' == $args['menu-item-description'] ) {
			$args['menu-item-description'] = ' ';
		}
	}

	// Populate the menu item object
	$post = array(
		'menu_order'   => $args['menu-item-position'],
		'ping_status'  => 0,
		'post_content' => $args['menu-item-description'],
		'post_excerpt' => $args['menu-item-attr-title'],
		'post_parent'  => $original_parent,
		'post_title'   => $args['menu-item-title'],
		'post_type'    => 'nav_menu_item',
	);

	$update = 0 != $menu_item_db_id;

	// New menu item. Default is draft status
	if ( ! $update ) {
		$post['ID']          = 0;
		$post['post_status'] = 'publish' == $args['menu-item-status'] ? 'publish' : 'draft';
		$menu_item_db_id     = wp_insert_post( $post );
		if ( ! $menu_item_db_id || is_wp_error( $menu_item_db_id ) ) {
			return $menu_item_db_id;
		}

		/**
		 * Fires immediately after a new navigation menu item has been added.
		 *
		 * @since 4.4.0
		 *
		 * @see wp_update_nav_menu_item()
		 *
		 * @param int   $menu_id         ID of the updated menu.
		 * @param int   $menu_item_db_id ID of the new menu item.
		 * @param array $args            An array of arguments used to update/add the menu item.
		 */
		do_action( 'wp_add_nav_menu_item', $menu_id, $menu_item_db_id, $args );
	}

	// Associate the menu item with the menu term
	// Only set the menu term if it isn't set to avoid unnecessary wp_get_object_terms()
	if ( $menu_id && ( ! $update || ! is_object_in_term( $menu_item_db_id, 'nav_menu', (int) $menu->term_id ) ) ) {
		wp_set_object_terms( $menu_item_db_id, array( $menu->term_id ), 'nav_menu' );
	}

	if ( 'custom' == $args['menu-item-type'] ) {
		$args['menu-item-object-id'] = $menu_item_db_id;
		$args['menu-item-object']    = 'custom';
	}

	$menu_item_db_id = (int) $menu_item_db_id;

	update_post_meta( $menu_item_db_id, '_menu_item_type', sanitize_key( $args['menu-item-type'] ) );
	update_post_meta( $menu_item_db_id, '_menu_item_menu_item_parent', strval( (int) $args['menu-item-parent-id'] ) );
	update_post_meta( $menu_item_db_id, '_menu_item_object_id', strval( (int) $args['menu-item-object-id'] ) );
	update_post_meta( $menu_item_db_id, '_menu_item_object', sanitize_key( $args['menu-item-object'] ) );
	update_post_meta( $menu_item_db_id, '_menu_item_target', sanitize_key( $args['menu-item-target'] ) );

	$args['menu-item-classes'] = array_map( 'sanitize_html_class', explode( ' ', $args['menu-item-classes'] ) );
	$args['menu-item-xfn']     = implode( ' ', array_map( 'sanitize_html_class', explode( ' ', $args['menu-item-xfn'] ) ) );
	update_post_meta( $menu_item_db_id, '_menu_item_classes', $args['menu-item-classes'] );
	update_post_meta( $menu_item_db_id, '_menu_item_xfn', $args['menu-item-xfn'] );
	update_post_meta( $menu_item_db_id, '_menu_item_url', esc_url_raw( $args['menu-item-url'] ) );

	if ( 0 == $menu_id ) {
		update_post_meta( $menu_item_db_id, '_menu_item_orphaned', (string) time() );
	} elseif ( get_post_meta( $menu_item_db_id, '_menu_item_orphaned' ) ) {
		delete_post_meta( $menu_item_db_id, '_menu_item_orphaned' );
	}

	// Update existing menu item. Default is publish status
	if ( $update ) {
		$post['ID']          = $menu_item_db_id;
		$post['post_status'] = 'draft' == $args['menu-item-status'] ? 'draft' : 'publish';
		wp_update_post( $post );
	}

	/**
	 * Fires after a navigation menu item has been updated.
	 *
	 * @since 3.0.0
	 *
	 * @see wp_update_nav_menu_item()
	 *
	 * @param int   $menu_id         ID of the updated menu.
	 * @param int   $menu_item_db_id ID of the updated menu item.
	 * @param array $args            An array of arguments used to update a menu item.
	 */
	do_action( 'wp_update_nav_menu_item', $menu_id, $menu_item_db_id, $args );

	return $menu_item_db_id;
}

Top ↑

Changelog Changelog

Changelog
Version Description
3.0.0 Introduced.


Top ↑

User Contributed Notes User Contributed Notes

  1. Skip to note 1 content
    Contributed by Josh Larson

    The $menu_item_data argument accepts an array of data. Depending upon the type of nav menu item you are attempting to add, it requires different parameters:

    Note that in several cases, menu-item-object must be included, and it must be set to the post type of the nav item you are referencing.

    Page

    $page = get_post(123); // etc
    wp_update_nav_menu_item($menu_id, 0, array(
        'menu-item-title' => 'My Link',
        'menu-item-object-id' => $page->ID,
        'menu-item-object' => 'page',
        'menu-item-status' => 'publish',
        'menu-item-type' => 'post_type',
    ));
    

    Post

    $post = get_post(123); // etc
    wp_update_nav_menu_item($menu_id, 0, array(
        'menu-item-title' => 'My Link',
        'menu-item-object-id' => $post->ID,
        'menu-item-object' => 'post',
        'menu-item-status' => 'publish',
        'menu-item-type' => 'post_type',
    ));
    

    Custom

    When adding a custom link to your nav menu, you can omit the menu-item-type because it defaults to custom.

    wp_update_nav_menu_item($menu_id, 0, array(
        'menu-item-title' => 'My Link',
        'menu-item-url' => 'http://example.com/',
        'menu-item-status' => 'publish',
        'menu-item-type' => 'custom', // optional
    ));
    

You must log in before being able to contribute a note or feedback.