diff --git src/wp-admin/css/customize-nav-menus.css src/wp-admin/css/customize-nav-menus.css
index df16735..163e935 100644
|
|
button.not-a-button { |
646 | 646 | } |
647 | 647 | |
648 | 648 | #custom-menu-item-name.invalid, |
649 | | #custom-menu-item-url.invalid { |
| 649 | #custom-menu-item-url.invalid, |
| 650 | .menu-name-field.invalid, |
| 651 | .menu-name-field.invalid:focus { |
650 | 652 | border: 1px solid #f00; |
651 | 653 | } |
652 | 654 | |
diff --git src/wp-admin/js/customize-nav-menus.js src/wp-admin/js/customize-nav-menus.js
index e707e4d..51e8365 100644
|
|
|
863 | 863 | button.removeClass( 'open' ); |
864 | 864 | button.attr( 'aria-expanded', 'false' ); |
865 | 865 | content.slideUp( 'fast' ); |
| 866 | content.find( '.menu-name-field' ).removeClass( 'invalid' ); |
866 | 867 | } |
867 | 868 | } |
868 | 869 | }); |
… |
… |
|
899 | 900 | return; |
900 | 901 | } |
901 | 902 | menuId = matches[1]; |
902 | | option = new Option( setting().name, menuId ); |
| 903 | option = new Option( setting().name || api.Menus.data.l10n.unnamed, menuId ); |
903 | 904 | control.container.find( 'select' ).append( option ); |
904 | 905 | }); |
905 | 906 | api.bind( 'remove', function( setting ) { |
… |
… |
|
925 | 926 | } |
926 | 927 | control.container.find( 'option[value=' + menuId + ']' ).remove(); |
927 | 928 | } else { |
928 | | control.container.find( 'option[value=' + menuId + ']' ).text( setting().name ); |
| 929 | control.container.find( 'option[value=' + menuId + ']' ).text( setting().name || api.Menus.data.l10n.unnamed ); |
929 | 930 | } |
930 | 931 | }); |
931 | 932 | } |
… |
… |
|
1635 | 1636 | */ |
1636 | 1637 | ready: function() { |
1637 | 1638 | var control = this, |
1638 | | menuId = control.params.menu_id; |
| 1639 | menuId = control.params.menu_id, |
| 1640 | menu = control.setting(), |
| 1641 | name; |
1639 | 1642 | |
1640 | 1643 | if ( 'undefined' === typeof this.params.menu_id ) { |
1641 | 1644 | throw new Error( 'params.menu_id was not defined' ); |
… |
… |
|
1666 | 1669 | this._setupTitle(); |
1667 | 1670 | |
1668 | 1671 | // Add menu to Custom Menu widgets. |
1669 | | if ( control.setting() ) { |
| 1672 | if ( menu ) { |
| 1673 | name = menu.name || api.Menus.data.l10n.unnamed; |
| 1674 | |
1670 | 1675 | api.control.each( function( widgetControl ) { |
1671 | 1676 | if ( ! widgetControl.extended( api.controlConstructor.widget_form ) || 'nav_menu' !== widgetControl.params.widget_id_base ) { |
1672 | 1677 | return; |
1673 | 1678 | } |
1674 | 1679 | var select = widgetControl.container.find( 'select' ); |
1675 | 1680 | if ( select.find( 'option[value=' + String( menuId ) + ']' ).length === 0 ) { |
1676 | | select.append( new Option( control.setting().name, menuId ) ); |
| 1681 | select.append( new Option( name, menuId ) ); |
1677 | 1682 | } |
1678 | 1683 | } ); |
1679 | | $( '#available-widgets-list .widget-inside:has(input.id_base[value=nav_menu]) select:first' ).append( new Option( control.setting().name, menuId ) ); |
| 1684 | $( '#available-widgets-list .widget-inside:has(input.id_base[value=nav_menu]) select:first' ).append( new Option( name, menuId ) ); |
1680 | 1685 | } |
1681 | 1686 | }, |
1682 | 1687 | |
… |
… |
|
1707 | 1712 | }); |
1708 | 1713 | |
1709 | 1714 | control.setting.bind( function( to ) { |
| 1715 | var name; |
1710 | 1716 | if ( false === to ) { |
1711 | 1717 | control._handleDeletion(); |
1712 | 1718 | } else { |
1713 | 1719 | // Update names in the Custom Menu widgets. |
| 1720 | name = to.name || api.Menus.data.l10n.unnamed; |
1714 | 1721 | api.control.each( function( widgetControl ) { |
1715 | 1722 | if ( ! widgetControl.extended( api.controlConstructor.widget_form ) || 'nav_menu' !== widgetControl.params.widget_id_base ) { |
1716 | 1723 | return; |
1717 | 1724 | } |
1718 | 1725 | var select = widgetControl.container.find( 'select' ); |
1719 | | select.find( 'option[value=' + String( menuId ) + ']' ).text( to.name ); |
| 1726 | select.find( 'option[value=' + String( menuId ) + ']' ).text( name ); |
1720 | 1727 | }); |
1721 | | $( '#available-widgets-list .widget-inside:has(input.id_base[value=nav_menu]) select:first option[value=' + String( menuId ) + ']' ).text( to.name ); |
| 1728 | $( '#available-widgets-list .widget-inside:has(input.id_base[value=nav_menu]) select:first option[value=' + String( menuId ) + ']' ).text( name ); |
1722 | 1729 | } |
1723 | 1730 | } ); |
1724 | 1731 | |
… |
… |
|
1877 | 1884 | if ( ! selectedMenuId || ! menuSetting || ! menuSetting() ) { |
1878 | 1885 | container.find( '.theme-location-set' ).hide(); |
1879 | 1886 | } else { |
1880 | | container.find( '.theme-location-set' ).show().find( 'span' ).text( menuSetting().name ); |
| 1887 | container.find( '.theme-location-set' ).show().find( 'span' ).text( menuSetting().name || api.Menus.data.l10n.unnamed ); |
1881 | 1888 | } |
1882 | 1889 | }; |
1883 | 1890 | |
… |
… |
|
1909 | 1916 | return; |
1910 | 1917 | } |
1911 | 1918 | |
1912 | | // Empty names are not allowed (will not be saved), don't update to one. |
1913 | | if ( menu.name ) { |
1914 | | var section = control.container.closest( '.accordion-section' ), |
1915 | | menuId = control.params.menu_id, |
1916 | | controlTitle = section.find( '.accordion-section-title' ), |
1917 | | sectionTitle = section.find( '.customize-section-title h3' ), |
1918 | | location = section.find( '.menu-in-location' ), |
1919 | | action = sectionTitle.find( '.customize-action' ); |
| 1919 | var section = control.container.closest( '.accordion-section' ), |
| 1920 | menuId = control.params.menu_id, |
| 1921 | controlTitle = section.find( '.accordion-section-title' ), |
| 1922 | sectionTitle = section.find( '.customize-section-title h3' ), |
| 1923 | location = section.find( '.menu-in-location' ), |
| 1924 | action = sectionTitle.find( '.customize-action' ), |
| 1925 | name = menu.name || api.Menus.data.l10n.unnamed; |
1920 | 1926 | |
1921 | | // Update the control title |
1922 | | controlTitle.text( menu.name ); |
1923 | | if ( location.length ) { |
1924 | | location.appendTo( controlTitle ); |
1925 | | } |
| 1927 | // Update the control title |
| 1928 | controlTitle.text( name ); |
| 1929 | if ( location.length ) { |
| 1930 | location.appendTo( controlTitle ); |
| 1931 | } |
1926 | 1932 | |
1927 | | // Update the section title |
1928 | | sectionTitle.text( menu.name ); |
1929 | | if ( action.length ) { |
1930 | | action.prependTo( sectionTitle ); |
1931 | | } |
| 1933 | // Update the section title |
| 1934 | sectionTitle.text( name ); |
| 1935 | if ( action.length ) { |
| 1936 | action.prependTo( sectionTitle ); |
| 1937 | } |
1932 | 1938 | |
1933 | | // Update the nav menu name in location selects. |
1934 | | api.control.each( function( control ) { |
1935 | | if ( /^nav_menu_locations\[/.test( control.id ) ) { |
1936 | | control.container.find( 'option[value=' + menuId + ']' ).text( menu.name ); |
1937 | | } |
1938 | | } ); |
| 1939 | // Update the nav menu name in location selects. |
| 1940 | api.control.each( function( control ) { |
| 1941 | if ( /^nav_menu_locations\[/.test( control.id ) ) { |
| 1942 | control.container.find( 'option[value=' + menuId + ']' ).text( name ); |
| 1943 | } |
| 1944 | } ); |
1939 | 1945 | |
1940 | | // Update the nav menu name in all location checkboxes. |
1941 | | section.find( '.customize-control-checkbox input' ).each( function() { |
1942 | | if ( $( this ).prop( 'checked' ) ) { |
1943 | | $( '.current-menu-location-name-' + $( this ).data( 'location-id' ) ).text( menu.name ); |
1944 | | } |
1945 | | } ); |
1946 | | } |
| 1946 | // Update the nav menu name in all location checkboxes. |
| 1947 | section.find( '.customize-control-checkbox input' ).each( function() { |
| 1948 | if ( $( this ).prop( 'checked' ) ) { |
| 1949 | $( '.current-menu-location-name-' + $( this ).data( 'location-id' ) ).text( name ); |
| 1950 | } |
| 1951 | } ); |
1947 | 1952 | } ); |
1948 | 1953 | }, |
1949 | 1954 | |
… |
… |
|
2181 | 2186 | |
2182 | 2187 | /** |
2183 | 2188 | * Create the new menu with the name supplied. |
2184 | | * |
2185 | | * @returns {boolean} |
2186 | 2189 | */ |
2187 | 2190 | submit: function() { |
2188 | 2191 | |
… |
… |
|
2194 | 2197 | customizeId, |
2195 | 2198 | placeholderId = api.Menus.generatePlaceholderAutoIncrementId(); |
2196 | 2199 | |
| 2200 | if ( ! name ) { |
| 2201 | nameInput.addClass( 'invalid' ); |
| 2202 | nameInput.focus(); |
| 2203 | return; |
| 2204 | } |
| 2205 | |
2197 | 2206 | customizeId = 'nav_menu[' + String( placeholderId ) + ']'; |
2198 | 2207 | |
2199 | 2208 | // Register the menu control setting. |
… |
… |
|
2219 | 2228 | params: { |
2220 | 2229 | id: customizeId, |
2221 | 2230 | panel: 'nav_menus', |
2222 | | title: name, |
| 2231 | title: name || api.Menus.data.l10n.unnamed, |
2223 | 2232 | customizeAction: api.Menus.data.l10n.customizingMenus, |
2224 | 2233 | type: 'nav_menu', |
2225 | 2234 | priority: 10, |
… |
… |
|
2230 | 2239 | |
2231 | 2240 | // Clear name field. |
2232 | 2241 | nameInput.val( '' ); |
| 2242 | nameInput.removeClass( 'invalid' ); |
2233 | 2243 | |
2234 | 2244 | wp.a11y.speak( api.Menus.data.l10n.menuAdded ); |
2235 | 2245 | |
… |
… |
|
2299 | 2309 | var insertedMenuIdMapping = {}; |
2300 | 2310 | |
2301 | 2311 | _( data.nav_menu_updates ).each(function( update ) { |
2302 | | var oldCustomizeId, newCustomizeId, oldSetting, newSetting, settingValue, oldSection, newSection; |
| 2312 | var oldCustomizeId, newCustomizeId, customizeId, oldSetting, newSetting, setting, settingValue, oldSection, newSection, wasSaved; |
2303 | 2313 | if ( 'inserted' === update.status ) { |
2304 | 2314 | if ( ! update.previous_term_id ) { |
2305 | 2315 | throw new Error( 'Expected previous_term_id' ); |
… |
… |
|
2321 | 2331 | if ( ! settingValue ) { |
2322 | 2332 | throw new Error( 'Did not expect setting to be empty (deleted).' ); |
2323 | 2333 | } |
2324 | | settingValue = _.clone( settingValue ); |
| 2334 | settingValue = $.extend( _.clone( settingValue ), update.saved_value ); |
2325 | 2335 | |
2326 | 2336 | insertedMenuIdMapping[ update.previous_term_id ] = update.term_id; |
2327 | 2337 | newCustomizeId = 'nav_menu[' + String( update.term_id ) + ']'; |
… |
… |
|
2379 | 2389 | } |
2380 | 2390 | |
2381 | 2391 | // @todo Update the Custom Menu selects, ensuring the newly-inserted IDs are used for any that have selected a placeholder menu. |
| 2392 | } else if ( 'updated' === update.status ) { |
| 2393 | customizeId = 'nav_menu[' + String( update.term_id ) + ']'; |
| 2394 | if ( ! api.has( customizeId ) ) { |
| 2395 | throw new Error( 'Expected setting to exist: ' + customizeId ); |
| 2396 | } |
| 2397 | |
| 2398 | // Make sure the setting gets updated with its sanitized server value (specifically the conflict-resolved name). |
| 2399 | setting = api( customizeId ); |
| 2400 | if ( ! _.isEqual( update.saved_value, setting.get() ) ) { |
| 2401 | wasSaved = api.state( 'saved' ).get(); |
| 2402 | setting.set( update.saved_value ); |
| 2403 | setting._dirty = false; |
| 2404 | api.state( 'saved' ).set( wasSaved ); |
| 2405 | } |
2382 | 2406 | } |
2383 | 2407 | } ); |
2384 | 2408 | |
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 { |
281 | 281 | 'itemTypes' => $this->available_item_types(), |
282 | 282 | 'l10n' => array( |
283 | 283 | 'untitled' => _x( '(no label)', 'missing menu item navigation label' ), |
| 284 | 'unnamed' => _x( '(unnamed)', 'Missing menu name.' ), |
284 | 285 | 'custom_label' => __( 'Custom Link' ), |
285 | 286 | /* translators: %s: Current menu location */ |
286 | 287 | 'menuLocation' => __( '(Currently set to: %s)' ), |
diff --git src/wp-includes/class-wp-customize-setting.php src/wp-includes/class-wp-customize-setting.php
index 5dd5293..3eb9824 100644
|
|
class WP_Customize_Nav_Menu_Item_Setting extends WP_Customize_Setting { |
1182 | 1182 | if ( false === $nav_menu_setting->save() ) { |
1183 | 1183 | $this->update_status = 'error'; |
1184 | 1184 | $this->update_error = new WP_Error( 'nav_menu_setting_failure' ); |
| 1185 | return; |
1185 | 1186 | } |
1186 | 1187 | |
1187 | 1188 | if ( $nav_menu_setting->previous_term_id !== intval( $value['nav_menu_term_id'] ) ) { |
… |
… |
class WP_Customize_Nav_Menu_Item_Setting extends WP_Customize_Setting { |
1207 | 1208 | if ( false === $parent_nav_menu_item_setting->save() ) { |
1208 | 1209 | $this->update_status = 'error'; |
1209 | 1210 | $this->update_error = new WP_Error( 'nav_menu_item_setting_failure' ); |
| 1211 | return; |
1210 | 1212 | } |
1211 | 1213 | |
1212 | 1214 | if ( $parent_nav_menu_item_setting->previous_post_id !== intval( $value['menu_item_parent'] ) ) { |
… |
… |
class WP_Customize_Nav_Menu_Setting extends WP_Customize_Setting { |
1606 | 1608 | $value = array_merge( $default, $value ); |
1607 | 1609 | $value = wp_array_slice_assoc( $value, array_keys( $default ) ); |
1608 | 1610 | |
| 1611 | if ( '' === $value['name'] ) { |
| 1612 | $value['name'] = _x( '(unnamed)', 'Missing menu name.' ); |
| 1613 | } |
| 1614 | |
1609 | 1615 | $value['name'] = trim( esc_html( $value['name'] ) ); // This sanitization code is used in wp-admin/nav-menus.php. |
1610 | 1616 | $value['description'] = sanitize_text_field( $value['description'] ); |
1611 | 1617 | $value['parent'] = max( 0, intval( $value['parent'] ) ); |
… |
… |
class WP_Customize_Nav_Menu_Setting extends WP_Customize_Setting { |
1673 | 1679 | $menu_data['menu-name'] = $value['name']; |
1674 | 1680 | } |
1675 | 1681 | |
1676 | | $r = wp_update_nav_menu_object( $is_placeholder ? 0 : $this->term_id, $menu_data ); |
| 1682 | $menu_id = $is_placeholder ? 0 : $this->term_id; |
| 1683 | $r = wp_update_nav_menu_object( $menu_id, $menu_data ); |
| 1684 | $original_name = $menu_data['menu-name']; |
| 1685 | $name_conflict_suffix = 1; |
| 1686 | while ( is_wp_error( $r ) && 'menu_exists' === $r->get_error_code() ) { |
| 1687 | $name_conflict_suffix += 1; |
| 1688 | $menu_data['menu-name'] = sprintf( __( '%1$s (%2$d)' ), $original_name, $name_conflict_suffix ); |
| 1689 | $r = wp_update_nav_menu_object( $menu_id, $menu_data ); |
| 1690 | } |
| 1691 | |
1677 | 1692 | if ( is_wp_error( $r ) ) { |
1678 | 1693 | $this->update_status = 'error'; |
1679 | 1694 | $this->update_error = $r; |
… |
… |
class WP_Customize_Nav_Menu_Setting extends WP_Customize_Setting { |
1764 | 1779 | 'previous_term_id' => $this->previous_term_id, |
1765 | 1780 | 'error' => $this->update_error ? $this->update_error->get_error_code() : null, |
1766 | 1781 | 'status' => $this->update_status, |
| 1782 | 'saved_value' => $this->value(), |
1767 | 1783 | ); |
1768 | 1784 | |
1769 | 1785 | return $data; |