Customize: Improve the menu creation flow.

Often, folks run into two issues when they create new menus: they click "Add a Menu" thinking it will add a new page to their menu, or they forget to assign their new menu to a location, and then wonder why it doesn't show up on their site.

This commit rearranges the order of items in the menu panel, and updates the flow for creating a menu by breaking it up into steps. Additionally, more help text has been added to guide people through the process of creating a menu.

Also adds default `type` lookups for Panel and Section instances. See #30741.

Props bpayton, obenland, westonruter, celloexpessions, afercia, melchoyce, zoonini, michelleweber.
Fixes #40104.

Built from https://develop.svn.wordpress.org/trunk@41768


git-svn-id: http://core.svn.wordpress.org/trunk@41602 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
Weston Ruter 2017-10-05 02:22:49 +00:00
parent a47a253e90
commit 275f4713a5
22 changed files with 672 additions and 384 deletions

View File

@ -557,11 +557,16 @@ body.trashing #publish-settings {
border-bottom-color: #ddd;
}
#customize-theme-controls .control-panel-content .control-section:nth-child(2),
#customize-theme-controls .control-panel-nav_menus .control-section:nth-child(3) {
#customize-theme-controls .control-panel-content:not(.control-panel-nav_menus) .control-section:nth-child(2),
#customize-theme-controls .control-panel-nav_menus .control-section-nav_menu,
#customize-theme-controls .control-section-nav_menu_locations .accordion-section-title {
border-top: 1px solid #ddd;
}
#customize-theme-controls .control-panel-nav_menus .control-section-nav_menu + .control-section-nav_menu {
border-top: none;
}
#customize-theme-controls > ul {
margin: 0;
}
@ -661,7 +666,8 @@ body.trashing #publish-settings {
position: static;
}
.customize-section-description-container {
.customize-section-description-container,
.control-section-nav_menu .customize-section-description-container {
margin-bottom: 15px;
}

File diff suppressed because one or more lines are too long

View File

@ -557,11 +557,16 @@ body.trashing #publish-settings {
border-bottom-color: #ddd;
}
#customize-theme-controls .control-panel-content .control-section:nth-child(2),
#customize-theme-controls .control-panel-nav_menus .control-section:nth-child(3) {
#customize-theme-controls .control-panel-content:not(.control-panel-nav_menus) .control-section:nth-child(2),
#customize-theme-controls .control-panel-nav_menus .control-section-nav_menu,
#customize-theme-controls .control-section-nav_menu_locations .accordion-section-title {
border-top: 1px solid #ddd;
}
#customize-theme-controls .control-panel-nav_menus .control-section-nav_menu + .control-section-nav_menu {
border-top: none;
}
#customize-theme-controls > ul {
margin: 0;
}
@ -661,7 +666,8 @@ body.trashing #publish-settings {
position: static;
}
.customize-section-description-container {
.customize-section-description-container,
.control-section-nav_menu .customize-section-description-container {
margin-bottom: 15px;
}

File diff suppressed because one or more lines are too long

View File

@ -1,10 +1,22 @@
#customize-theme-controls #accordion-section-menu_locations {
position: relative;
margin-bottom: 15px;
margin-top: 15px;
}
#customize-theme-controls #accordion-section-menu_locations > .accordion-section-title {
border-bottom-color: #ddd;
margin-top: 15px;
}
#customize-theme-controls .customize-section-title-nav_menus-heading,
#customize-theme-controls .customize-section-title-menu_locations-heading,
#customize-theme-controls .customize-section-title-menu_locations-description {
padding: 0 12px 0 12px;
}
#customize-theme-controls .customize-control-description.customize-section-title-menu_locations-description {
/* Override the default italic style for control descriptions */
font-style: normal;
}
.menu-in-location,
@ -27,6 +39,23 @@
line-height: 28px;
}
#customize-controls .customize-control-nav_menu_name {
margin-bottom: 12px;
}
.customize-control-nav_menu_name p:last-of-type {
margin-bottom: 0;
}
#customize-new-menu-submit {
float: left;
min-width: 85px;
}
#customize-new-menu-submit-description {
margin: 0;
}
.wp-customizer .menu-item-bar .menu-item-handle,
.wp-customizer .menu-item-settings,
.wp-customizer .menu-item-settings .description-thin {
@ -175,12 +204,25 @@
border-top: none;
}
.menu-settings .customize-control-checkbox label {
.wp-customizer .menu-location-settings {
margin-top: 12px;
border-top: none;
}
.wp-customizer .control-section-nav_menu .menu-location-settings {
margin-top: 24px;
border-top: 1px solid #ddd;
padding-top: 12px;
}
.menu-settings .customize-control-checkbox label,
.menu-location-settings .customize-control-checkbox label {
line-height: 1;
}
/* @todo update selector or potentially remove */
.menu-settings .customize-control.customize-control-checkbox {
.menu-settings .customize-control.customize-control-checkbox,
.menu-location-settings .customize-control.customize-control-checkbox {
margin-bottom: 8px; /* Override collapsing at smaller viewports. */
}
@ -738,27 +780,16 @@ body.adding-menu-items #customize-preview iframe {
/* @todo update selector */
#accordion-section-add_menu {
margin: 15px 12px;
overflow: hidden;
text-align: left;
}
.new-menu-section-content {
display: none;
padding: 15px 0 0 0;
clear: both;
#accordion-section-add_menu h3,
#accordion-section-add_menu .customize-add-menu-button {
margin: 0;
}
/* @todo update selector */
#accordion-section-add_menu .accordion-section-title {
padding-right: 45px;
}
/* @todo update selector */
#accordion-section-add_menu .accordion-section-title:before {
font: normal 20px/1 dashicons;
position: absolute;
top: 12px;
right: 14px;
content: "\f132";
#accordion-section-add_menu .customize-add-menu-button {
font-weight: normal;
}
#create-new-menu-submit {
@ -772,6 +803,10 @@ body.adding-menu-items #customize-preview iframe {
width: 100%;
}
.assigned-menu-locations-title p {
margin: 0 0 8px 0;
}
li.assigned-to-menu-location .menu-delete-item {
display: none;
}
@ -808,7 +843,12 @@ li.assigned-to-menu-location .add-new-menu-item {
margin-bottom: 0;
}
.customize-control-nav_menu {
.customize-control-nav_menu .new-menu-item-invitation {
margin-top: 0;
margin-bottom: 0;
}
.customize-control-nav_menu .customize-control-nav_menu-buttons {
margin-top: 12px;
}

File diff suppressed because one or more lines are too long

View File

@ -1,10 +1,22 @@
#customize-theme-controls #accordion-section-menu_locations {
position: relative;
margin-bottom: 15px;
margin-top: 15px;
}
#customize-theme-controls #accordion-section-menu_locations > .accordion-section-title {
border-bottom-color: #ddd;
margin-top: 15px;
}
#customize-theme-controls .customize-section-title-nav_menus-heading,
#customize-theme-controls .customize-section-title-menu_locations-heading,
#customize-theme-controls .customize-section-title-menu_locations-description {
padding: 0 12px 0 12px;
}
#customize-theme-controls .customize-control-description.customize-section-title-menu_locations-description {
/* Override the default italic style for control descriptions */
font-style: normal;
}
.menu-in-location,
@ -27,6 +39,23 @@
line-height: 28px;
}
#customize-controls .customize-control-nav_menu_name {
margin-bottom: 12px;
}
.customize-control-nav_menu_name p:last-of-type {
margin-bottom: 0;
}
#customize-new-menu-submit {
float: right;
min-width: 85px;
}
#customize-new-menu-submit-description {
margin: 0;
}
.wp-customizer .menu-item-bar .menu-item-handle,
.wp-customizer .menu-item-settings,
.wp-customizer .menu-item-settings .description-thin {
@ -175,12 +204,25 @@
border-top: none;
}
.menu-settings .customize-control-checkbox label {
.wp-customizer .menu-location-settings {
margin-top: 12px;
border-top: none;
}
.wp-customizer .control-section-nav_menu .menu-location-settings {
margin-top: 24px;
border-top: 1px solid #ddd;
padding-top: 12px;
}
.menu-settings .customize-control-checkbox label,
.menu-location-settings .customize-control-checkbox label {
line-height: 1;
}
/* @todo update selector or potentially remove */
.menu-settings .customize-control.customize-control-checkbox {
.menu-settings .customize-control.customize-control-checkbox,
.menu-location-settings .customize-control.customize-control-checkbox {
margin-bottom: 8px; /* Override collapsing at smaller viewports. */
}
@ -738,27 +780,16 @@ body.adding-menu-items #customize-preview iframe {
/* @todo update selector */
#accordion-section-add_menu {
margin: 15px 12px;
overflow: hidden;
text-align: right;
}
.new-menu-section-content {
display: none;
padding: 15px 0 0 0;
clear: both;
#accordion-section-add_menu h3,
#accordion-section-add_menu .customize-add-menu-button {
margin: 0;
}
/* @todo update selector */
#accordion-section-add_menu .accordion-section-title {
padding-left: 45px;
}
/* @todo update selector */
#accordion-section-add_menu .accordion-section-title:before {
font: normal 20px/1 dashicons;
position: absolute;
top: 12px;
left: 14px;
content: "\f132";
#accordion-section-add_menu .customize-add-menu-button {
font-weight: normal;
}
#create-new-menu-submit {
@ -772,6 +803,10 @@ body.adding-menu-items #customize-preview iframe {
width: 100%;
}
.assigned-menu-locations-title p {
margin: 0 0 8px 0;
}
li.assigned-to-menu-location .menu-delete-item {
display: none;
}
@ -808,7 +843,12 @@ li.assigned-to-menu-location .add-new-menu-item {
margin-bottom: 0;
}
.customize-control-nav_menu {
.customize-control-nav_menu .new-menu-item-invitation {
margin-top: 0;
margin-bottom: 0;
}
.customize-control-nav_menu .customize-control-nav_menu-buttons {
margin-top: 12px;
}

File diff suppressed because one or more lines are too long

View File

@ -1234,8 +1234,21 @@
* @param {object} [options.params] - Deprecated wrapper for the above properties.
*/
initialize: function ( id, options ) {
var section = this;
Container.prototype.initialize.call( section, id, options );
var section = this, params;
params = options.params || options;
// Look up the type if one was not supplied.
if ( ! params.type ) {
_.find( api.sectionConstructor, function( Constructor, type ) {
if ( Constructor === section.constructor ) {
params.type = type;
return true;
}
return false;
} );
}
Container.prototype.initialize.call( section, id, params );
section.id = id;
section.panel = new api.Value();
@ -2507,8 +2520,22 @@
* @param {object} [options.params] - Deprecated wrapper for the above properties.
*/
initialize: function ( id, options ) {
var panel = this;
Container.prototype.initialize.call( panel, id, options );
var panel = this, params;
params = options.params || options;
// Look up the type if one was not supplied.
if ( ! params.type ) {
_.find( api.panelConstructor, function( Constructor, type ) {
if ( Constructor === panel.constructor ) {
params.type = type;
return true;
}
return false;
} );
}
Container.prototype.initialize.call( panel, id, params );
panel.embed();
panel.deferred.embedded.done( function () {
panel.ready();
@ -3095,7 +3122,7 @@
* @param {string} [options.active=true] - Whether the control is active.
* @param {string} options.section - The ID of the section the control belongs to.
* @param {mixed} [options.setting] - The ID of the main setting or an instance of this setting.
* @param {mixed} options.settings - An object with keys (e.g. default) that maps to setting IDs or Setting/Value objects, or an array of setting IDs or Setting/Value objects.
* @param {mixed} options.settings - An object with keys (e.g. default) that maps to setting IDs or Setting/Value objects, or an array of setting IDs or Setting/Value objects.
* @param {mixed} options.settings.default - The ID of the setting the control relates to.
* @param {string} options.settings.data - @todo Is this used?
* @param {string} options.label - Label.
@ -3107,6 +3134,8 @@
defaultActiveArguments: { duration: 'fast', completeCallback: $.noop },
defaults: {
label: '',
description: '',
active: true,
priority: 10
},

File diff suppressed because one or more lines are too long

View File

@ -811,6 +811,18 @@
panel.container.find( '.hide-column-tog' ).click( function() {
panel.saveManageColumnsState();
});
// Wait until after construction to patch the UI
_.defer( function () {
panel.contentContainer.find( '#accordion-section-menu_locations' ).prepend(
wp.template( 'nav-menu-locations-header' )( api.Menus.data )
);
panel.contentContainer.find( '#accordion-section-add_menu .accordion-section-title' ).replaceWith(
wp.template( 'nav-menu-create-menu-section-title' )
);
} );
},
/**
@ -961,7 +973,16 @@
},
populateControls: function() {
var section = this, menuNameControlId, menuAutoAddControlId, menuControl, menuNameControl, menuAutoAddControl;
var section = this,
menuNameControlId,
menuLocationsControlId,
menuAutoAddControlId,
menuDeleteControlId,
menuControl,
menuNameControl,
menuLocationsControl,
menuAutoAddControl,
menuDeleteControl;
// Add the control for managing the menu name.
menuNameControlId = section.id + '[name]';
@ -996,6 +1017,22 @@
menuControl.active.set( true );
}
// Add the menu locations control.
menuLocationsControlId = section.id + '[locations]';
menuLocationsControl = api.control( menuLocationsControlId );
if ( ! menuLocationsControl ) {
menuLocationsControl = new api.controlConstructor.nav_menu_locations( menuLocationsControlId, {
section: section.id,
priority: 999,
settings: {
'default': section.id
},
menu_id: section.params.menu_id
} );
api.control.add( menuLocationsControl.id, menuLocationsControl );
menuControl.active.set( true );
}
// Add the control for managing the menu auto_add.
menuAutoAddControlId = section.id + '[auto_add]';
menuAutoAddControl = api.control( menuAutoAddControlId );
@ -1004,7 +1041,7 @@
type: 'nav_menu_auto_add',
label: '',
section: section.id,
priority: 999,
priority: 1000,
settings: {
'default': section.id
}
@ -1013,6 +1050,25 @@
menuAutoAddControl.active.set( true );
}
// Add the control for deleting the menu
menuDeleteControlId = section.id + '[delete]';
menuDeleteControl = api.control( menuDeleteControlId );
if ( ! menuDeleteControl ) {
menuDeleteControl = new api.Control( menuDeleteControlId, {
section: section.id,
priority: 1001,
templateId: 'nav-menu-delete-button'
} );
api.control.add( menuDeleteControl.id, menuDeleteControl );
menuDeleteControl.active.set( true );
menuDeleteControl.deferred.embedded.done( function () {
menuDeleteControl.container.find( 'button' ).on( 'click', function() {
var menuId = section.params.menu_id;
var menuControl = api.Menus.getMenuControl( menuId );
menuControl.setting.set( false );
});
} );
}
},
/**
@ -1093,7 +1149,6 @@
* wp.customize.Menus.NewMenuSection
*
* Customizer section for new menus.
* Note that 'new_menu' must match the WP_Customize_New_Menu_Section::$type.
*
* @constructor
* @augments wp.customize.Section
@ -1106,51 +1161,164 @@
* @since 4.3.0
*/
attachEvents: function() {
var section = this;
this.container.on( 'click', '.add-menu-toggle', function() {
if ( section.expanded() ) {
section.collapse();
} else {
section.expand();
}
var section = this,
container = section.container,
contentContainer = section.contentContainer;
/*
* We have to manually handle section expanded because we do not
* apply the `accordion-section-title` class to this button-driven section.
*/
container.on( 'click', '.customize-add-menu-button', function() {
section.expand();
});
contentContainer.on( 'keydown', '.menu-name-field', function( event ) {
if ( 13 === event.which ) { // Enter.
section.submit();
}
} );
contentContainer.on( 'click', '#customize-new-menu-submit', function( event ) {
section.submit();
event.stopPropagation();
event.preventDefault();
} );
api.Section.prototype.attachEvents.apply( this, arguments );
},
/**
* Update UI to reflect expanded state.
* Set up the control.
*
* @since 4.1.0
*
* @param {Boolean} expanded
* @since 4.9.0
*/
onChangeExpanded: function( expanded ) {
ready: function() {
this.populateControls();
},
/**
* Create the controls for this section.
*
* @since 4.9.0
*/
populateControls: function() {
var section = this,
button = section.container.find( '.add-menu-toggle' ),
content = section.contentContainer,
customizer = section.headContainer.closest( '.wp-full-overlay-sidebar-content' );
if ( expanded ) {
button.addClass( 'open' );
button.attr( 'aria-expanded', 'true' );
content.slideDown( 'fast', function() {
customizer.scrollTop( customizer.height() );
});
} else {
button.removeClass( 'open' );
button.attr( 'aria-expanded', 'false' );
content.slideUp( 'fast' );
content.find( '.menu-name-field' ).removeClass( 'invalid' );
menuNameControlId,
menuLocationsControlId,
newMenuSubmitControlId,
menuNameControl,
menuLocationsControl,
newMenuSubmitControl;
menuNameControlId = section.id + '[name]';
menuNameControl = api.control( menuNameControlId );
if ( ! menuNameControl ) {
menuNameControl = new api.controlConstructor.nav_menu_name( menuNameControlId, {
label: api.Menus.data.l10n.menuNameLabel,
description: api.Menus.data.l10n.newMenuNameDescription,
section: section.id,
priority: 0
} );
api.control.add( menuNameControl.id, menuNameControl );
menuNameControl.active.set( true );
}
menuLocationsControlId = section.id + '[locations]';
menuLocationsControl = api.control( menuLocationsControlId );
if ( ! menuLocationsControl ) {
menuLocationsControl = new api.controlConstructor.nav_menu_locations( menuLocationsControlId, {
section: section.id,
priority: 1,
menu_id: ''
} );
api.control.add( menuLocationsControlId, menuLocationsControl );
menuLocationsControl.active.set( true );
}
newMenuSubmitControlId = section.id + '[submit]';
newMenuSubmitControl = api.control( newMenuSubmitControlId );
if ( !newMenuSubmitControl ) {
newMenuSubmitControl = new api.Control( newMenuSubmitControlId, {
section: section.id,
priority: 1,
templateId: 'nav-menu-submit-new-button'
} );
api.control.add( newMenuSubmitControlId, newMenuSubmitControl );
newMenuSubmitControl.active.set( true );
}
},
/**
* Find the content element.
* Create the new menu with name and location supplied by the user.
*
* @since 4.7.0
*
* @returns {jQuery} Content UL element.
* @since 4.9.0
*/
getContent: function() {
return this.container.find( 'ul:first' );
submit: function() {
var section = this,
contentContainer = section.contentContainer,
nameInput = contentContainer.find( '.menu-name-field' ).first(),
name = nameInput.val(),
menuSection,
customizeId,
placeholderId = api.Menus.generatePlaceholderAutoIncrementId();
if ( ! name ) {
nameInput.addClass( 'invalid' );
nameInput.focus();
return;
}
customizeId = 'nav_menu[' + String( placeholderId ) + ']';
// Register the menu control setting.
api.create( customizeId, customizeId, {}, {
type: 'nav_menu',
transport: api.Menus.data.settingTransport,
previewer: api.previewer
} );
api( customizeId ).set( $.extend(
{},
api.Menus.data.defaultSettingValues.nav_menu,
{
name: name
}
) );
/*
* Add the menu section (and its controls).
* Note that this will automatically create the required controls
* inside via the Section's ready method.
*/
menuSection = new api.Menus.MenuSection( customizeId, {
panel: 'nav_menus',
title: displayNavMenuName( name ),
customizeAction: api.Menus.data.l10n.customizingMenus,
priority: 10,
menu_id: placeholderId
} );
api.section.add( customizeId, menuSection );
// Clear name field.
nameInput.val( '' );
nameInput.removeClass( 'invalid' );
contentContainer.find( '.assigned-menu-location input[type=checkbox]' ).each( function() {
var checkbox = $( this ),
navMenuLocationSetting;
if ( checkbox.prop( 'checked' ) ) {
navMenuLocationSetting = api( 'nav_menu_locations[' + checkbox.data( 'location-id' ) + ']' );
navMenuLocationSetting.set( placeholderId );
// Reset state for next new menu
checkbox.prop( 'checked', false );
}
} );
wp.a11y.speak( api.Menus.data.l10n.menuAdded );
// Focus on the new menu section.
api.section( customizeId ).focus(); // @todo should we focus on the new menu's control and open the add-items panel? Thinking user flow...
}
});
@ -1512,6 +1680,8 @@
wp.a11y.speak( api.Menus.data.l10n.itemDeleted );
$adjacentFocusTarget.focus(); // keyboard accessibility
} );
control.setting.set( false );
} );
},
@ -2034,45 +2204,88 @@
api.Menus.MenuNameControl = api.Control.extend({
ready: function() {
var control = this,
settingValue = control.setting();
var control = this;
/*
* Since the control is not registered in PHP, we need to prevent the
* preview's sending of the activeControls to result in this control
* being deactivated.
*/
control.active.validate = function() {
var value, section = api.section( control.section() );
if ( section ) {
value = section.active();
} else {
value = false;
}
return value;
};
control.nameElement = new api.Element( control.container.find( '.menu-name-field' ) );
control.nameElement.bind(function( value ) {
if ( control.setting ) {
var settingValue = control.setting();
if ( settingValue && settingValue.name !== value ) {
settingValue = _.clone( settingValue );
settingValue.name = value;
control.setting.set( settingValue );
}
});
if ( settingValue ) {
control.nameElement.set( settingValue.name );
}
control.setting.bind(function( object ) {
if ( object ) {
control.nameElement.set( object.name );
control.nameElement = new api.Element( control.container.find( '.menu-name-field' ) );
control.nameElement.bind(function( value ) {
var settingValue = control.setting();
if ( settingValue && settingValue.name !== value ) {
settingValue = _.clone( settingValue );
settingValue.name = value;
control.setting.set( settingValue );
}
});
if ( settingValue ) {
control.nameElement.set( settingValue.name );
}
control.setting.bind(function( object ) {
if ( object ) {
control.nameElement.set( object.name );
}
});
}
}
});
/**
* wp.customize.Menus.MenuLocationsControl
*
* Customizer control for a nav menu's locations.
*
* @since 4.9.0
* @constructor
* @augments wp.customize.Control
*/
api.Menus.MenuLocationsControl = api.Control.extend({
/**
* Set up the control.
*
* @since 4.9.0
*/
ready: function () {
var control = this;
control.container.find( '.assigned-menu-location' ).each(function() {
var container = $( this ),
checkbox = container.find( 'input[type=checkbox]' ),
element = new api.Element( checkbox ),
navMenuLocationSetting = api( 'nav_menu_locations[' + checkbox.data( 'location-id' ) + ']' ),
isNewMenu = control.params.menu_id === '',
updateCheckbox = isNewMenu ? _.noop : function( checked ) {
element.set( checked );
},
updateSetting = isNewMenu ? _.noop : function( checked ) {
navMenuLocationSetting.set( checked ? control.params.menu_id : 0 );
},
updateSelectedMenuLabel = function( selectedMenuId ) {
var menuSetting = api( 'nav_menu[' + String( selectedMenuId ) + ']' );
if ( ! selectedMenuId || ! menuSetting || ! menuSetting() ) {
container.find( '.theme-location-set' ).hide();
} else {
container.find( '.theme-location-set' ).show().find( 'span' ).text( displayNavMenuName( menuSetting().name ) );
}
};
updateCheckbox( navMenuLocationSetting.get() === control.params.menu_id );
checkbox.on( 'change', function() {
// Note: We can't use element.bind( function( checked ){ ... } ) here because it will trigger a change as well.
updateSetting( this.checked );
} );
navMenuLocationSetting.bind( function( selectedMenuId ) {
updateCheckbox( selectedMenuId === control.params.menu_id );
updateSelectedMenuLabel( selectedMenuId );
} );
updateSelectedMenuLabel( navMenuLocationSetting.get() );
});
}
});
/**
@ -2180,7 +2393,6 @@
} );
this._setupAddition();
this._setupLocations();
this._setupTitle();
// Add menu to Custom Menu widgets.
@ -2210,6 +2422,15 @@
select.append( new Option( name, menuId ) );
}
}
/*
* Wait for menu items to be added.
* Ideally, we'd bind to an event indicating construction is complete,
* but deferring appears to be the best option today.
*/
_.defer( function () {
control.updateInvitationVisibility();
} );
},
/**
@ -2235,11 +2456,6 @@
});
}
} );
control.container.find( '.menu-delete-item .button-link-delete' ).on( 'click', function( event ) {
event.preventDefault();
control.setting.set( false );
});
},
/**
@ -2393,43 +2609,6 @@
widgetTemplate.find( 'option[value=' + String( menuId ) + ']' ).remove();
},
// Setup theme location checkboxes.
_setupLocations: function() {
var control = this;
control.container.find( '.assigned-menu-location' ).each(function() {
var container = $( this ),
checkbox = container.find( 'input[type=checkbox]' ),
element,
updateSelectedMenuLabel,
navMenuLocationSetting = api( 'nav_menu_locations[' + checkbox.data( 'location-id' ) + ']' );
updateSelectedMenuLabel = function( selectedMenuId ) {
var menuSetting = api( 'nav_menu[' + String( selectedMenuId ) + ']' );
if ( ! selectedMenuId || ! menuSetting || ! menuSetting() ) {
container.find( '.theme-location-set' ).hide();
} else {
container.find( '.theme-location-set' ).show().find( 'span' ).text( displayNavMenuName( menuSetting().name ) );
}
};
element = new api.Element( checkbox );
element.set( navMenuLocationSetting.get() === control.params.menu_id );
checkbox.on( 'change', function() {
// Note: We can't use element.bind( function( checked ){ ... } ) here because it will trigger a change as well.
navMenuLocationSetting.set( this.checked ? control.params.menu_id : 0 );
} );
navMenuLocationSetting.bind(function( selectedMenuId ) {
element.set( selectedMenuId === control.params.menu_id );
updateSelectedMenuLabel( selectedMenuId );
});
updateSelectedMenuLabel( navMenuLocationSetting.get() );
});
},
/**
* Update Section Title as menu name is changed.
*/
@ -2607,6 +2786,7 @@
currentAbsolutePosition: 0
} );
menuControl.updateInvitationVisibility( menuItemControls );
menuControl.container.find( '.reorder-toggle' ).toggle( menuItemControls.length > 1 );
},
@ -2681,103 +2861,22 @@
wp.a11y.speak( api.Menus.data.l10n.itemAdded );
return menuItemControl;
},
/**
* Show an invitation to add new menu items when there are no menu items.
*
* @since 4.9.0
*
* @param {wp.customize.controlConstructor.nav_menu_item[]} optionalMenuItemControls
*/
updateInvitationVisibility: function ( optionalMenuItemControls ) {
var menuItemControls = optionalMenuItemControls || this.getMenuItemControls();
this.container.find( '.new-menu-item-invitation' ).toggle( menuItemControls.length === 0 );
}
} );
/**
* wp.customize.Menus.NewMenuControl
*
* Customizer control for creating new menus and handling deletion of existing menus.
* Note that 'new_menu' must match the WP_Customize_New_Menu_Control::$type.
*
* @constructor
* @augments wp.customize.Control
*/
api.Menus.NewMenuControl = api.Control.extend({
/**
* Set up the control.
*/
ready: function() {
this._bindHandlers();
},
_bindHandlers: function() {
var self = this,
name = $( '#customize-control-new_menu_name input' ),
submit = $( '#create-new-menu-submit' );
name.on( 'keydown', function( event ) {
if ( 13 === event.which ) { // Enter.
self.submit();
}
} );
submit.on( 'click', function( event ) {
self.submit();
event.stopPropagation();
event.preventDefault();
} );
},
/**
* Create the new menu with the name supplied.
*/
submit: function() {
var control = this,
container = control.container.closest( '.accordion-section-new-menu' ),
nameInput = container.find( '.menu-name-field' ).first(),
name = nameInput.val(),
menuSection,
customizeId,
placeholderId = api.Menus.generatePlaceholderAutoIncrementId();
if ( ! name ) {
nameInput.addClass( 'invalid' );
nameInput.focus();
return;
}
customizeId = 'nav_menu[' + String( placeholderId ) + ']';
// Register the menu control setting.
api.create( customizeId, customizeId, {}, {
type: 'nav_menu',
transport: api.Menus.data.settingTransport,
previewer: api.previewer
} );
api( customizeId ).set( $.extend(
{},
api.Menus.data.defaultSettingValues.nav_menu,
{
name: name
}
) );
/*
* Add the menu section (and its controls).
* Note that this will automatically create the required controls
* inside via the Section's ready method.
*/
menuSection = new api.Menus.MenuSection( customizeId, {
panel: 'nav_menus',
title: displayNavMenuName( name ),
customizeAction: api.Menus.data.l10n.customizingMenus,
type: 'nav_menu',
priority: 10,
menu_id: placeholderId
} );
api.section.add( menuSection );
// Clear name field.
nameInput.val( '' );
nameInput.removeClass( 'invalid' );
wp.a11y.speak( api.Menus.data.l10n.menuAdded );
// Focus on the new menu section.
api.section( customizeId ).focus(); // @todo should we focus on the new menu's control and open the add-items panel? Thinking user flow...
}
});
/**
* Extends wp.customize.controlConstructor with control constructor for
* menu_location, menu_item, nav_menu, and new_menu.
@ -2787,8 +2886,8 @@
nav_menu_item: api.Menus.MenuItemControl,
nav_menu: api.Menus.MenuControl,
nav_menu_name: api.Menus.MenuNameControl,
nav_menu_auto_add: api.Menus.MenuAutoAddControl,
new_menu: api.Menus.NewMenuControl
nav_menu_locations: api.Menus.MenuLocationsControl,
nav_menu_auto_add: api.Menus.MenuAutoAddControl
});
/**

File diff suppressed because one or more lines are too long

View File

@ -769,16 +769,16 @@ require_once( ABSPATH . WPINC . '/customize/class-wp-customize-nav-menu-location
*/
require_once( ABSPATH . WPINC . '/customize/class-wp-customize-nav-menu-name-control.php' );
/**
* WP_Customize_Nav_Menu_Locations_Control class.
*/
require_once( ABSPATH . WPINC . '/customize/class-wp-customize-nav-menu-locations-control.php' );
/**
* WP_Customize_Nav_Menu_Auto_Add_Control class.
*/
require_once( ABSPATH . WPINC . '/customize/class-wp-customize-nav-menu-auto-add-control.php' );
/**
* WP_Customize_New_Menu_Control class.
*/
require_once( ABSPATH . WPINC . '/customize/class-wp-customize-new-menu-control.php' );
/**
* WP_Customize_Date_Time_Control class.
*/

