// Remove non-existent/deleted menus.
$nav_menu_option['auto_add'] = array_intersect(
$nav_menu_option['auto_add'],
wp_get_nav_menus( array( 'fields' => 'ids' ) )
update_option( 'nav_menu_options', $nav_menu_option, false );
wp_defer_term_counting( false );
/** This action is documented in wp-includes/nav-menu.php */
do_action( 'wp_update_nav_menu', $nav_menu_selected_id );
/* translators: %s: Nav menu title. */
$message = sprintf( __( '%s has been updated.' ), '<strong>' . $nav_menu_selected_title . '</strong>' );
'additional_classes' => array( 'updated' ),
$messages[] = wp_get_admin_notice( $message, $notice_args );
unset( $menu_items, $unsorted_menu_items );
* If a JSON blob of navigation menu data is in POST data, expand it and inject
* it into `$_POST` to avoid PHP `max_input_vars` limitations. See #14134.
function _wp_expand_nav_menu_post_data() {
if ( ! isset( $_POST['nav-menu-data'] ) ) {
$data = json_decode( stripslashes( $_POST['nav-menu-data'] ) );
if ( ! is_null( $data ) && $data ) {
foreach ( $data as $post_input_data ) {
* For input names that are arrays (e.g. `menu-item-db-id[3][4][5]`),
* derive the array path keys via regex and set the value in $_POST.
preg_match( '#([^\[]*)(\[(.+)\])?#', $post_input_data->name, $matches );
$array_bits = array( $matches[1] );
if ( isset( $matches[3] ) ) {
$array_bits = array_merge( $array_bits, explode( '][', $matches[3] ) );
$new_post_data = array();
// Build the new array value from leaf to trunk.
for ( $i = count( $array_bits ) - 1; $i >= 0; $i-- ) {
if ( count( $array_bits ) - 1 === $i ) {
$new_post_data[ $array_bits[ $i ] ] = wp_slash( $post_input_data->value );
$new_post_data = array( $array_bits[ $i ] => $new_post_data );
$_POST = array_replace_recursive( $_POST, $new_post_data );