WordPress.org

Make WordPress Core

Changeset 37748


Ignore:
Timestamp:
06/19/16 12:24:23 (17 months ago)
Author:
swissspidy
Message:

Menus: Support nested array variables in POST data when saving menus.

[36510] allowed larger menus to be created in the Edit Menu screen by JSON-encoding the entire form into a single input field. However, it did not correctly handle nested arrays.

This introduces a new _wp_expand_nav_menu_post_data() helper function to handle this POST data which uses array_replace_recursive() internally. Since the latter is only available on PHP 5.3+, we add a compatibility function to ensure PHP 5.2 support.

Props ericlewis, neverything, swissspidy.
Fixes #36590 for trunk. See #14134.

Location:
trunk
Files:
2 added
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/includes/nav-menu.php

    r37529 r37748  
    10601060    return $messages; 
    10611061} 
     1062 
     1063/** 
     1064 * If a JSON blob of navigation menu data is in POST data, expand it and inject 
     1065 * it into `$_POST` to avoid PHP `max_input_vars` limitations. See #14134. 
     1066 * 
     1067 * @ignore 
     1068 * @since 4.5.3 
     1069 * @access private 
     1070 */ 
     1071function _wp_expand_nav_menu_post_data() { 
     1072    if ( ! isset( $_POST['nav-menu-data'] ) ) { 
     1073        return; 
     1074    } 
     1075 
     1076    $data = json_decode( stripslashes( $_POST['nav-menu-data'] ) ); 
     1077 
     1078    if ( ! is_null( $data ) && $data ) { 
     1079        foreach ( $data as $post_input_data ) { 
     1080            // For input names that are arrays (e.g. `menu-item-db-id[3][4][5]`), 
     1081            // derive the array path keys via regex and set the value in $_POST. 
     1082            preg_match( '#([^\[]*)(\[(.+)\])?#', $post_input_data->name, $matches ); 
     1083 
     1084            $array_bits = array( $matches[1] ); 
     1085 
     1086            if ( isset( $matches[3] ) ) { 
     1087                $array_bits = array_merge( $array_bits, explode( '][', $matches[3] ) ); 
     1088            } 
     1089 
     1090            $new_post_data = array(); 
     1091 
     1092            // Build the new array value from leaf to trunk. 
     1093            for ( $i = count( $array_bits ) - 1; $i >= 0; $i -- ) { 
     1094                if ( $i == count( $array_bits ) - 1 ) { 
     1095                    $new_post_data[ $array_bits[ $i ] ] = wp_slash( $post_input_data->value ); 
     1096                } else { 
     1097                    $new_post_data = array( $array_bits[ $i ] => $new_post_data ); 
     1098                } 
     1099            } 
     1100 
     1101            $_POST = array_replace_recursive( $_POST, $new_post_data ); 
     1102        } 
     1103    } 
     1104} 
  • trunk/src/wp-admin/nav-menus.php

    r37488 r37748  
    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': 
  • trunk/src/wp-includes/compat.php

    r37674 r37748  
    436436} 
    437437 
     438if ( ! function_exists( 'array_replace_recursive' ) ) : 
     439    /** 
     440     * PHP-agnostic version of {@link array_replace_recursive()}. 
     441     * 
     442     * The array_replace_recursive() function is a PHP 5.3 function. WordPress 
     443     * currently supports down to PHP 5.2, so this method is a workaround 
     444     * for PHP 5.2. 
     445     * 
     446     * Note: array_replace_recursive() supports infinite arguments, but for our use- 
     447     * case, we only need to support two arguments. 
     448     * 
     449     * Subject to removal once WordPress makes PHP 5.3.0 the minimum requirement. 
     450     * 
     451     * @since 4.5.3 
     452     * 
     453     * @see http://php.net/manual/en/function.array-replace-recursive.php#109390 
     454     * 
     455     * @param  array $base         Array with keys needing to be replaced. 
     456     * @param  array $replacements Array with the replaced keys. 
     457     * 
     458     * @return array 
     459     */ 
     460    function array_replace_recursive( $base = array(), $replacements = array() ) { 
     461        foreach ( array_slice( func_get_args(), 1 ) as $replacements ) { 
     462            $bref_stack = array( &$base ); 
     463            $head_stack = array( $replacements ); 
     464 
     465            do { 
     466                end( $bref_stack ); 
     467 
     468                $bref = &$bref_stack[ key( $bref_stack ) ]; 
     469                $head = array_pop( $head_stack ); 
     470 
     471                unset( $bref_stack[ key( $bref_stack ) ] ); 
     472 
     473                foreach ( array_keys( $head ) as $key ) { 
     474                    if ( isset( $key, $bref ) && is_array( $bref[ $key ] ) && is_array( $head[ $key ] ) ) { 
     475                        $bref_stack[] = &$bref[ $key ]; 
     476                        $head_stack[] = $head[ $key ]; 
     477                    } else { 
     478                        $bref[ $key ] = $head[ $key ]; 
     479                    } 
     480                } 
     481            } while ( count( $head_stack ) ); 
     482        } 
     483 
     484        return $base; 
     485    } 
     486endif; 
     487 
    438488// SPL can be disabled on PHP 5.2 
    439489if ( ! function_exists( 'spl_autoload_register' ) ): 
Note: See TracChangeset for help on using the changeset viewer.