WordPress.org

Make WordPress Core

Ticket #36590: 36590.5.diff

File 36590.5.diff, 7.2 KB (added by swissspidy, 4 years ago)
  • src/wp-admin/includes/nav-menu.php

    diff --git src/wp-admin/includes/nav-menu.php src/wp-admin/includes/nav-menu.php
    index 18dcc97..47f6e61 100644
    function wp_nav_menu_update_menu_items ( $nav_menu_selected_id, $nav_menu_select 
    10571057
    10581058        return $messages;
    10591059}
     1060
     1061/**
     1062 * If a JSON blob of navigation menu data is in POST data, expand it and inject
     1063 * it into `$_POST` to avoid PHP `max_input_vars` limitations. See #14134.
     1064 *
     1065 * @ignore
     1066 * @since 4.5.1
     1067 * @access private
     1068 */
     1069function _wp_expand_nav_menu_post_data() {
     1070        if ( ! isset( $_POST['nav-menu-data'] ) ) {
     1071                return;
     1072        }
     1073
     1074        $data = json_decode( stripslashes( $_POST['nav-menu-data'] ) );
     1075
     1076        if ( ! is_null( $data ) && $data ) {
     1077                foreach ( $data as $post_input_data ) {
     1078                        // For input names that are arrays (e.g. `menu-item-db-id[3][4][5]`),
     1079                        // derive the array path keys via regex and set the value in $_POST.
     1080                        preg_match( '#([^\[]*)(\[(.+)\])?#', $post_input_data->name, $matches );
     1081
     1082                        $array_bits = array( $matches[1] );
     1083
     1084                        if ( isset( $matches[3] ) ) {
     1085                                $array_bits = array_merge( $array_bits, explode( '][', $matches[3] ) );
     1086                        }
     1087
     1088                        $new_post_data = array();
     1089
     1090                        // Build the new array value from leaf to trunk.
     1091                        for ( $i = count( $array_bits ) - 1; $i >= 0; $i -- ) {
     1092                                if ( $i == count( $array_bits ) - 1 ) {
     1093                                        $new_post_data[ $array_bits[ $i ] ] = wp_slash( $post_input_data->value );
     1094                                } else {
     1095                                        $new_post_data = array( $array_bits[ $i ] => $new_post_data );
     1096                                }
     1097                        }
     1098
     1099                        $_POST = _array_replace_recursive( $_POST, $new_post_data );
     1100                }
     1101        }
     1102}
     1103
     1104/**
     1105 * PHP-agnostic version of {@link array_replace_recursive()}.
     1106 *
     1107 * The array_replace_recursive() function is a PHP 5.3 function. WordPress
     1108 * currently supports down to PHP 5.2, so this method is a workaround
     1109 * for PHP 5.2.
     1110 *
     1111 * Note: array_replace_recursive() supports infinite arguments, but for our use-
     1112 * case, we only need to support two arguments.
     1113 *
     1114 * Subject to removal once WordPress makes PHP 5.3.0 the minimum requirement.
     1115 *
     1116 * @ignore
     1117 * @since 4.5.1
     1118 * @access private
     1119 *
     1120 * @see http://php.net/manual/en/function.array-replace-recursive.php#109390
     1121 *
     1122 * @param  array $base         Array with keys needing to be replaced.
     1123 * @param  array $replacements Array with the replaced keys.
     1124 *
     1125 * @return array
     1126 */
     1127function _array_replace_recursive( $base = array(), $replacements = array() ) {
     1128        if ( function_exists( 'array_replace_recursive' ) ) {
     1129                return array_replace_recursive( $base, $replacements );
     1130        }
     1131
     1132        // PHP 5.2-compatible version
     1133        // http://php.net/manual/en/function.array-replace-recursive.php#109390.
     1134        foreach ( array_slice( func_get_args(), 1 ) as $replacements ) {
     1135                $bref_stack = array( &$base );
     1136                $head_stack = array( $replacements );
     1137
     1138                do {
     1139                        end( $bref_stack );
     1140
     1141                        $bref = &$bref_stack[ key( $bref_stack ) ];
     1142                        $head = array_pop( $head_stack );
     1143
     1144                        unset( $bref_stack[ key( $bref_stack ) ] );
     1145
     1146                        foreach ( array_keys( $head ) as $key ) {
     1147                                if ( isset( $key, $bref ) && is_array( $bref[ $key ] ) && is_array( $head[ $key ] ) ) {
     1148                                        $bref_stack[] = &$bref[ $key ];
     1149                                        $head_stack[] = $head[ $key ];
     1150                                } else {
     1151                                        $bref[ $key ] = $head[ $key ];
     1152                                }
     1153                        }
     1154                } while ( count( $head_stack ) );
     1155        }
     1156
     1157        return $base;
     1158}
  • src/wp-admin/nav-menus.php

    diff --git src/wp-admin/nav-menus.php src/wp-admin/nav-menus.php
    index ab15bed..1b5e09b 100644
    $action = isset( $_REQUEST['action'] ) ? $_REQUEST['action'] : 'edit'; 
    5353 * If a JSON blob of navigation menu data is found, expand it and inject it
    5454 * into `$_POST` to avoid PHP `max_input_vars` limitations. See #14134.
    5555 */
    56 if ( isset( $_POST['nav-menu-data'] ) ) {
    57         $data = json_decode( stripslashes( $_POST['nav-menu-data'] ) );
    58         if ( ! is_null( $data ) && $data ) {
    59                 foreach ( $data as $post_input_data ) {
    60                         // For input names that are arrays (e.g. `menu-item-db-id[3]`), derive the array path keys via regex.
    61                         if ( preg_match( '#(.*)\[(\w+)\]#', $post_input_data->name, $matches ) ) {
    62                                 if ( empty( $_POST[ $matches[1] ] ) ) {
    63                                         $_POST[ $matches[1] ] = array();
    64                                 }
    65                                 // Cast input elements with a numeric array index to integers.
    66                                 if ( is_numeric( $matches[2] ) ) {
    67                                         $matches[2] = (int) $matches[2];
    68                                 }
    69                                 $_POST[ $matches[1] ][ $matches[2] ] = wp_slash( $post_input_data->value );
    70                         } else {
    71                                 $_POST[ $post_input_data->name ] = wp_slash( $post_input_data->value );
    72                         }
    73                 }
    74         }
    75 }
     56_wp_expand_nav_menu_post_data();
     57
    7658switch ( $action ) {
    7759        case 'add-menu-item':
    7860                check_admin_referer( 'add-menu_item', 'menu-settings-column-nonce' );
  • new file tests/phpunit/tests/menu/wpExpandNavMenuPostData.php

    diff --git tests/phpunit/tests/menu/wpExpandNavMenuPostData.php tests/phpunit/tests/menu/wpExpandNavMenuPostData.php
    new file mode 100644
    index 0000000..361c4f9
    - +  
     1<?php
     2
     3/**
     4 * @group menu
     5 * @ticket 36590
     6 */
     7class Tests_Menu_WpExpandNavMenuPostData extends WP_UnitTestCase {
     8        public function test_unnested_data_should_expand() {
     9                include_once( ABSPATH . 'wp-admin/includes/nav-menu.php' );
     10
     11                if ( empty( $_POST ) ) {
     12                        $_POST = array();
     13                }
     14
     15                $data = array();
     16                $data[0] = new StdClass;
     17                $data[0]->name = 'yesorno';
     18                $data[0]->value = 'yes';
     19                $_POST['nav-menu-data'] = addslashes( json_encode( $data ) );
     20
     21                _wp_expand_nav_menu_post_data();
     22
     23                $expected = array(
     24                        'nav-menu-data' => $_POST['nav-menu-data'],
     25                        'yesorno' => 'yes'
     26                );
     27
     28                $this->assertEquals( $expected, $_POST );
     29        }
     30
     31        public function test_multidimensional_nested_array_should_expand() {
     32                include_once( ABSPATH . 'wp-admin/includes/nav-menu.php' );
     33
     34                if ( empty( $_POST ) ) {
     35                        $_POST = array();
     36                }
     37
     38                $data = array();
     39                $data[0] = new StdClass;
     40                $data[0]->name = 'would[1][do][the][trick]';
     41                $data[0]->value = 'yes';
     42                $_POST['nav-menu-data'] = addslashes( json_encode( $data ) );
     43
     44                _wp_expand_nav_menu_post_data();
     45
     46                $expected = array(
     47                        'nav-menu-data' => $_POST['nav-menu-data'],
     48                        'would' => array(
     49                                1 => array(
     50                                        'do' => array(
     51                                                'the' => array(
     52                                                        'trick' => 'yes',
     53                                                ),
     54                                        ),
     55                                ),
     56                        ),
     57                );
     58                $this->assertEquals( $expected, $_POST );
     59        }
     60
     61        public function test_multidimensional_nested_array_should_expand_and_merge() {
     62                include_once( ABSPATH . 'wp-admin/includes/nav-menu.php' );
     63
     64                if ( empty( $_POST ) ) {
     65                        $_POST = array();
     66                }
     67
     68                $data = array();
     69                $data[0] = new StdClass;
     70                $data[0]->name = 'would[1][do][the][trick]';
     71                $data[0]->value = 'yes';
     72                $data[1] = new StdClass;
     73                $data[1]->name = 'would[2][do][the][trick]';
     74                $data[1]->value = 'yes';
     75                $data[2] = new StdClass;
     76                $data[2]->name = 'would[2][do][the][job]';
     77                $data[2]->value = 'yes';
     78                $_POST['nav-menu-data'] = addslashes( json_encode( $data ) );
     79
     80                _wp_expand_nav_menu_post_data();
     81
     82                $expected = array(
     83                        'nav-menu-data' => $_POST['nav-menu-data'],
     84                        'would' => array(
     85                                1 => array(
     86                                        'do' => array(
     87                                                'the' => array(
     88                                                        'trick' => 'yes',
     89                                                ),
     90                                        ),
     91                                ),
     92                                2 => array(
     93                                        'do' => array(
     94                                                'the' => array(
     95                                                        'trick' => 'yes',
     96                                                        'job'   => 'yes',
     97                                                ),
     98                                        ),
     99                                ),
     100                        ),
     101                );
     102
     103                $this->assertEquals( $expected, $_POST );
     104        }
     105}