Index: src/wp-admin/includes/nav-menu.php
===================================================================
--- src/wp-admin/includes/nav-menu.php	(revision 37269)
+++ src/wp-admin/includes/nav-menu.php	(working copy)
@@ -1057,3 +1057,37 @@
 
 	return $messages;
 }
+
+/**
+ * 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.
+ *
+ * @since 4.5.1
+ */
+function wp_expand_nav_menu_post_data() {
+	if ( ! isset( $_POST['nav-menu-data'] ) ) {
+		return;
+	}
+	$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 ( $i == count($array_bits) - 1 ) {
+					$new_post_data[ $array_bits[$i] ] = wp_slash( $post_input_data->value );
+				} else {
+					$new_post_data = array( $array_bits[$i] => $new_post_data );
+				}
+			}
+			$_POST = array_replace_recursive( $_POST, $new_post_data );
+		}
+	}
+}
Index: src/wp-admin/nav-menus.php
===================================================================
--- src/wp-admin/nav-menus.php	(revision 37269)
+++ src/wp-admin/nav-menus.php	(working copy)
@@ -53,26 +53,8 @@
  * If a JSON blob of navigation menu data is found, expand it and inject it
  * into `$_POST` to avoid PHP `max_input_vars` limitations. See #14134.
  */
-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]`), derive the array path keys via regex.
-			if ( preg_match( '#(.*)\[(\w+)\]#', $post_input_data->name, $matches ) ) {
-				if ( empty( $_POST[ $matches[1] ] ) ) {
-					$_POST[ $matches[1] ] = array();
-				}
-				// Cast input elements with a numeric array index to integers.
-				if ( is_numeric( $matches[2] ) ) {
-					$matches[2] = (int) $matches[2];
-				}
-				$_POST[ $matches[1] ][ $matches[2] ] = wp_slash( $post_input_data->value );
-			} else {
-				$_POST[ $post_input_data->name ] = wp_slash( $post_input_data->value );
-			}
-		}
-	}
-}
+wp_expand_nav_menu_post_data();
+
 switch ( $action ) {
 	case 'add-menu-item':
 		check_admin_referer( 'add-menu_item', 'menu-settings-column-nonce' );
Index: tests/phpunit/tests/menu/wpExpandNavMenuPostData.php
===================================================================
--- tests/phpunit/tests/menu/wpExpandNavMenuPostData.php	(nonexistent)
+++ tests/phpunit/tests/menu/wpExpandNavMenuPostData.php	(working copy)
@@ -0,0 +1,92 @@
+<?php
+
+/**
+ * @group menu
+ */
+class Tests_Menu_WpExpandNavMenuPostData extends WP_UnitTestCase {
+
+	public function test_unnested_data_should_expand() {
+		include_once( ABSPATH . 'wp-admin/includes/nav-menu.php' );
+		if ( empty( $_POST ) ) {
+			$_POST = array();
+		}
+		$data = array();
+		$data[0] = new StdClass;
+		$data[0]->name = 'yesorno';
+		$data[0]->value = 'yes';
+		$_POST['nav-menu-data'] = addslashes( json_encode( $data ) );
+		wp_expand_nav_menu_post_data();
+		$expected = array(
+			'nav-menu-data' => $_POST['nav-menu-data'],
+			'yesorno' => 'yes'
+		);
+		$this->assertEquals( $expected, $_POST );
+	}
+
+	public function test_multidimensional_nested_array_should_expand() {
+		include_once( ABSPATH . 'wp-admin/includes/nav-menu.php' );
+		if ( empty( $_POST ) ) {
+			$_POST = array();
+		}
+		$data = array();
+		$data[0] = new StdClass;
+		$data[0]->name = 'would[1][do][the][trick]';
+		$data[0]->value = 'yes';
+		$_POST['nav-menu-data'] = addslashes( json_encode( $data ) );
+		wp_expand_nav_menu_post_data();
+		$expected = array(
+			'nav-menu-data' => $_POST['nav-menu-data'],
+			'would' => array(
+				1 => array(
+					'do' => array(
+						'the' => array(
+							'trick' => 'yes'
+						)
+					)
+				)
+			)
+		);
+		$this->assertEquals( $expected, $_POST );
+	}
+
+	public function test_multidimensional_nested_array_should_expand_and_merge() {
+		include_once( ABSPATH . 'wp-admin/includes/nav-menu.php' );
+		if ( empty( $_POST ) ) {
+			$_POST = array();
+		}
+		$data = array();
+		$data[0] = new StdClass;
+		$data[0]->name = 'would[1][do][the][trick]';
+		$data[0]->value = 'yes';
+		$data[1] = new StdClass;
+		$data[1]->name = 'would[2][do][the][trick]';
+		$data[1]->value = 'yes';
+		$data[2] = new StdClass;
+		$data[2]->name = 'would[2][do][the][job]';
+		$data[2]->value = 'yes';
+		$_POST['nav-menu-data'] = addslashes( json_encode( $data ) );
+		wp_expand_nav_menu_post_data();
+		$expected = array(
+			'nav-menu-data' => $_POST['nav-menu-data'],
+			'would' => array(
+				1 => array(
+					'do' => array(
+						'the' => array(
+							'trick' => 'yes'
+						)
+					)
+				),
+				2 => array(
+					'do' => array(
+						'the' => array(
+							'trick' => 'yes',
+							'job' => 'yes'
+						)
+					)
+				)
+			)
+		);
+		$this->assertEquals( $expected, $_POST );
+	}
+
+}
