WordPress.org

Make WordPress Core

Ticket #36590: 36590.2.diff

File 36590.2.diff, 5.4 KB (added by ericlewis, 5 years ago)
  • src/wp-admin/includes/nav-menu.php

     
    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 * @since 4.5.1
     1066 */
     1067function wp_expand_nav_menu_post_data() {
     1068        if ( ! isset( $_POST['nav-menu-data'] ) ) {
     1069                return;
     1070        }
     1071        $data = json_decode( stripslashes( $_POST['nav-menu-data'] ) );
     1072        if ( ! is_null( $data ) && $data ) {
     1073                foreach ( $data as $post_input_data ) {
     1074                        // For input names that are arrays (e.g. `menu-item-db-id[3][4][5]`),
     1075                        // derive the array path keys via regex and set the value in $_POST.
     1076                        preg_match( '#([^\[]*)(\[(.+)\])?#', $post_input_data->name, $matches );
     1077                        $array_bits = array( $matches[1] );
     1078                        if ( isset( $matches[3]) ) {
     1079                                $array_bits = array_merge( $array_bits, explode( '][', $matches[3] ) );
     1080                        }
     1081                        $new_post_data = array();
     1082                        // Build the new array value from leaf to trunk.
     1083                        for ( $i = count($array_bits) - 1; $i >= 0; $i-- ) {
     1084                                if ( $i == count($array_bits) - 1 ) {
     1085                                        $new_post_data[ $array_bits[$i] ] = wp_slash( $post_input_data->value );
     1086                                } else {
     1087                                        $new_post_data = array( $array_bits[$i] => $new_post_data );
     1088                                }
     1089                        }
     1090                        $_POST = array_replace_recursive( $_POST, $new_post_data );
     1091                }
     1092        }
     1093}
  • src/wp-admin/nav-menus.php

     
    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 }
     56wp_expand_nav_menu_post_data();
     57
    7658switch ( $action ) {
    7759        case 'add-menu-item':
    7860                check_admin_referer( 'add-menu_item', 'menu-settings-column-nonce' );
  • tests/phpunit/tests/menu/wpExpandNavMenuPostData.php

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