Skip to content
This repository was archived by the owner on Dec 16, 2022. It is now read-only.

Add support for setting validation in 4.6-alpha #150

Merged
merged 14 commits into from
Jun 1, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 1 addition & 10 deletions css/customize-posts.css
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
/* In case Customize Setting Validation is not active */
div.customize-setting-validation-message.error {
display: none;
}

.customize-posts-panel-notice {
color: #555;
Expand All @@ -10,12 +6,7 @@ div.customize-setting-validation-message.error {
border-top: 1px solid #ddd;
}

.customize-section-title > div.customize-setting-validation-message {
border-top: 1px solid #ddd;
margin-top: 0;
margin-bottom: 0;
}
.customize-setting-validation-message .override-post-conflict {
.customize-control-notifications-container .override-post-conflict {
margin-left: 1ex;
float: right;
}
Expand Down
147 changes: 87 additions & 60 deletions js/customize-post-section.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* global wp, tinyMCE */
/* eslint consistent-this: [ "error", "section" ], no-magic-numbers: [ "error", { "ignore": [0,1] } ] */
/* eslint consistent-this: [ "error", "section" ], no-magic-numbers: [ "error", { "ignore": [-1,0,1] } ] */

(function( api, $ ) {
'use strict';
Expand Down Expand Up @@ -193,6 +193,21 @@
}
},

/**
* Prevent notifications for settings from being added to post field control notifications.
*
* @param {string} code Notification code.
* @param {wp.customize.Notification} notification Notification object.
* @returns {wp.customize.Notification|null} Notification if not bypassed.
*/
addPostFieldControlNotification: function( code, notification ) {
if ( -1 !== code.indexOf( ':' ) ) {
return null;
} else {
return api.Values.prototype.add.call( this, code, notification );
}
},

/**
* Add post title control.
*
Expand Down Expand Up @@ -223,18 +238,16 @@
section.postFieldControls.post_title = control;
api.control.add( control.id, control );

// Remove the setting from the settingValidationMessages since it is not specific to this field.
if ( control.settingValidationMessages ) {
control.settingValidationMessages.remove( setting.id );
control.settingValidationMessages.add( control.id, new api.Value( '' ) );
if ( control.notifications ) {
control.notifications.add = section.addPostFieldControlNotification;
}
return control;
},

/**
* Add post slug control.
*
* @returns {wp.customize.Control}
* @returns {wp.customize.Control} Added control.
*/
addSlugControl: function() {
var section = this, control, setting = api( section.id );
Expand Down Expand Up @@ -272,10 +285,8 @@
section.postFieldControls.post_name = control;
api.control.add( control.id, control );

// Remove the setting from the settingValidationMessages since it is not specific to this field.
if ( control.settingValidationMessages ) {
control.settingValidationMessages.remove( setting.id );
control.settingValidationMessages.add( control.id, new api.Value( '' ) );
if ( control.notifications ) {
control.notifications.add = section.addPostFieldControlNotification;
}
return control;
},
Expand Down Expand Up @@ -538,10 +549,8 @@
control.container.append( control.editorToggleExpandButton );
} );

// Remove the setting from the settingValidationMessages since it is not specific to this field.
if ( control.settingValidationMessages ) {
control.settingValidationMessages.remove( setting.id );
control.settingValidationMessages.add( control.id, new api.Value( '' ) );
if ( control.notifications ) {
control.notifications.add = section.addPostFieldControlNotification;
}
return control;
},
Expand Down Expand Up @@ -576,10 +585,8 @@
section.postFieldControls.post_excerpt = control;
api.control.add( control.id, control );

// Remove the setting from the settingValidationMessages since it is not specific to this field.
if ( control.settingValidationMessages ) {
control.settingValidationMessages.remove( setting.id );
control.settingValidationMessages.add( control.id, new api.Value( '' ) );
if ( control.notifications ) {
control.notifications.add = section.addPostFieldControlNotification;
}
return control;
},
Expand Down Expand Up @@ -614,10 +621,8 @@
section.postFieldControls.post_discussion_fields = control;
api.control.add( control.id, control );

// Remove the setting from the settingValidationMessages since it is not specific to this field.
if ( control.settingValidationMessages ) {
control.settingValidationMessages.remove( setting.id );
control.settingValidationMessages.add( control.id, new api.Value( '' ) );
if ( control.notifications ) {
control.notifications.add = section.addPostFieldControlNotification;
}
return control;
},
Expand Down Expand Up @@ -653,10 +658,8 @@
section.postFieldControls.post_author = control;
api.control.add( control.id, control );

// Remove the setting from the settingValidationMessages since it is not specific to this field.
if ( control.settingValidationMessages ) {
control.settingValidationMessages.remove( setting.id );
control.settingValidationMessages.add( control.id, new api.Value( '' ) );
if ( control.notifications ) {
control.notifications.add = section.addPostFieldControlNotification;
}
return control;
},
Expand All @@ -667,39 +670,65 @@
* @returns {void}
*/
setupSettingValidation: function() {
var section = this, setting = api( section.id );
if ( ! setting.validationMessage ) {
var section = this, setting = api( section.id ), debouncedRenderNotifications;
if ( ! setting.notifications ) {
return;
}

section.validationMessageElement = $( '<div class="customize-setting-validation-message error" aria-live="assertive"></div>' );
section.container.find( '.customize-section-title' ).append( section.validationMessageElement );
setting.validationMessage.bind( function( message ) {
var template = wp.template( 'customize-setting-validation-message' );
section.validationMessageElement.empty().append( $.trim(
template( { messages: [ message ] } )
) );
if ( message ) {
section.validationMessageElement.slideDown( 'fast' );
} else {
section.validationMessageElement.slideUp( 'fast' );
}
section.container.toggleClass( 'customize-setting-invalid', '' !== message );
// Add the notifications API.
section.notifications = new api.Values({ defaultConstructor: api.Notification });
section.notificationsContainer = $( '<div class="customize-control-notifications-container"></div>' );
section.notificationsTemplate = wp.template( 'customize-post-section-notifications' );
section.container.find( '.customize-section-title' ).after( section.notificationsContainer );
section.getNotificationsContainerElement = function() {
return section.notificationsContainer;
};
section.renderNotifications = api.Control.prototype.renderNotifications;

// Sync setting notifications into the section notifications
setting.notifications.bind( 'add', function( settingNotification ) {
var notification = new api.Notification( setting.id + ':' + settingNotification.code, settingNotification );
section.notifications.add( notification.code, notification );
} );
setting.notifications.bind( 'remove', function( settingNotification ) {
section.notifications.remove( setting.id + ':' + settingNotification.code );
} );

/*
* Render notifications when the collection is updated.
* Note that this debounced/deferred rendering is needed for two reasons:
* 1) The 'remove' event is triggered just _before_ the notification is actually removed.
* 2) Improve performance when adding/removing multiple notifications at a time.
*/
debouncedRenderNotifications = _.debounce( function renderNotifications() {
section.renderNotifications();
} );
section.notifications.bind( 'add', function( notification ) {
wp.a11y.speak( notification.message, 'assertive' );
debouncedRenderNotifications();
} );
section.notifications.bind( 'remove', debouncedRenderNotifications );
section.renderNotifications();

// Dismiss conflict block when clicking on button.
section.validationMessageElement.on( 'click', '.override-post-conflict', function( e ) {
section.notificationsContainer.on( 'click', '.override-post-conflict', function( e ) {
var ourValue;
e.preventDefault();
ourValue = _.clone( setting.get() );
ourValue.post_modified_gmt = '';
setting.set( ourValue );
section.resetPostFieldControlSettingValidationMessages();

_.each( section.postFieldControls, function( control ) {
if ( control.notifications ) {
control.notifications.remove( 'post_update_conflict' );
}
} );
setting.notifications.remove( 'post_update_conflict' );
} );

// Detect conflict errors.
api.bind( 'error', function( response ) {
var theirValue, ourValue, overrideButton, wasOverrideButtonAdded = false;
var theirValue, ourValue;
if ( ! response.update_conflicted_setting_values ) {
return;
}
Expand All @@ -709,27 +738,23 @@
}
ourValue = setting.get();
_.each( theirValue, function( theirFieldValue, fieldId ) {
var control, validationMessage;
var control, notification;
if ( 'post_modified' === fieldId || 'post_modified_gmt' === fieldId || theirFieldValue === ourValue[ fieldId ] ) {
return;
}
control = api.control( setting.id + '[' + fieldId + ']' );
if ( control && control.settingValidationMessages && control.settingValidationMessages.has( control.id ) ) {
validationMessage = api.Posts.data.l10n.theirChange.replace( '%s', String( theirFieldValue ) );
control.settingValidationMessages( control.id ).set( validationMessage );

if ( ! wasOverrideButtonAdded ) {
overrideButton = $( '<button class="button override-post-conflict" type="button"></button>' );
overrideButton.text( api.Posts.data.l10n.overrideButtonText );
section.validationMessageElement.find( 'li:first' ).prepend( overrideButton );
wasOverrideButtonAdded = true;
}
if ( control && control.notifications ) {
notification = new api.Notification( 'post_update_conflict', {
message: api.Posts.data.l10n.theirChange.replace( '%s', String( theirFieldValue ) )
} );
control.notifications.remove( notification.code );
control.notifications.add( notification.code, notification );
}
} );
} );

api.bind( 'save', function() {
section.resetPostFieldControlSettingValidationMessages();
section.resetPostFieldControlErrorNotifications();
} );
},

Expand All @@ -738,12 +763,14 @@
*
* @returns {void}
*/
resetPostFieldControlSettingValidationMessages: function() {
resetPostFieldControlErrorNotifications: function() {
var section = this;
_.each( section.postFieldControls, function( postFieldControl ) {
if ( postFieldControl.settingValidationMessages ) {
postFieldControl.settingValidationMessages.each( function( validationMessage ) {
validationMessage.set( '' );
if ( postFieldControl.notifications ) {
postFieldControl.notifications.each( function( notification ) {
if ( 'error' === notification.type ) {
postFieldControl.notifications.remove( notification.code );
}
} );
}
} );
Expand Down
8 changes: 6 additions & 2 deletions js/customize-posts-panel.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,15 +88,19 @@
button.prop( 'disabled', true );

postData = {
post_type: panel.postType,
post_status: 'publish'
};
if ( postObj.supports.title ) {
postData.post_title = api.Posts.data.l10n.noTitle;
}

promise = api.Posts.insertAutoDraftPost( postData );
promise = api.Posts.insertAutoDraftPost( panel.postType );
promise.done( function( data ) {
data.setting.set( _.extend(
{},
data.setting.get(),
postData
) );

// Navigate to the newly-created post if it is public; otherwise, refresh the preview.
if ( postObj['public'] && data.url ) {
Expand Down
15 changes: 9 additions & 6 deletions js/customize-posts.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,16 +88,16 @@
/**
* Insert a new stubbed `auto-draft` post.
*
* @param {object} params - Parameters to configure the setting.
* @return {Promise} Promise resolved with the added section.
* @param {string} postType Post type to create.
* @return {jQuery.promise} Promise resolved with the added section.
*/
component.insertAutoDraftPost = function( params ) {
component.insertAutoDraftPost = function( postType ) {
var request, deferred = $.Deferred();

request = wp.ajax.post( 'customize-posts-add-new', {
request = wp.ajax.post( 'customize-posts-insert-auto-draft', {
'customize-posts-nonce': api.Posts.data.nonce,
'wp_customize': 'on',
'params': params || {}
'post_type': postType
} );

request.done( function( response ) {
Expand All @@ -106,7 +106,10 @@
deferred.rejectWith( 'no_sections' );
} else {
deferred.resolve( _.extend(
{ section: sections[0] },
{
section: sections[0],
setting: api( sections[0].id )
},
response
) );
}
Expand Down
1 change: 0 additions & 1 deletion php/class-wp-customize-dynamic-control.php
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,6 @@ class="widefat"
/>
<# } #>
<# } #>
<div class="customize-setting-validation-message error" aria-live="assertive"></div>
<?php
}
}
14 changes: 5 additions & 9 deletions php/class-wp-customize-featured-image-controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -378,11 +378,11 @@ public function sanitize_value( $attachment_id ) {
*
* @param string $attachment_id The value to sanitize.
* @param WP_Customize_Postmeta_Setting $setting Setting.
* @param bool $strict Whether validation is being done. This is part of the proposed patch in in #34893.
* @return mixed|null Null if an input isn't valid, otherwise the sanitized value.
* @return mixed|WP_Error Sanitized value or `WP_Error` if invalid.
*/
public function sanitize_setting( $attachment_id, WP_Customize_Postmeta_Setting $setting, $strict = false ) {
public function sanitize_setting( $attachment_id, WP_Customize_Postmeta_Setting $setting ) {
unset( $setting );
$has_setting_validation = method_exists( 'WP_Customize_Setting', 'validate' );

$is_valid = (
'' === $attachment_id
Expand All @@ -397,12 +397,8 @@ public function sanitize_setting( $attachment_id, WP_Customize_Postmeta_Setting
* and the meta is registered wit WP_Customize_Featured_Image_Controller::sanitize_value() as the sanitize_callback().
* So $attachment_id is either a valid attachment ID, -1, or false.
*/
if ( $strict && ! $is_valid ) {
if ( $strict ) {
return new WP_Error( 'invalid_attachment_id', __( 'The attachment is invalid.', 'customize-posts' ) );
} else {
return null;
}
if ( ! $is_valid ) {
return $has_setting_validation ? new WP_Error( 'invalid_attachment_id', __( 'The attachment is invalid.', 'customize-posts' ) ) : null;
}

$attachment_id = $this->sanitize_value( $attachment_id );
Expand Down
12 changes: 4 additions & 8 deletions php/class-wp-customize-page-template-controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -104,19 +104,15 @@ public function sanitize_value( $raw_path ) {
*
* @param string $page_template The value to sanitize.
* @param WP_Customize_Postmeta_Setting $setting Setting.
* @param bool $strict Whether validation is being done. This is part of the proposed patch in in #34893.
* @return mixed|null Null if an input isn't valid, otherwise the sanitized value.
* @return mixed|WP_Error Sanitized value or WP_Error if invalid valid.
*/
public function sanitize_setting( $page_template, WP_Customize_Postmeta_Setting $setting, $strict = false ) {
public function sanitize_setting( $page_template, WP_Customize_Postmeta_Setting $setting ) {
$post = get_post( $setting->post_id );
$page_templates = wp_get_theme()->get_page_templates( $post );
$has_setting_validation = method_exists( 'WP_Customize_Setting', 'validate' );

if ( 'default' !== $page_template && ! isset( $page_templates[ $page_template ] ) ) {
if ( $strict ) {
return new WP_Error( 'invalid_page_template', __( 'The page template is invalid.', 'customize-posts' ) );
} else {
return null;
}
return $has_setting_validation ? new WP_Error( 'invalid_page_template', __( 'The page template is invalid.', 'customize-posts' ) ) : null;
}
return $page_template;
}
Expand Down
Loading