Make WordPress Core

Changeset 37748


Ignore:
Timestamp:
06/19/2016 12:24:23 PM (10 years 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.