Make WordPress Core

Changeset 36510


Ignore:
Timestamp:
02/11/2016 07:07:30 PM (9 years ago)
Author:
ericlewis
Message:

Menus: Allow larger menus to be created in the Edit Menu screen.

In the Edit Menu screen, each menu item creates 11 form input elements. In menus with more than 71 menu items, often items after the 71st weren't saved. This was because PHP's runtime configuration max_input_vars default value is 1000. Large menus exceed this, so PHP didn't populate the $_POST superglobal for the latter menu items.

The entire form is now JSON-encoded into a single input which populates $_POST manually on form submission.

This was attempted previously in [36506] which was reverted in [36507]. Some form fields were not being slurped into the form's JSON representation, and it did not scale for a site with many posts. This approach fixes those problems.

Props ocean90, afercia.
See #14134.

Location:
trunk/src
Files:
3 edited

Legend:

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

    r36507 r36510  
    4444            this.attachQuickSearchListeners();
    4545            this.attachThemeLocationsListeners();
     46            this.attachMenuSaveSubmitListeners();
    4647
    4748            this.attachTabsPanelListeners();
     
    835836        },
    836837
     838        attachMenuSaveSubmitListeners : function() {
     839            /*
     840             * When a navigation menu is saved, store a JSON representation of all form data
     841             * in a single input to avoid PHP `max_input_vars` limitations. See #14134.
     842             */
     843            $('#update-nav-menu').submit(function() {
     844                var navMenuData = $('#update-nav-menu').serializeArray();
     845                $('[name="nav-menu-data"]').val( JSON.stringify( navMenuData ) );
     846            });
     847        },
     848
    837849        attachThemeLocationsListeners : function() {
    838850            var loc = $('#nav-menu-theme-locations'), params = {};
  • trunk/src/wp-admin/nav-menus.php

    r36507 r36510  
    5050$action = isset( $_REQUEST['action'] ) ? $_REQUEST['action'] : 'edit';
    5151
     52/*
     53 * If a JSON blob of navigation menu data is found, expand it and inject it
     54 * into `$_POST` to avoid PHP `max_input_vars` limitations. See #14134.
     55 */
     56if ( 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( '#(.*)(?:\[(\d+)\])#', $post_input_data->name, $matches ) ) {
     62                if ( empty( $_POST[$matches[1]] ) ) {
     63                    $_POST[$matches[1]] = array();
     64                }
     65                $_POST[$matches[1]][(int)$matches[2]] = $post_input_data->value;
     66            } else {
     67                $_POST[$post_input_data->name] = $post_input_data->value;
     68            }
     69        }
     70    }
     71}
    5272switch ( $action ) {
    5373    case 'add-menu-item':
     
    732752            <form id="update-nav-menu" method="post" enctype="multipart/form-data">
    733753                <div class="menu-edit <?php if ( $add_new_screen ) echo 'blank-slate'; ?>">
     754                    <input type="hidden" name="nav-menu-data">
    734755                    <?php
    735756                    wp_nonce_field( 'closedpostboxes', 'closedpostboxesnonce', false );
  • trunk/src/wp-includes/script-loader.php

    r36388 r36510  
    643643
    644644        // Navigation Menus
    645         $scripts->add( 'nav-menu', "/wp-admin/js/nav-menu$suffix.js", array( 'jquery-ui-sortable', 'jquery-ui-draggable', 'jquery-ui-droppable', 'wp-lists', 'postbox' ) );
     645        $scripts->add( 'nav-menu', "/wp-admin/js/nav-menu$suffix.js", array( 'jquery-ui-sortable', 'jquery-ui-draggable', 'jquery-ui-droppable', 'wp-lists', 'postbox', 'json2' ) );
    646646        did_action( 'init' ) && $scripts->localize( 'nav-menu', 'navMenuL10n', array(
    647647            'noResultsFound' => __( 'No results found.' ),
Note: See TracChangeset for help on using the changeset viewer.