Customize: Allow controls to be created with pre-instantiated `Setting` object(s), or even with plain `Value` object(s).
* Allow passing settings in keyed object (e.g. `settings: { default: 'id' } ), or as an array (e.g. `settings: [ 'id' ]`) with first being default; again, `Setting`/`Value` objects may be supplied instead of IDs. * Allow a single setting to be supplied with just a single `setting` param, either a string or a `Setting`/`Value` object. * Update `changeset_status` and `scheduled_changeset_date` to be added dynamically with JS and simply passing of `api.state()` instances as `setting`. * Introduce a `data-customize-setting-key-link` attribute which, unlike `data-customize-setting-link`, allows passing the setting key (e.g. `default`) as opposed to the setting ID. * Allow `WP_Customize_Control::get_link()` to return `data-customize-setting-key-link` when setting is not registered. * Eliminate `default_value` from `WP_Customize_Date_Time_Control` since now comes from supplied `Value`. * Export status choices as `wp.customize.settings.changeset.statusChoices`. * Export date and time formats as `wp.customize.settings.dateFormat` and `wp.customize.settings.timeFormat` respectively. Props westonruter, sayedwp. See #39896, #30738, #30741, #42083. Fixes #37964, #36167. git-svn-id: https://develop.svn.wordpress.org/trunk@41750 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
parent
11ccab09e0
commit
0cc238c7c7
|
@ -138,7 +138,7 @@ body.trashing #publish-settings {
|
|||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
#customize-control-changeset_status label,
|
||||
#customize-control-changeset_status .customize-inside-control-row,
|
||||
#customize-control-changeset_preview_link input {
|
||||
background-color: #ffffff;
|
||||
border-bottom: 1px solid #ddd;
|
||||
|
@ -170,13 +170,13 @@ body.trashing #publish-settings {
|
|||
border-color: #dc3232;
|
||||
}
|
||||
|
||||
#customize-control-changeset_status label {
|
||||
#customize-control-changeset_status .customize-inside-control-row {
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
#customize-control-changeset_status label:first-of-type {
|
||||
#customize-control-changeset_status .customize-inside-control-row:first-of-type {
|
||||
border-top: 1px solid #ddd;
|
||||
}
|
||||
|
||||
|
@ -2809,7 +2809,7 @@ body.adding-widget .add-new-widget:before,
|
|||
height: 31px;
|
||||
}
|
||||
|
||||
#customize-control-changeset_status label {
|
||||
#customize-control-changeset_status .customize-inside-control-row {
|
||||
padding-top: 15px;
|
||||
}
|
||||
|
||||
|
|
|
@ -3094,8 +3094,10 @@
|
|||
* @param {string} [options.priority=10] - Order of priority to show the control within the section.
|
||||
* @param {string} [options.active=true] - Whether the control is active.
|
||||
* @param {string} options.section - The ID of the section the control belongs to.
|
||||
* @param {string} options.settings.default - The ID of the setting the control relates to.
|
||||
* @param {string} options.settings.data
|
||||
* @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.default - The ID of the setting the control relates to.
|
||||
* @param {string} options.settings.data - @todo Is this used?
|
||||
* @param {string} options.label - Label.
|
||||
* @param {string} options.description - Description.
|
||||
* @param {number} [options.instanceNumber] - Order in which this instance was created in relation to other instances.
|
||||
|
@ -3110,8 +3112,7 @@
|
|||
},
|
||||
|
||||
initialize: function( id, options ) {
|
||||
var control = this,
|
||||
nodes, radios, settings;
|
||||
var control = this, deferredSettingIds = [], settings, gatherSettings;
|
||||
|
||||
control.params = _.extend( {}, control.defaults );
|
||||
|
||||
|
@ -3123,6 +3124,17 @@
|
|||
control.params.instanceNumber = api.Control.instanceCounter;
|
||||
}
|
||||
|
||||
// Look up the type if one was not supplied.
|
||||
if ( ! control.params.type ) {
|
||||
_.find( api.controlConstructor, function( Constructor, type ) {
|
||||
if ( Constructor === control.constructor ) {
|
||||
control.params.type = type;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} );
|
||||
}
|
||||
|
||||
_.extend( control.params, options.params || options );
|
||||
if ( ! control.params.content ) {
|
||||
control.params.content = $( '<li></li>', {
|
||||
|
@ -3153,31 +3165,6 @@
|
|||
|
||||
control.elements = [];
|
||||
|
||||
nodes = control.container.find('[data-customize-setting-link]');
|
||||
radios = {};
|
||||
|
||||
nodes.each( function() {
|
||||
var node = $( this ),
|
||||
name;
|
||||
|
||||
if ( node.is( ':radio' ) ) {
|
||||
name = node.prop( 'name' );
|
||||
if ( radios[ name ] ) {
|
||||
return;
|
||||
}
|
||||
|
||||
radios[ name ] = true;
|
||||
node = nodes.filter( '[name="' + name + '"]' );
|
||||
}
|
||||
|
||||
api( node.data( 'customizeSettingLink' ), function( setting ) {
|
||||
var element = new api.Element( node );
|
||||
control.elements.push( element );
|
||||
element.sync( setting );
|
||||
element.set( setting() );
|
||||
});
|
||||
});
|
||||
|
||||
control.active.bind( function ( active ) {
|
||||
var args = control.activeArgumentsQueue.shift();
|
||||
args = $.extend( {}, control.defaultActiveArguments, args );
|
||||
|
@ -3190,57 +3177,105 @@
|
|||
|
||||
api.utils.bubbleChildValueChanges( control, [ 'section', 'priority', 'active' ] );
|
||||
|
||||
/*
|
||||
* After all settings related to the control are available,
|
||||
* make them available on the control and embed the control into the page.
|
||||
*/
|
||||
settings = $.map( control.params.settings, function( value ) {
|
||||
return value;
|
||||
});
|
||||
|
||||
if ( 0 === settings.length ) {
|
||||
control.setting = null;
|
||||
control.settings = {};
|
||||
control.embed();
|
||||
|
||||
settings = {};
|
||||
if ( control.params.setting ) {
|
||||
settings['default'] = control.params.setting;
|
||||
}
|
||||
_.extend( settings, control.params.settings );
|
||||
|
||||
// Note: Settings can be an array or an object.
|
||||
_.each( settings, function( setting, key ) {
|
||||
if ( _.isObject( setting ) ) { // @todo Or check if instance of api.Setting?
|
||||
control.settings[ key ] = setting;
|
||||
} else {
|
||||
api.apply( api, settings.concat( function() {
|
||||
var key;
|
||||
deferredSettingIds.push( setting );
|
||||
}
|
||||
} );
|
||||
|
||||
control.settings = {};
|
||||
for ( key in control.params.settings ) {
|
||||
control.settings[ key ] = api( control.params.settings[ key ] );
|
||||
gatherSettings = function() {
|
||||
|
||||
// Fill-in all resolved settings.
|
||||
_.each( settings, function ( settingId, key ) {
|
||||
if ( ! control.settings[ key ] && _.isString( settingId ) ) {
|
||||
control.settings[ key ] = api( settingId );
|
||||
}
|
||||
} );
|
||||
|
||||
// Make sure settings passed as array gets associated with default.
|
||||
if ( control.settings[0] && ! control.settings['default'] ) {
|
||||
control.settings['default'] = control.settings[0];
|
||||
}
|
||||
|
||||
// Identify the main setting.
|
||||
control.setting = control.settings['default'] || null;
|
||||
|
||||
// Add setting notifications to the control notification.
|
||||
_.each( control.settings, function( setting ) {
|
||||
setting.notifications.bind( 'add', function( settingNotification ) {
|
||||
var params = _.extend(
|
||||
{},
|
||||
settingNotification,
|
||||
{
|
||||
setting: setting.id
|
||||
}
|
||||
);
|
||||
control.notifications.add( new api.Notification( setting.id + ':' + settingNotification.code, params ) );
|
||||
} );
|
||||
setting.notifications.bind( 'remove', function( settingNotification ) {
|
||||
control.notifications.remove( setting.id + ':' + settingNotification.code );
|
||||
} );
|
||||
} );
|
||||
|
||||
control.embed();
|
||||
}) );
|
||||
};
|
||||
|
||||
if ( 0 === deferredSettingIds.length ) {
|
||||
gatherSettings();
|
||||
} else {
|
||||
api.apply( api, deferredSettingIds.concat( gatherSettings ) );
|
||||
}
|
||||
|
||||
// After the control is embedded on the page, invoke the "ready" method.
|
||||
control.deferred.embedded.done( function () {
|
||||
control.linkElements();
|
||||
control.setupNotifications();
|
||||
control.ready();
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Link elements between settings and inputs.
|
||||
*
|
||||
* @since 4.7.0
|
||||
* @access public
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
linkElements: function () {
|
||||
var control = this, nodes, radios, element;
|
||||
|
||||
nodes = control.container.find( '[data-customize-setting-link], [data-customize-setting-key-link]' );
|
||||
radios = {};
|
||||
|
||||
nodes.each( function () {
|
||||
var node = $( this ), name, setting;
|
||||
|
||||
if ( node.data( 'customizeSettingLinked' ) ) {
|
||||
return;
|
||||
}
|
||||
node.data( 'customizeSettingLinked', true ); // Prevent re-linking element.
|
||||
|
||||
if ( node.is( ':radio' ) ) {
|
||||
name = node.prop( 'name' );
|
||||
if ( radios[name] ) {
|
||||
return;
|
||||
}
|
||||
|
||||
radios[name] = true;
|
||||
node = nodes.filter( '[name="' + name + '"]' );
|
||||
}
|
||||
|
||||
// Let link by default refer to setting ID. If it doesn't exist, fallback to looking up by setting key.
|
||||
if ( node.data( 'customizeSettingLink' ) ) {
|
||||
setting = api( node.data( 'customizeSettingLink' ) );
|
||||
} else if ( node.data( 'customizeSettingKeyLink' ) ) {
|
||||
setting = control.settings[ node.data( 'customizeSettingKeyLink' ) ];
|
||||
}
|
||||
|
||||
if ( setting ) {
|
||||
element = new api.Element( node );
|
||||
control.elements.push( element );
|
||||
element.sync( setting );
|
||||
element.set( setting() );
|
||||
}
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Embed the control into the page.
|
||||
*/
|
||||
|
@ -3342,6 +3377,26 @@
|
|||
setupNotifications: function() {
|
||||
var control = this, renderNotificationsIfVisible, onSectionAssigned;
|
||||
|
||||
// Add setting notifications to the control notification.
|
||||
_.each( control.settings, function( setting ) {
|
||||
if ( ! setting.notifications ) {
|
||||
return;
|
||||
}
|
||||
setting.notifications.bind( 'add', function( settingNotification ) {
|
||||
var params = _.extend(
|
||||
{},
|
||||
settingNotification,
|
||||
{
|
||||
setting: setting.id
|
||||
}
|
||||
);
|
||||
control.notifications.add( new api.Notification( setting.id + ':' + settingNotification.code, params ) );
|
||||
} );
|
||||
setting.notifications.bind( 'remove', function( settingNotification ) {
|
||||
control.notifications.remove( setting.id + ':' + settingNotification.code );
|
||||
} );
|
||||
} );
|
||||
|
||||
control.notifications.container = control.getNotificationsContainerElement();
|
||||
|
||||
renderNotificationsIfVisible = function() {
|
||||
|
@ -4986,14 +5041,8 @@
|
|||
|
||||
_.bindAll( control, 'populateSetting', 'updateDaysForMonth', 'updateMinutesForHour', 'populateDateInputs' );
|
||||
|
||||
// @todo This needs https://core.trac.wordpress.org/ticket/37964
|
||||
if ( ! control.setting ) {
|
||||
control.setting = new api.Value();
|
||||
}
|
||||
|
||||
// @todo Should this be? Default should be on client. The default value should be in the setting itself.
|
||||
if ( ! control.setting.get() && control.params.defaultValue ) {
|
||||
control.setting.set( control.params.defaultValue );
|
||||
throw new Error( 'Missing setting' );
|
||||
}
|
||||
|
||||
control.container.find( '.date-input' ).each( function() {
|
||||
|
@ -6360,8 +6409,9 @@
|
|||
publishSettingsBtn = $( '#publish-settings' ),
|
||||
footerActions = $( '#customize-footer-actions' );
|
||||
|
||||
// Set up publish settings section and its controls.
|
||||
api.section( 'publish_settings', function( section ) {
|
||||
var updateButtonsState, trashControl, updateSectionActive, isSectionActive;
|
||||
var updateButtonsState, trashControl, updateSectionActive, isSectionActive, statusControl, dateControl, toggleDateControl, publishWhenTime, pollInterval, updateTimeArrivedPoller, timeArrivedPollingInterval = 1000;
|
||||
|
||||
trashControl = new api.Control( 'trash_changeset', {
|
||||
type: 'button',
|
||||
|
@ -6433,6 +6483,84 @@
|
|||
publishSettingsBtn.attr( 'aria-expanded', String( isExpanded ) );
|
||||
publishSettingsBtn.toggleClass( 'active', isExpanded );
|
||||
} );
|
||||
|
||||
statusControl = new api.Control( 'changeset_status', {
|
||||
priority: 10,
|
||||
type: 'radio',
|
||||
section: 'publish_settings',
|
||||
setting: api.state( 'selectedChangesetStatus' ),
|
||||
templateId: 'customize-selected-changeset-status-control',
|
||||
label: api.l10n.action,
|
||||
choices: api.settings.changeset.statusChoices
|
||||
} );
|
||||
api.control.add( statusControl );
|
||||
|
||||
dateControl = new api.DateTimeControl( 'changeset_scheduled_date', {
|
||||
priority: 20,
|
||||
section: 'publish_settings',
|
||||
setting: api.state( 'selectedChangesetDate' ),
|
||||
minYear: ( new Date() ).getFullYear(),
|
||||
allowPastDate: false,
|
||||
includeTime: true,
|
||||
twelveHourFormat: /a/i.test( api.settings.timeFormat ),
|
||||
description: api.l10n.scheduleDescription
|
||||
} );
|
||||
dateControl.notifications.alt = true;
|
||||
api.control.add( dateControl );
|
||||
|
||||
publishWhenTime = function() {
|
||||
api.state( 'selectedChangesetStatus' ).set( 'publish' );
|
||||
api.previewer.save();
|
||||
};
|
||||
|
||||
// Start countdown for when the dateTime arrives, or clear interval when it is .
|
||||
updateTimeArrivedPoller = function() {
|
||||
var shouldPoll = (
|
||||
'future' === api.state( 'changesetStatus' ).get() &&
|
||||
'future' === api.state( 'selectedChangesetStatus' ).get() &&
|
||||
api.state( 'changesetDate' ).get() &&
|
||||
api.state( 'selectedChangesetDate' ).get() === api.state( 'changesetDate' ).get() &&
|
||||
api.utils.getRemainingTime( api.state( 'changesetDate' ).get() ) >= 0
|
||||
);
|
||||
|
||||
if ( shouldPoll && ! pollInterval ) {
|
||||
pollInterval = setInterval( function() {
|
||||
var remainingTime = api.utils.getRemainingTime( api.state( 'changesetDate' ).get() );
|
||||
api.state( 'remainingTimeToPublish' ).set( remainingTime );
|
||||
if ( remainingTime <= 0 ) {
|
||||
clearInterval( pollInterval );
|
||||
pollInterval = 0;
|
||||
publishWhenTime();
|
||||
}
|
||||
}, timeArrivedPollingInterval );
|
||||
} else if ( ! shouldPoll && pollInterval ) {
|
||||
clearInterval( pollInterval );
|
||||
pollInterval = 0;
|
||||
}
|
||||
};
|
||||
|
||||
api.state( 'changesetDate' ).bind( updateTimeArrivedPoller );
|
||||
api.state( 'selectedChangesetDate' ).bind( updateTimeArrivedPoller );
|
||||
api.state( 'changesetStatus' ).bind( updateTimeArrivedPoller );
|
||||
api.state( 'selectedChangesetStatus' ).bind( updateTimeArrivedPoller );
|
||||
updateTimeArrivedPoller();
|
||||
|
||||
// Ensure dateControl only appears when selected status is future.
|
||||
dateControl.active.validate = function() {
|
||||
return 'future' === api.state( 'selectedChangesetStatus' ).get();
|
||||
};
|
||||
toggleDateControl = function( value ) {
|
||||
dateControl.active.set( 'future' === value );
|
||||
};
|
||||
toggleDateControl( api.state( 'selectedChangesetStatus' ).get() );
|
||||
api.state( 'selectedChangesetStatus' ).bind( toggleDateControl );
|
||||
|
||||
// Show notification on date control when status is future but it isn't a future date.
|
||||
api.state( 'saving' ).bind( function( isSaving ) {
|
||||
if ( isSaving && 'future' === api.state( 'selectedChangesetStatus' ).get() ) {
|
||||
dateControl.toggleFutureDateNotification( ! dateControl.isFutureDate() );
|
||||
}
|
||||
} );
|
||||
} );
|
||||
|
||||
// Prevent the form from saving when enter is pressed on an input or select element.
|
||||
|
@ -7062,6 +7190,7 @@
|
|||
// Set default states.
|
||||
changesetStatus( api.settings.changeset.status );
|
||||
changesetDate( api.settings.changeset.publishDate );
|
||||
selectedChangesetDate( api.settings.changeset.publishDate );
|
||||
selectedChangesetStatus( '' === api.settings.changeset.status || 'auto-draft' === api.settings.changeset.status ? 'publish' : api.settings.changeset.status );
|
||||
selectedChangesetStatus.link( changesetStatus ); // Ensure that direct updates to status on server via wp.customizer.previewer.save() will update selection.
|
||||
saved( true );
|
||||
|
@ -7985,80 +8114,6 @@
|
|||
});
|
||||
})();
|
||||
|
||||
// Publish settings section and controls.
|
||||
api.control( 'changeset_status', 'changeset_scheduled_date', function( statusControl, dateControl ) {
|
||||
$.when( statusControl.deferred.embedded, dateControl.deferred.embedded ).done( function() {
|
||||
var radioNodes, statusElement, toggleDateControl, publishWhenTime, pollInterval, updateTimeArrivedPoller, timeArrivedPollingInterval = 1000;
|
||||
|
||||
radioNodes = statusControl.container.find( 'input[type=radio][name]' );
|
||||
statusElement = new api.Element( radioNodes );
|
||||
statusControl.elements.push( statusElement );
|
||||
|
||||
statusElement.sync( api.state( 'selectedChangesetStatus' ) );
|
||||
statusElement.set( api.state( 'selectedChangesetStatus' ).get() );
|
||||
|
||||
dateControl.notifications.alt = true;
|
||||
dateControl.deferred.embedded.done( function() {
|
||||
api.state( 'selectedChangesetDate' ).sync( dateControl.setting );
|
||||
api.state( 'selectedChangesetDate' ).set( dateControl.setting() );
|
||||
} );
|
||||
|
||||
publishWhenTime = function() {
|
||||
api.state( 'selectedChangesetStatus' ).set( 'publish' );
|
||||
api.previewer.save();
|
||||
};
|
||||
|
||||
// Start countdown for when the dateTime arrives, or clear interval when it is .
|
||||
updateTimeArrivedPoller = function() {
|
||||
var shouldPoll = (
|
||||
'future' === api.state( 'changesetStatus' ).get() &&
|
||||
'future' === api.state( 'selectedChangesetStatus' ).get() &&
|
||||
api.state( 'changesetDate' ).get() &&
|
||||
api.state( 'selectedChangesetDate' ).get() === api.state( 'changesetDate' ).get() &&
|
||||
api.utils.getRemainingTime( api.state( 'changesetDate' ).get() ) >= 0
|
||||
);
|
||||
|
||||
if ( shouldPoll && ! pollInterval ) {
|
||||
pollInterval = setInterval( function() {
|
||||
var remainingTime = api.utils.getRemainingTime( api.state( 'changesetDate' ).get() );
|
||||
api.state( 'remainingTimeToPublish' ).set( remainingTime );
|
||||
if ( remainingTime <= 0 ) {
|
||||
clearInterval( pollInterval );
|
||||
pollInterval = 0;
|
||||
publishWhenTime();
|
||||
}
|
||||
}, timeArrivedPollingInterval );
|
||||
} else if ( ! shouldPoll && pollInterval ) {
|
||||
clearInterval( pollInterval );
|
||||
pollInterval = 0;
|
||||
}
|
||||
};
|
||||
|
||||
api.state( 'changesetDate' ).bind( updateTimeArrivedPoller );
|
||||
api.state( 'selectedChangesetDate' ).bind( updateTimeArrivedPoller );
|
||||
api.state( 'changesetStatus' ).bind( updateTimeArrivedPoller );
|
||||
api.state( 'selectedChangesetStatus' ).bind( updateTimeArrivedPoller );
|
||||
updateTimeArrivedPoller();
|
||||
|
||||
// Ensure dateControl only appears when selected status is future.
|
||||
dateControl.active.validate = function() {
|
||||
return 'future' === statusElement.get();
|
||||
};
|
||||
toggleDateControl = function( value ) {
|
||||
dateControl.active.set( 'future' === value );
|
||||
};
|
||||
toggleDateControl( statusElement.get() );
|
||||
statusElement.bind( toggleDateControl );
|
||||
|
||||
// Show notification on date control when status is future but it isn't a future date.
|
||||
api.state( 'saving' ).bind( function( isSaving ) {
|
||||
if ( isSaving && 'future' === api.state( 'selectedChangesetStatus' ).get() ) {
|
||||
dateControl.toggleFutureDateNotification( ! dateControl.isFutureDate() );
|
||||
}
|
||||
} );
|
||||
} );
|
||||
} );
|
||||
|
||||
// Toggle visibility of Header Video notice when active state change.
|
||||
api.control( 'header_video', function( headerVideoControl ) {
|
||||
headerVideoControl.deferred.embedded.done( function() {
|
||||
|
|
|
@ -430,15 +430,18 @@ class WP_Customize_Control {
|
|||
* Get the data link attribute for a setting.
|
||||
*
|
||||
* @since 3.4.0
|
||||
* @since 4.9.0 Return a `data-customize-setting-key-link` attribute if a setting is not registered for the supplied setting key.
|
||||
*
|
||||
* @param string $setting_key
|
||||
* @return string Data link parameter, if $setting_key is a valid setting, empty string otherwise.
|
||||
* @return string Data link parameter, a `data-customize-setting-link` attribute if the `$setting_key` refers to a pre-registered setting,
|
||||
* and a `data-customize-setting-key-link` attribute if the setting is not yet registered.
|
||||
*/
|
||||
public function get_link( $setting_key = 'default' ) {
|
||||
if ( ! isset( $this->settings[ $setting_key ] ) )
|
||||
return '';
|
||||
|
||||
if ( isset( $this->settings[ $setting_key ] ) && $this->settings[ $setting_key ] instanceof WP_Customize_Setting ) {
|
||||
return 'data-customize-setting-link="' . esc_attr( $this->settings[ $setting_key ]->id ) . '"';
|
||||
} else {
|
||||
return 'data-customize-setting-key-link="' . esc_attr( $setting_key ) . '"';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -3642,6 +3642,23 @@ final class WP_Customize_Manager {
|
|||
<script type="text/html" id="tmpl-customize-trash-changeset-control">
|
||||
<button type="button" class="button-link button-link-delete"><?php _e( 'Discard changes' ); ?></button>
|
||||
</script>
|
||||
<script type="text/html" id="tmpl-customize-selected-changeset-status-control">
|
||||
<# var inputId = _.uniqueId( 'customize-selected-changeset-status-control-input-' ); #>
|
||||
<# var descriptionId = _.uniqueId( 'customize-selected-changeset-status-control-description-' ); #>
|
||||
<# if ( data.label ) { #>
|
||||
<label for="{{ inputId }}" class="customize-control-title">{{ data.label }}</label>
|
||||
<# } #>
|
||||
<# if ( data.description ) { #>
|
||||
<span id="{{ descriptionId }}" class="description customize-control-description">{{{ data.description }}}</span>
|
||||
<# } #>
|
||||
<# _.each( data.choices, function( choice ) { #>
|
||||
<# var choiceId = inputId + '-' + choice.status; #>
|
||||
<span class="customize-inside-control-row">
|
||||
<input id="{{ choiceId }}" type="radio" value="{{ choice.status }}" name="{{ inputId }}" data-customize-setting-key-link="default">
|
||||
<label for="{{ choiceId }}">{{ choice.label }}</label>
|
||||
</span>
|
||||
<# } ); #>
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
|
||||
|
@ -4024,12 +4041,39 @@ final class WP_Customize_Manager {
|
|||
}
|
||||
}
|
||||
|
||||
$current_user_can_publish = current_user_can( get_post_type_object( 'customize_changeset' )->cap->publish_posts );
|
||||
|
||||
// @todo Include all of the status labels here from script-loader.php, and then allow it to be filtered.
|
||||
$status_choices = array();
|
||||
if ( $current_user_can_publish ) {
|
||||
$status_choices[] = array(
|
||||
'status' => 'publish',
|
||||
'label' => __( 'Publish' ),
|
||||
);
|
||||
}
|
||||
$status_choices[] = array(
|
||||
'status' => 'draft',
|
||||
'label' => __( 'Save Draft' ),
|
||||
);
|
||||
if ( $current_user_can_publish ) {
|
||||
$status_choices[] = array(
|
||||
'status' => 'future',
|
||||
'label' => __( 'Schedule' ),
|
||||
);
|
||||
}
|
||||
|
||||
// Prepare Customizer settings to pass to JavaScript.
|
||||
$changeset_post = null;
|
||||
if ( $changeset_post_id ) {
|
||||
$changeset_post = get_post( $changeset_post_id );
|
||||
}
|
||||
|
||||
if ( $this->changeset_post_id() && 'future' === get_post_status( $this->changeset_post_id() ) ) {
|
||||
$initial_date = get_the_time( 'Y-m-d H:i:s', $this->changeset_post_id() );
|
||||
} else {
|
||||
$initial_date = current_time( 'mysql', false );
|
||||
}
|
||||
|
||||
$settings = array(
|
||||
'changeset' => array(
|
||||
'uuid' => $this->changeset_uuid(),
|
||||
|
@ -4038,10 +4082,13 @@ final class WP_Customize_Manager {
|
|||
'hasAutosaveRevision' => ! empty( $autosave_revision_post ),
|
||||
'latestAutoDraftUuid' => $autosave_autodraft_post ? $autosave_autodraft_post->post_name : null,
|
||||
'status' => $changeset_post ? $changeset_post->post_status : '',
|
||||
'currentUserCanPublish' => current_user_can( get_post_type_object( 'customize_changeset' )->cap->publish_posts ),
|
||||
'publishDate' => $changeset_post ? $changeset_post->post_date : '', // @todo Only if future status? Rename to just date?
|
||||
'currentUserCanPublish' => $current_user_can_publish,
|
||||
'publishDate' => $initial_date,
|
||||
'statusChoices' => $status_choices,
|
||||
),
|
||||
'initialServerDate' => current_time( 'mysql', false ),
|
||||
'dateFormat' => get_option( 'date_format' ),
|
||||
'timeFormat' => get_option( 'time_format' ),
|
||||
'initialServerTimestamp' => floor( microtime( true ) * 1000 ),
|
||||
'initialClientTimestamp' => -1, // To be set with JS below.
|
||||
'timeouts' => array(
|
||||
|
@ -4205,6 +4252,7 @@ final class WP_Customize_Manager {
|
|||
|
||||
/* Publish Settings */
|
||||
|
||||
// Note the controls for this section are added via JS.
|
||||
$this->add_section( 'publish_settings', array(
|
||||
'title' => __( 'Publish Settings' ),
|
||||
'priority' => 0,
|
||||
|
@ -4213,47 +4261,6 @@ final class WP_Customize_Manager {
|
|||
'active_callback' => array( $this, 'is_theme_active' ),
|
||||
) );
|
||||
|
||||
/* Publish Settings Controls */
|
||||
$status_choices = array(
|
||||
'publish' => __( 'Publish' ),
|
||||
'draft' => __( 'Save Draft' ),
|
||||
'future' => __( 'Schedule' ),
|
||||
);
|
||||
|
||||
if ( ! current_user_can( get_post_type_object( 'customize_changeset' )->cap->publish_posts ) ) {
|
||||
unset( $status_choices['publish'] );
|
||||
}
|
||||
|
||||
$this->add_control( 'changeset_status', array(
|
||||
'section' => 'publish_settings',
|
||||
'priority' => 10,
|
||||
'settings' => array(),
|
||||
'type' => 'radio',
|
||||
'label' => __( 'Action' ),
|
||||
'choices' => $status_choices,
|
||||
'capability' => 'customize',
|
||||
) );
|
||||
|
||||
if ( $this->changeset_post_id() && 'future' === get_post_status( $this->changeset_post_id() ) ) {
|
||||
$initial_date = get_the_time( 'Y-m-d H:i:s', $this->changeset_post_id() );
|
||||
} else {
|
||||
$initial_date = current_time( 'mysql', false );
|
||||
}
|
||||
|
||||
$this->add_control( new WP_Customize_Date_Time_Control( $this, 'changeset_scheduled_date', array(
|
||||
'section' => 'publish_settings',
|
||||
'priority' => 20,
|
||||
'settings' => array(),
|
||||
'type' => 'date_time',
|
||||
'min_year' => date( 'Y' ),
|
||||
'allow_past_date' => false,
|
||||
'include_time' => true,
|
||||
'twelve_hour_format' => false !== stripos( get_option( 'time_format' ), 'a' ),
|
||||
'description' => __( 'Schedule your customization changes to publish ("go live") at a future date.' ),
|
||||
'capability' => 'customize',
|
||||
'default_value' => $initial_date,
|
||||
) ) );
|
||||
|
||||
/* Themes (controls are loaded via ajax) */
|
||||
|
||||
$this->add_panel( new WP_Customize_Themes_Panel( $this, 'themes', array(
|
||||
|
|
|
@ -65,14 +65,6 @@ class WP_Customize_Date_Time_Control extends WP_Customize_Control {
|
|||
*/
|
||||
public $twelve_hour_format = true;
|
||||
|
||||
/**
|
||||
* Default date/time to be displayed in the control.
|
||||
*
|
||||
* @since 4.9.0
|
||||
* @var string
|
||||
*/
|
||||
public $default_value;
|
||||
|
||||
/**
|
||||
* Don't render the control's content - it's rendered with a JS template.
|
||||
*
|
||||
|
@ -94,7 +86,6 @@ class WP_Customize_Date_Time_Control extends WP_Customize_Control {
|
|||
$data['allowPastDate'] = (bool) $this->allow_past_date;
|
||||
$data['twelveHourFormat'] = (bool) $this->twelve_hour_format;
|
||||
$data['includeTime'] = (bool) $this->include_time;
|
||||
$data['defaultValue'] = $this->default_value;
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
|
|
@ -566,6 +566,7 @@ function wp_default_scripts( &$scripts ) {
|
|||
'saved' => __( 'Saved' ),
|
||||
'cancel' => __( 'Cancel' ),
|
||||
'close' => __( 'Close' ),
|
||||
'action' => __( 'Action' ),
|
||||
'cheatin' => __( 'Cheatin’ uh?' ),
|
||||
'notAllowed' => __( 'Sorry, you are not allowed to customize this site.' ),
|
||||
'previewIframeTitle' => __( 'Site Preview' ),
|
||||
|
@ -594,6 +595,7 @@ function wp_default_scripts( &$scripts ) {
|
|||
_n_noop( 'Unable to save due to %s invalid setting.', 'Unable to save due to %s invalid settings.' ),
|
||||
array( 'singular', 'plural' )
|
||||
),
|
||||
'scheduleDescription' => __( 'Schedule your customization changes to publish ("go live") at a future date.' ),
|
||||
) );
|
||||
$scripts->add( 'customize-selective-refresh', "/wp-includes/js/customize-selective-refresh$suffix.js", array( 'jquery', 'wp-util', 'customize-preview' ), false, 1 );
|
||||
|
||||
|
|
|
@ -2581,7 +2581,7 @@ class Tests_WP_Customize_Manager extends WP_UnitTestCase {
|
|||
$data = json_decode( $json, true );
|
||||
$this->assertNotEmpty( $data );
|
||||
|
||||
$this->assertEqualSets( array( 'theme', 'url', 'browser', 'panels', 'sections', 'nonce', 'autofocus', 'documentTitleTmpl', 'previewableDevices', 'changeset', 'timeouts', 'initialClientTimestamp', 'initialServerDate', 'initialServerTimestamp', 'l10n' ), array_keys( $data ) );
|
||||
$this->assertEqualSets( array( 'theme', 'url', 'browser', 'panels', 'sections', 'nonce', 'autofocus', 'documentTitleTmpl', 'previewableDevices', 'changeset', 'timeouts', 'dateFormat', 'timeFormat', 'initialClientTimestamp', 'initialServerDate', 'initialServerTimestamp', 'l10n' ), array_keys( $data ) );
|
||||
$this->assertEquals( $autofocus, $data['autofocus'] );
|
||||
$this->assertArrayHasKey( 'save', $data['nonce'] );
|
||||
$this->assertArrayHasKey( 'preview', $data['nonce'] );
|
||||
|
@ -2596,6 +2596,7 @@ class Tests_WP_Customize_Manager extends WP_UnitTestCase {
|
|||
'uuid',
|
||||
'currentUserCanPublish',
|
||||
'publishDate',
|
||||
'statusChoices',
|
||||
),
|
||||
array_keys( $data['changeset'] )
|
||||
);
|
||||
|
|
|
@ -710,9 +710,9 @@ jQuery( window ).load( function (){
|
|||
params: {
|
||||
section: section.id,
|
||||
type: 'date_time',
|
||||
setting: new wp.customize.Value( datetime ),
|
||||
includeTime: true,
|
||||
content: '<li id="customize-control-' + controlId + '" class="customize-control"></li>',
|
||||
defaultValue: datetime
|
||||
content: '<li id="customize-control-' + controlId + '" class="customize-control"></li>'
|
||||
}
|
||||
} );
|
||||
|
||||
|
|
Loading…
Reference in New Issue