Make WordPress Core

Ticket #32760: 32760.4.diff

File 32760.4.diff, 13.4 KB (added by westonruter, 9 years ago)

Additional change: https://github.com/xwp/wordpress-develop/commit/8b3615aab81ff4115d233ac48d90a63f7d58f5b5

  • src/wp-admin/css/customize-nav-menus.css

    diff --git src/wp-admin/css/customize-nav-menus.css src/wp-admin/css/customize-nav-menus.css
    index aa0deed..fc14598 100644
    button.not-a-button { 
    654654}
    655655
    656656#custom-menu-item-name.invalid,
    657 #custom-menu-item-url.invalid {
     657#custom-menu-item-url.invalid,
     658.menu-name-field.invalid,
     659.menu-name-field.invalid:focus {
    658660        border: 1px solid #f00;
    659661}
    660662
  • src/wp-admin/js/customize-nav-menus.js

    diff --git src/wp-admin/js/customize-nav-menus.js src/wp-admin/js/customize-nav-menus.js
    index ee1e7b9..563f71c 100644
     
    864864                                button.removeClass( 'open' );
    865865                                button.attr( 'aria-expanded', 'false' );
    866866                                content.slideUp( 'fast' );
     867                                content.find( '.menu-name-field' ).removeClass( 'invalid' );
    867868                        }
    868869                }
    869870        });
     
    900901                                        return;
    901902                                }
    902903                                menuId = matches[1];
    903                                 option = new Option( setting().name, menuId );
     904                                option = new Option( displayNavMenuName( setting().name ), menuId );
    904905                                control.container.find( 'select' ).append( option );
    905906                        });
    906907                        api.bind( 'remove', function( setting ) {
     
    926927                                        }
    927928                                        control.container.find( 'option[value=' + menuId + ']' ).remove();
    928929                                } else {
    929                                         control.container.find( 'option[value=' + menuId + ']' ).text( setting().name );
     930                                        control.container.find( 'option[value=' + menuId + ']' ).text( displayNavMenuName( setting().name ) );
    930931                                }
    931932                        });
    932933                }
     
    16361637                 */
    16371638                ready: function() {
    16381639                        var control = this,
    1639                                 menuId = control.params.menu_id;
     1640                                menuId = control.params.menu_id,
     1641                                menu = control.setting(),
     1642                                name;
    16401643
    16411644                        if ( 'undefined' === typeof this.params.menu_id ) {
    16421645                                throw new Error( 'params.menu_id was not defined' );
     
    16671670                        this._setupTitle();
    16681671
    16691672                        // Add menu to Custom Menu widgets.
    1670                         if ( control.setting() ) {
     1673                        if ( menu ) {
     1674                                name = displayNavMenuName( menu.name );
     1675
    16711676                                api.control.each( function( widgetControl ) {
    16721677                                        if ( ! widgetControl.extended( api.controlConstructor.widget_form ) || 'nav_menu' !== widgetControl.params.widget_id_base ) {
    16731678                                                return;
    16741679                                        }
    16751680                                        var select = widgetControl.container.find( 'select' );
    16761681                                        if ( select.find( 'option[value=' + String( menuId ) + ']' ).length === 0 ) {
    1677                                                 select.append( new Option( control.setting().name, menuId ) );
     1682                                                select.append( new Option( name, menuId ) );
    16781683                                        }
    16791684                                } );
    1680                                 $( '#available-widgets-list .widget-inside:has(input.id_base[value=nav_menu]) select:first' ).append( new Option( control.setting().name, menuId ) );
     1685                                $( '#available-widgets-list .widget-inside:has(input.id_base[value=nav_menu]) select:first' ).append( new Option( name, menuId ) );
    16811686                        }
    16821687                },
    16831688
     
    17081713                        });
    17091714
    17101715                        control.setting.bind( function( to ) {
     1716                                var name;
    17111717                                if ( false === to ) {
    17121718                                        control._handleDeletion();
    17131719                                } else {
    17141720                                        // Update names in the Custom Menu widgets.
     1721                                        name = displayNavMenuName( to.name );
    17151722                                        api.control.each( function( widgetControl ) {
    17161723                                                if ( ! widgetControl.extended( api.controlConstructor.widget_form ) || 'nav_menu' !== widgetControl.params.widget_id_base ) {
    17171724                                                        return;
    17181725                                                }
    17191726                                                var select = widgetControl.container.find( 'select' );
    1720                                                 select.find( 'option[value=' + String( menuId ) + ']' ).text( to.name );
     1727                                                select.find( 'option[value=' + String( menuId ) + ']' ).text( name );
    17211728                                        });
    1722                                         $( '#available-widgets-list .widget-inside:has(input.id_base[value=nav_menu]) select:first option[value=' + String( menuId ) + ']' ).text( to.name );
     1729                                        $( '#available-widgets-list .widget-inside:has(input.id_base[value=nav_menu]) select:first option[value=' + String( menuId ) + ']' ).text( name );
    17231730                                }
    17241731                        } );
    17251732
     
    18781885                                        if ( ! selectedMenuId || ! menuSetting || ! menuSetting() ) {
    18791886                                                container.find( '.theme-location-set' ).hide();
    18801887                                        } else {
    1881                                                 container.find( '.theme-location-set' ).show().find( 'span' ).text( menuSetting().name );
     1888                                                container.find( '.theme-location-set' ).show().find( 'span' ).text( displayNavMenuName( menuSetting().name ) );
    18821889                                        }
    18831890                                };
    18841891
     
    19101917                                        return;
    19111918                                }
    19121919
    1913                                 // Empty names are not allowed (will not be saved), don't update to one.
    1914                                 if ( menu.name ) {
    1915                                         var section = control.container.closest( '.accordion-section' ),
    1916                                                 menuId = control.params.menu_id,
    1917                                                 controlTitle = section.find( '.accordion-section-title' ),
    1918                                                 sectionTitle = section.find( '.customize-section-title h3' ),
    1919                                                 location = section.find( '.menu-in-location' ),
    1920                                                 action = sectionTitle.find( '.customize-action' );
     1920                                var section = control.container.closest( '.accordion-section' ),
     1921                                        menuId = control.params.menu_id,
     1922                                        controlTitle = section.find( '.accordion-section-title' ),
     1923                                        sectionTitle = section.find( '.customize-section-title h3' ),
     1924                                        location = section.find( '.menu-in-location' ),
     1925                                        action = sectionTitle.find( '.customize-action' ),
     1926                                        name = displayNavMenuName( menu.name );
    19211927
    1922                                         // Update the control title
    1923                                         controlTitle.text( menu.name );
    1924                                         if ( location.length ) {
    1925                                                 location.appendTo( controlTitle );
    1926                                         }
     1928                                // Update the control title
     1929                                controlTitle.text( name );
     1930                                if ( location.length ) {
     1931                                        location.appendTo( controlTitle );
     1932                                }
    19271933
    1928                                         // Update the section title
    1929                                         sectionTitle.text( menu.name );
    1930                                         if ( action.length ) {
    1931                                                 action.prependTo( sectionTitle );
    1932                                         }
     1934                                // Update the section title
     1935                                sectionTitle.text( name );
     1936                                if ( action.length ) {
     1937                                        action.prependTo( sectionTitle );
     1938                                }
    19331939
    1934                                         // Update the nav menu name in location selects.
    1935                                         api.control.each( function( control ) {
    1936                                                 if ( /^nav_menu_locations\[/.test( control.id ) ) {
    1937                                                         control.container.find( 'option[value=' + menuId + ']' ).text( menu.name );
    1938                                                 }
    1939                                         } );
     1940                                // Update the nav menu name in location selects.
     1941                                api.control.each( function( control ) {
     1942                                        if ( /^nav_menu_locations\[/.test( control.id ) ) {
     1943                                                control.container.find( 'option[value=' + menuId + ']' ).text( name );
     1944                                        }
     1945                                } );
    19401946
    1941                                         // Update the nav menu name in all location checkboxes.
    1942                                         section.find( '.customize-control-checkbox input' ).each( function() {
    1943                                                 if ( $( this ).prop( 'checked' ) ) {
    1944                                                         $( '.current-menu-location-name-' + $( this ).data( 'location-id' ) ).text( menu.name );
    1945                                                 }
    1946                                         } );
    1947                                 }
     1947                                // Update the nav menu name in all location checkboxes.
     1948                                section.find( '.customize-control-checkbox input' ).each( function() {
     1949                                        if ( $( this ).prop( 'checked' ) ) {
     1950                                                $( '.current-menu-location-name-' + $( this ).data( 'location-id' ) ).text( name );
     1951                                        }
     1952                                } );
    19481953                        } );
    19491954                },
    19501955
     
    21822187
    21832188                /**
    21842189                 * Create the new menu with the name supplied.
    2185                  *
    2186                  * @returns {boolean}
    21872190                 */
    21882191                submit: function() {
    21892192
     
    21952198                                customizeId,
    21962199                                placeholderId = api.Menus.generatePlaceholderAutoIncrementId();
    21972200
     2201                        if ( ! name ) {
     2202                                nameInput.addClass( 'invalid' );
     2203                                nameInput.focus();
     2204                                return;
     2205                        }
     2206
    21982207                        customizeId = 'nav_menu[' + String( placeholderId ) + ']';
    21992208
    22002209                        // Register the menu control setting.
     
    22202229                                params: {
    22212230                                        id: customizeId,
    22222231                                        panel: 'nav_menus',
    2223                                         title: name,
     2232                                        title: displayNavMenuName( name ),
    22242233                                        customizeAction: api.Menus.data.l10n.customizingMenus,
    22252234                                        type: 'nav_menu',
    22262235                                        priority: 10,
     
    22312240
    22322241                        // Clear name field.
    22332242                        nameInput.val( '' );
     2243                        nameInput.removeClass( 'invalid' );
    22342244
    22352245                        wp.a11y.speak( api.Menus.data.l10n.menuAdded );
    22362246
     
    23002310                var insertedMenuIdMapping = {};
    23012311
    23022312                _( data.nav_menu_updates ).each(function( update ) {
    2303                         var oldCustomizeId, newCustomizeId, oldSetting, newSetting, settingValue, oldSection, newSection;
     2313                        var oldCustomizeId, newCustomizeId, customizeId, oldSetting, newSetting, setting, settingValue, oldSection, newSection, wasSaved;
    23042314                        if ( 'inserted' === update.status ) {
    23052315                                if ( ! update.previous_term_id ) {
    23062316                                        throw new Error( 'Expected previous_term_id' );
     
    23222332                                if ( ! settingValue ) {
    23232333                                        throw new Error( 'Did not expect setting to be empty (deleted).' );
    23242334                                }
    2325                                 settingValue = _.clone( settingValue );
     2335                                settingValue = $.extend( _.clone( settingValue ), update.saved_value );
    23262336
    23272337                                insertedMenuIdMapping[ update.previous_term_id ] = update.term_id;
    23282338                                newCustomizeId = 'nav_menu[' + String( update.term_id ) + ']';
     
    23802390                                }
    23812391
    23822392                                // @todo Update the Custom Menu selects, ensuring the newly-inserted IDs are used for any that have selected a placeholder menu.
     2393                        } else if ( 'updated' === update.status ) {
     2394                                customizeId = 'nav_menu[' + String( update.term_id ) + ']';
     2395                                if ( ! api.has( customizeId ) ) {
     2396                                        throw new Error( 'Expected setting to exist: ' + customizeId );
     2397                                }
     2398
     2399                                // Make sure the setting gets updated with its sanitized server value (specifically the conflict-resolved name).
     2400                                setting = api( customizeId );
     2401                                if ( ! _.isEqual( update.saved_value, setting.get() ) ) {
     2402                                        wasSaved = api.state( 'saved' ).get();
     2403                                        setting.set( update.saved_value );
     2404                                        setting._dirty = false;
     2405                                        api.state( 'saved' ).set( wasSaved );
     2406                                }
    23832407                        }
    23842408                } );
    23852409
     
    25272551                return 'nav_menu_item[' + menuItemId + ']';
    25282552        }
    25292553
     2554        /**
     2555         * Apply sanitize_text_field()-like logic to the supplied name, returning a
     2556         * "unnammed" fallback string if the name is then empty.
     2557         *
     2558         * @param {string} name
     2559         * @returns {string}
     2560         */
     2561        function displayNavMenuName( name ) {
     2562                name = $( '<div>' ).text( name ).html(); // Emulate esc_html() which is used in wp-admin/nav-menus.php.
     2563                name = $.trim( name );
     2564                return name || api.Menus.data.l10n.unnamed;
     2565        }
     2566
    25302567})( wp.customize, wp, jQuery );
  • src/wp-includes/class-wp-customize-nav-menus.php

    diff --git src/wp-includes/class-wp-customize-nav-menus.php src/wp-includes/class-wp-customize-nav-menus.php
    index 7fbbda8..a9aae0d 100644
    final class WP_Customize_Nav_Menus { 
    281281                        'itemTypes'            => $this->available_item_types(),
    282282                        'l10n'                 => array(
    283283                                'untitled'          => _x( '(no label)', 'missing menu item navigation label' ),
     284                                'unnamed'           => _x( '(unnamed)', 'Missing menu name.' ),
    284285                                'custom_label'      => __( 'Custom Link' ),
    285286                                /* translators: %s: Current menu location */
    286287                                'menuLocation'      => __( '(Currently set to: %s)' ),
  • src/wp-includes/class-wp-customize-setting.php

    diff --git src/wp-includes/class-wp-customize-setting.php src/wp-includes/class-wp-customize-setting.php
    index 5dd5293..b36919c 100644
    class WP_Customize_Nav_Menu_Item_Setting extends WP_Customize_Setting { 
    11821182                                if ( false === $nav_menu_setting->save() ) {
    11831183                                        $this->update_status = 'error';
    11841184                                        $this->update_error  = new WP_Error( 'nav_menu_setting_failure' );
     1185                                        return;
    11851186                                }
    11861187
    11871188                                if ( $nav_menu_setting->previous_term_id !== intval( $value['nav_menu_term_id'] ) ) {
    class WP_Customize_Nav_Menu_Item_Setting extends WP_Customize_Setting { 
    12071208                                if ( false === $parent_nav_menu_item_setting->save() ) {
    12081209                                        $this->update_status = 'error';
    12091210                                        $this->update_error  = new WP_Error( 'nav_menu_item_setting_failure' );
     1211                                        return;
    12101212                                }
    12111213
    12121214                                if ( $parent_nav_menu_item_setting->previous_post_id !== intval( $value['menu_item_parent'] ) ) {
    class WP_Customize_Nav_Menu_Setting extends WP_Customize_Setting { 
    16061608                $value = array_merge( $default, $value );
    16071609                $value = wp_array_slice_assoc( $value, array_keys( $default ) );
    16081610
     1611                if ( '' === $value['name'] ) {
     1612                        $value['name'] = _x( '(unnamed)', 'Missing menu name.' );
     1613                }
     1614
    16091615                $value['name']        = trim( esc_html( $value['name'] ) ); // This sanitization code is used in wp-admin/nav-menus.php.
    16101616                $value['description'] = sanitize_text_field( $value['description'] );
    16111617                $value['parent']      = max( 0, intval( $value['parent'] ) );
    class WP_Customize_Nav_Menu_Setting extends WP_Customize_Setting { 
    16691675                } else {
    16701676                        // Insert or update menu.
    16711677                        $menu_data = wp_array_slice_assoc( $value, array( 'description', 'parent' ) );
    1672                         if ( isset( $value['name'] ) ) {
    1673                                 $menu_data['menu-name'] = $value['name'];
     1678                        $menu_data['menu-name'] = $value['name'];
     1679                        if ( '' === trim( $menu_data['menu-name'] ) ) {
     1680                                $menu_data['menu-name'] = _x( '(unnamed)', 'Missing menu name.' );
     1681                        }
     1682
     1683                        $menu_id = $is_placeholder ? 0 : $this->term_id;
     1684                        $r = wp_update_nav_menu_object( $menu_id, $menu_data );
     1685                        $original_name = $menu_data['menu-name'];
     1686                        $name_conflict_suffix = 1;
     1687                        while ( is_wp_error( $r ) && 'menu_exists' === $r->get_error_code() ) {
     1688                                $name_conflict_suffix += 1;
     1689                                $menu_data['menu-name'] = sprintf( __( '%1$s (%2$d)' ), $original_name, $name_conflict_suffix );
     1690                                $r = wp_update_nav_menu_object( $menu_id, $menu_data );
    16741691                        }
    16751692
    1676                         $r = wp_update_nav_menu_object( $is_placeholder ? 0 : $this->term_id, $menu_data );
    16771693                        if ( is_wp_error( $r ) ) {
    16781694                                $this->update_status = 'error';
    16791695                                $this->update_error  = $r;
    class WP_Customize_Nav_Menu_Setting extends WP_Customize_Setting { 
    17641780                        'previous_term_id' => $this->previous_term_id,
    17651781                        'error'            => $this->update_error ? $this->update_error->get_error_code() : null,
    17661782                        'status'           => $this->update_status,
     1783                        'saved_value'      => $this->value(),
    17671784                );
    17681785
    17691786                return $data;