View File

@ -315,8 +315,8 @@ final class WP_Customize_Manager {
require_once( ABSPATH . WPINC . '/customize/class-wp-customize-nav-menu-item-control.php' );
require_once( ABSPATH . WPINC . '/customize/class-wp-customize-nav-menu-location-control.php' );
require_once( ABSPATH . WPINC . '/customize/class-wp-customize-nav-menu-name-control.php' );
require_once( ABSPATH . WPINC . '/customize/class-wp-customize-nav-menu-locations-control.php' );
require_once( ABSPATH . WPINC . '/customize/class-wp-customize-nav-menu-auto-add-control.php' );
require_once( ABSPATH . WPINC . '/customize/class-wp-customize-new-menu-control.php' );
require_once( ABSPATH . WPINC . '/customize/class-wp-customize-nav-menus-panel.php' );
@ -324,7 +324,6 @@ final class WP_Customize_Manager {
require_once( ABSPATH . WPINC . '/customize/class-wp-customize-themes-section.php' );
require_once( ABSPATH . WPINC . '/customize/class-wp-customize-sidebar-section.php' );
require_once( ABSPATH . WPINC . '/customize/class-wp-customize-nav-menu-section.php' );
require_once( ABSPATH . WPINC . '/customize/class-wp-customize-new-menu-section.php' );
require_once( ABSPATH . WPINC . '/customize/class-wp-customize-custom-css-setting.php' );
require_once( ABSPATH . WPINC . '/customize/class-wp-customize-filter-setting.php' );

View File

@ -395,39 +395,49 @@ final class WP_Customize_Nav_Menus {
$temp_nav_menu_setting = new WP_Customize_Nav_Menu_Setting( $this->manager, 'nav_menu[-1]' );
$temp_nav_menu_item_setting = new WP_Customize_Nav_Menu_Item_Setting( $this->manager, 'nav_menu_item[-1]' );
$num_locations = count( get_registered_nav_menus() );
if ( 1 === $num_locations ) {
$locations_description = __( 'Your theme can display menus in one location.' );
} else {
/* translators: %s: number of menu locations */
$locations_description = sprintf( _n( 'Your theme can display menus in %s location.', 'Your theme can display menus in %s locations.', $num_locations ), number_format_i18n( $num_locations ) );
}
// Pass data to JS.
$settings = array(
'allMenus' => wp_get_nav_menus(),
'itemTypes' => $this->available_item_types(),
'l10n' => array(
'untitled' => _x( '(no label)', 'missing menu item navigation label' ),
'unnamed' => _x( '(unnamed)', 'Missing menu name.' ),
'custom_label' => __( 'Custom Link' ),
'page_label' => get_post_type_object( 'page' )->labels->singular_name,
/* translators: %s: menu location */
'menuLocation' => _x( '(Currently set to: %s)', 'menu' ),
'menuNameLabel' => __( 'Menu Name' ),
'itemAdded' => __( 'Menu item added' ),
'itemDeleted' => __( 'Menu item deleted' ),
'menuAdded' => __( 'Menu created' ),
'menuDeleted' => __( 'Menu deleted' ),
'movedUp' => __( 'Menu item moved up' ),
'movedDown' => __( 'Menu item moved down' ),
'movedLeft' => __( 'Menu item moved out of submenu' ),
'movedRight' => __( 'Menu item is now a sub-item' ),
'untitled' => _x( '(no label)', 'missing menu item navigation label' ),
'unnamed' => _x( '(unnamed)', 'Missing menu name.' ),
'custom_label' => __( 'Custom Link' ),
'page_label' => get_post_type_object( 'page' )->labels->singular_name,
/* translators: %s: menu location */
'menuLocation' => _x( '(Currently set to: %s)', 'menu' ),
'locationsDescription' => $locations_description,
'menuNameLabel' => __( 'Menu Name' ),
'newMenuNameDescription' => __( 'If your theme has multiple menus, giving them clear names will help you manage them.' ),
'itemAdded' => __( 'Menu item added' ),
'itemDeleted' => __( 'Menu item deleted' ),
'menuAdded' => __( 'Menu created' ),
'menuDeleted' => __( 'Menu deleted' ),
'movedUp' => __( 'Menu item moved up' ),
'movedDown' => __( 'Menu item moved down' ),
'movedLeft' => __( 'Menu item moved out of submenu' ),
'movedRight' => __( 'Menu item is now a sub-item' ),
/* translators: ▸ is the unicode right-pointing triangle, and %s is the section title in the Customizer */
'customizingMenus' => sprintf( __( 'Customizing ▸ %s' ), esc_html( $this->manager->get_panel( 'nav_menus' )->title ) ),
'customizingMenus' => sprintf( __( 'Customizing ▸ %s' ), esc_html( $this->manager->get_panel( 'nav_menus' )->title ) ),
/* translators: %s: title of menu item which is invalid */
'invalidTitleTpl' => __( '%s (Invalid)' ),
'invalidTitleTpl' => __( '%s (Invalid)' ),
/* translators: %s: title of menu item in draft status */
'pendingTitleTpl' => __( '%s (Pending)' ),
'itemsFound' => __( 'Number of items found: %d' ),
'itemsFoundMore' => __( 'Additional items found: %d' ),
'itemsLoadingMore' => __( 'Loading more results... please wait.' ),
'reorderModeOn' => __( 'Reorder mode enabled' ),
'reorderModeOff' => __( 'Reorder mode closed' ),
'reorderLabelOn' => esc_attr__( 'Reorder menu items' ),
'reorderLabelOff' => esc_attr__( 'Close reorder mode' ),
'pendingTitleTpl' => __( '%s (Pending)' ),
'itemsFound' => __( 'Number of items found: %d' ),
'itemsFoundMore' => __( 'Additional items found: %d' ),
'itemsLoadingMore' => __( 'Loading more results... please wait.' ),
'reorderModeOn' => __( 'Reorder mode enabled' ),
'reorderModeOff' => __( 'Reorder mode closed' ),
'reorderLabelOn' => esc_attr__( 'Reorder menu items' ),
'reorderLabelOff' => esc_attr__( 'Close reorder mode' ),
),
'settingTransport' => 'postMessage',
'phpIntMax' => PHP_INT_MAX,
@ -537,6 +547,7 @@ final class WP_Customize_Nav_Menus {
$this->manager->register_panel_type( 'WP_Customize_Nav_Menus_Panel' );
$this->manager->register_control_type( 'WP_Customize_Nav_Menu_Control' );
$this->manager->register_control_type( 'WP_Customize_Nav_Menu_Name_Control' );
$this->manager->register_control_type( 'WP_Customize_Nav_Menu_Locations_Control' );
$this->manager->register_control_type( 'WP_Customize_Nav_Menu_Auto_Add_Control' );
$this->manager->register_control_type( 'WP_Customize_Nav_Menu_Item_Control' );
@ -558,23 +569,24 @@ final class WP_Customize_Nav_Menus {
// Menu locations.
$locations = get_registered_nav_menus();
$num_locations = count( array_keys( $locations ) );
$num_locations = count( $locations );
if ( 1 == $num_locations ) {
$description = '<p>' . __( 'Your theme supports one menu. Select which menu you would like to use.' ) . '</p>';
$description = '<p>' . __( 'Your theme can display menus in one location. Select which menu you would like to use.' ) . '</p>';
} else {
/* translators: %s: number of menu locations */
$description = '<p>' . sprintf( _n( 'Your theme supports %s menu. Select which menu appears in each location.', 'Your theme supports %s menus. Select which menu appears in each location.', $num_locations ), number_format_i18n( $num_locations ) ) . '</p>';
$description = '<p>' . sprintf( _n( 'Your theme can display menus in %s location. Select which menu you would like to use.', 'Your theme can display menus in %s locations. Select which menu appears in each location.', $num_locations ), number_format_i18n( $num_locations ) ) . '</p>';
}
if ( current_theme_supports( 'widgets' ) ) {
/* translators: URL to the widgets panel of the customizer */
$description .= '<p>' . sprintf( __( 'You can also place menus in <a href="%s">widget areas</a> with the &#8220;Custom Menu&#8221; widget.' ), "javascript:wp.customize.panel( 'widgets' ).focus();" ) . '</p>';
$description .= '<p>' . sprintf( __( 'If your theme has widget areas, you can also add menus there. Visit the <a href="%s">Widgets panel</a> and add a &#8220;Custom Menu widget&#8221; to display a menu in a sidebar or footer.' ), "javascript:wp.customize.panel( 'widgets' ).focus();" ) . '</p>';
}
$this->manager->add_section( 'menu_locations', array(
'title' => __( 'Menu Locations' ),
'panel' => 'nav_menus',
'priority' => 5,
'description' => $description,
'title' => __( 'View All Locations' ),
'panel' => 'nav_menus',
'priority' => 30,
'description' => $description
) );
$choices = array( '0' => __( '&mdash; Select &mdash;' ) );
@ -667,27 +679,13 @@ final class WP_Customize_Nav_Menus {
}
// Add the add-new-menu section and controls.
$this->manager->add_section( new WP_Customize_New_Menu_Section( $this->manager, 'add_menu', array(
'title' => __( 'Add a Menu' ),
$this->manager->add_section( 'add_menu', array(
'type' => 'new_menu',
'title' => __( 'New Menu' ),
'panel' => 'nav_menus',
'priority' => 999,
) ) );
$this->manager->add_control( 'new_menu_name', array(
'label' => __( 'New menu name' ),
'section' => 'add_menu',
'type' => 'text',
'settings' => array(),
'input_attrs' => array(
'class' => 'menu-name-field',
),
'priority' => 20,
) );
$this->manager->add_control( new WP_Customize_New_Menu_Control( $this->manager, 'create_new_menu', array(
'section' => 'add_menu',
'settings' => array(),
) ) );
$this->manager->add_setting( new WP_Customize_Filter_Setting( $this->manager, 'nav_menus_created_posts', array(
'transport' => 'postMessage',
'type' => 'option', // To prevent theme prefix in changeset.
@ -925,6 +923,32 @@ final class WP_Customize_Nav_Menus {
?>
</div>
</script>
<script type="text/html" id="tmpl-nav-menu-delete-button">
<div class="menu-delete-item">
<button type="button" class="button-link button-link-delete">
<?php _e( 'Delete Menu' ); ?>
</button>
</div>
</script>
<script type="text/html" id="tmpl-nav-menu-submit-new-button">
<p id="customize-new-menu-submit-description"><?php _e( 'Click "next" to start adding links to your new menu.' ); ?></p>
<button id="customize-new-menu-submit" type="button" class="button" aria-describedby="customize-new-menu-submit-description"><?php _e( 'Next' ); ?></button>
</script>
<script type="text/html" id="tmpl-nav-menu-locations-header">
<span class="customize-control-title customize-section-title-menu_locations-heading"><?php _e( 'Menu Locations' ); ?></span>
<p class="customize-control-description customize-section-title-menu_locations-description">{{ data.l10n.locationsDescription }}</p>
</script>
<script type="text/html" id="tmpl-nav-menu-create-menu-section-title">
<h3>
<button type="button" class="button customize-add-menu-button">
<?php _e( 'Create New Menu' ); ?>
</button>
</h3>
</script>
<?php
}

View File

@ -385,6 +385,3 @@ require_once( ABSPATH . WPINC . '/customize/class-wp-customize-sidebar-section.p
/** WP_Customize_Nav_Menu_Section class */
require_once( ABSPATH . WPINC . '/customize/class-wp-customize-nav-menu-section.php' );
/** WP_Customize_New_Menu_Section class */
require_once( ABSPATH . WPINC . '/customize/class-wp-customize-new-menu-section.php' );

View File

@ -38,11 +38,14 @@ class WP_Customize_Nav_Menu_Auto_Add_Control extends WP_Customize_Control {
*/
protected function content_template() {
?>
<# var elementId = _.uniqueId( 'customize-nav-menu-auto-add-control-' ); #>
<span class="customize-control-title"><?php _e( 'Menu Options' ); ?></span>
<label>
<input type="checkbox" class="auto_add" />
<?php _e( 'Automatically add new top-level pages to this menu' ); ?>
</label>
<span class="customize-inside-control-row">
<input id="{{ elementId }}" type="checkbox" class="auto_add" />
<label for="{{ elementId }}">
<?php _e( 'Automatically add new top-level pages to this menu' ); ?>
</label>
</span>
<?php
}
}

View File

@ -22,14 +22,6 @@ class WP_Customize_Nav_Menu_Control extends WP_Customize_Control {
*/
public $type = 'nav_menu';
/**
* The nav menu setting.
*
* @since 4.3.0
* @var WP_Customize_Nav_Menu_Setting
*/
public $setting;
/**
* Don't render the control's content - it uses a JS template instead.
*
@ -44,45 +36,17 @@ class WP_Customize_Nav_Menu_Control extends WP_Customize_Control {
*/
public function content_template() {
?>
<# var elementId; #>
<button type="button" class="button add-new-menu-item" aria-label="<?php esc_attr_e( 'Add or remove menu items' ); ?>" aria-expanded="false" aria-controls="available-menu-items">
<?php _e( 'Add Items' ); ?>
</button>
<button type="button" class="button-link reorder-toggle" aria-label="<?php esc_attr_e( 'Reorder menu items' ); ?>" aria-describedby="reorder-items-desc-{{ data.menu_id }}">
<span class="reorder"><?php _e( 'Reorder' ); ?></span>
<span class="reorder-done"><?php _e( 'Done' ); ?></span>
</button>
<p class="screen-reader-text" id="reorder-items-desc-{{ data.menu_id }}"><?php _e( 'When in reorder mode, additional controls to reorder menu items will be available in the items list above.' ); ?></p>
<span class="menu-delete-item">
<button type="button" class="button-link button-link-delete">
<?php _e( 'Delete Menu' ); ?>
<p class="new-menu-item-invitation"><?php _e( 'Time to add some links! Click "Add menu items" to start putting pages, categories, and custom links in your menu. Add as many things as you\'d like.' ); ?></p>
<div class="customize-control-nav_menu-buttons">
<button type="button" class="button add-new-menu-item" aria-label="<?php esc_attr_e( 'Add or remove menu items' ); ?>" aria-expanded="false" aria-controls="available-menu-items">
<?php _e( 'Add Items' ); ?>
</button>
</span>
<?php if ( current_theme_supports( 'menus' ) ) : ?>
<ul class="menu-settings">
<li class="customize-control">
<span class="customize-control-title"><?php _e( 'Display Location' ); ?></span>
</li>
<?php foreach ( get_registered_nav_menus() as $location => $description ) : ?>
<# elementId = _.uniqueId( 'customize-nav-menu-control-location-' ); #>
<li class="customize-control customize-control-checkbox assigned-menu-location customize-inside-control-row">
<input id="{{ elementId }}" type="checkbox" data-menu-id="{{ data.menu_id }}" data-location-id="<?php echo esc_attr( $location ); ?>" class="menu-location" />
<label for="{{ elementId }}">
<?php echo $description; ?>
<span class="theme-location-set">
<?php
/* translators: %s: menu name */
printf( _x( '(Current: %s)', 'menu location' ),
'<span class="current-menu-location-name-' . esc_attr( $location ) . '"></span>'
);
?>
</span>
</label>
</li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
<button type="button" class="button-link reorder-toggle" aria-label="<?php esc_attr_e( 'Reorder menu items' ); ?>" aria-describedby="reorder-items-desc-{{ data.menu_id }}">
<span class="reorder"><?php _e( 'Reorder' ); ?></span>
<span class="reorder-done"><?php _e( 'Done' ); ?></span>
</button>
</div>
<p class="screen-reader-text" id="reorder-items-desc-{{ data.menu_id }}"><?php _e( 'When in reorder mode, additional controls to reorder menu items will be available in the items list above.' ); ?></p>
<?php
}

View File

@ -0,0 +1,70 @@
<?php
/**
* Customize API: WP_Customize_Nav_Menu_Locations_Control class
*
* @package WordPress
* @subpackage Customize
* @since 4.9.0
*/
/**
* Customize Nav Menu Locations Control Class.
*
* @since 4.9.0
*/
class WP_Customize_Nav_Menu_Locations_Control extends WP_Customize_Control {
/**
* Control type.
*
* @since 4.9.0
* @var string
*/
public $type = 'nav_menu_locations';
/**
* Don't render the control's content - it uses a JS template instead.
*
* @since 4.9.0
*/
public function render_content() {}
/**
* JS/Underscore template for the control UI.
*
* @since 4.9.0
*/
public function content_template() {
if ( current_theme_supports( 'menus' ) ):
?>
<# var elementId; #>
<ul class="menu-location-settings">
<li class="customize-control assigned-menu-locations-title">
<span class="customize-control-title"><?php _e( 'Menu Locations' ); ?></span>
<p><?php _e( 'Here\'s where this menu appears. If you\'d like to change that, pick another location.' ); ?></p>
</li>
<?php foreach ( get_registered_nav_menus() as $location => $description ) : ?>
<# elementId = _.uniqueId( 'customize-nav-menu-control-location-' ); #>
<li class="customize-control customize-control-checkbox assigned-menu-location">
<span class="customize-inside-control-row">
<input id="{{ elementId }}" type="checkbox" data-menu-id="{{ data.menu_id }}" data-location-id="<?php echo esc_attr( $location ); ?>" class="menu-location" />
<label for="{{ elementId }}">
<?php echo $description; ?>
<span class="theme-location-set">
<?php
/* translators: %s: menu name */
printf( _x( '(Current: %s)', 'menu location' ),
'<span class="current-menu-location-name-' . esc_attr( $location ) . '"></span>'
);
?>
</span>
</label>
</span>
</li>
<?php endforeach; ?>
</ul>
<?php
endif;
}
}

View File

@ -40,10 +40,17 @@ class WP_Customize_Nav_Menu_Name_Control extends WP_Customize_Control {
?>
<label>
<# if ( data.label ) { #>
<span class="customize-control-title screen-reader-text">{{ data.label }}</span>
<span class="customize-control-title">{{ data.label }}</span>
<# } #>
<input type="text" class="menu-name-field live-update-section-title" />
<input type="text" class="menu-name-field live-update-section-title"
<# if ( data.description ) { #>
aria-describedby="{{ data.section }}-description"
<# } #>
/>
</label>
<# if ( data.description ) { #>
<p id="{{ data.section }}-description">{{ data.description }}</p>
<# } #>
<?php
}
}

View File

@ -92,6 +92,10 @@ class WP_Customize_Nav_Menus_Panel extends WP_Customize_Panel {
<?php $this->render_screen_options(); ?>
</div>
</li>
<?php
// NOTE: The following is a workaround for an inability to treat (and thus label) a list of sections as a whole.
?>
<li class="customize-control-title customize-section-title-nav_menus-heading"><?php _e( 'Menus' ); ?></li>
<?php
}
}

View File

@ -4,7 +4,7 @@
*
* @global string $wp_version
*/
$wp_version = '4.9-alpha-41767';
$wp_version = '4.9-alpha-41768';
/**
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.