Improving Setting Validation in the Customizer

In #34893 and the accompanying Customize Setting Validation feature pluginFeature Plugin A plugin that was created with the intention of eventually being proposed for inclusion in WordPress Core. See Features as Plugins. I’ve suggested improvements to the CustomizerCustomizer Tool built into WordPress core that hooks into most modern themes. You can use it to preview and modify many of your site’s appearance settings. setting validation model. More can be read about the proposal in that ticketticket Created for both bug reports and feature development on the bug tracker. description and pluginPlugin A plugin is a piece of software containing a group of functions that can be added to a WordPress website. They can extend functionality or add new features to your WordPress websites. WordPress plugins are written in the PHP programming language and integrate seamlessly with WordPress. These can be free in the Plugin Directory or can be cost-based plugin from a third-party readme, but the short of it is that settings in the Customizer generally undergo clean-up sanitization but lack a robust system for pass/fail validation. Here is a video demo depicting what I think validation should look like in the Customizer:

Normally the Customizer just sanitizes values by attempting to coerce them and clean them up into something that can be safely used (e.g. stripping tags). As for validation, and while I believe this is relatively unusual to encounter, you can also do strict validation of a setting by blocking it from being saved: this is done by returning null from WP_Customize_Setting::sanitize() (often via  WP_Customize_Setting::$sanitize_callback). This is the behavior for setting the background_color: if the value is not a valid hex code, it will not save. The problem here is that there is no feedback to the user that the save was blocked. If user tries to enter “blue” as a color instead of a hex code, they will not get informed that this is invalidinvalid A resolution on the bug tracker (and generally common in software development, sometimes also notabug) that indicates the ticket is not a bug, is a support request, or is generally invalid.: it will be as if they never tried to save any change at all. Incidentally, this is also the case for widgets, where the WP_Widget::update() normally just sanitizes the instance arrays, though it can return false to blockBlock Block is the abstract term used to describe units of markup that, composed together, form the content or layout of a webpage using the WordPress editor. The idea combines concepts of what in the past may have achieved with shortcodes, custom HTML, and embed discovery into a single consistent API and user experience. an update, with likewise no indication that the update was blocked.

Additionally, in the current validation system, if you have made 10 changes in your Customizer session (transaction), but half of them get blocked from saving due to being invalid, then you have an only partially-saved Customizer state. This is a really bad experience for sites that make heavy use of the Customizer beyond just using it to tweak some colors.

So to summarize the suggested improvements to validation in the customizer:

  1. All modified settings should be validated up-front before any of them are saved.
  2. If any setting is invalid, the Customizer save request should be rejected: a save thus becomes transactional with all the settings left dirty to try saving again.
  3. Validation error messages should be displayed to the user, prompting them to fix their mistake and try again.

All of the above is implemented in the Customize Setting Validation feature plugin, and I’d love your feedback on it. One thing in particular I need feedback on is how specifically a setting should go about performing validation on the server. As noted above, the WP_Customize_Setting::sanitize() method can currently do both sanitization (returning a cleaned-up value) and validation (returning null to block saving if value is beyond repair). In the current feature plugin, I’m proposing:

  1. Continue to use the same sanitize methods/callbacks/filters.
  2. Introduce a new $strict param to indicate that validation is being performed.
  3. Allow these functions to fail validation by returning WP_Error instances with information about what failed in addition to null as they can today.

Update 2016-06-26: The following examples differ from what has been committed to coreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress. A follow-up post will detail the new APIs for validation.

How the changes would look for WP_Customize_Setting::sanitize():

 * Sanitize an input.
 * @since 3.4.0
 * @since 4.6.0 Added `$strict` param to indicate validation is being performed.
 * @param string|array $value  The value to sanitize.
 * @param bool         $strict Whether validation is being performed.
 * @return string|array|null|WP_Error Null or WP_Error if an input isn't valid, otherwise the sanitized value.
public function sanitize( $value, $strict = false )

And for the customize_sanitize_{$id} filterFilter Filters are one of the two types of Hooks They provide a way for functions to modify data of other functions. They are the counterpart to Actions. Unlike Actions, filters are meant to work in an isolated manner, and should never have side effects such as affecting global variables and output.:

 * Filter a Customize setting value.
 * @since 3.4.0
 * @since 4.6.0 Added `$strict` param to indicate validation is being performed.
 * @param mixed                $value  Value of the setting.
 * @param bool                 $strict Whether validation is being performed.
 * @param WP_Customize_Setting $this   WP_Customize_Setting instance.
return apply_filters( "customize_sanitize_{$this->id}", $value, $this, $strict );

This should be nicely backwards-compatible, and allow for the sanitize/validate logic to be kept in the same function since they are very closely related. But that raises some questions:

  1. Should there be a separate WP_Customize_Setting::validate() method as well that by default calls WP_Customize_Setting::sanitize() with the $strict param set to true?
  2. Should validation only be applied when saving the setting while mere sanitization is required for previewing a value change?

On the second point here, my thought is that it may often be the desire for looser cleanup sanitization to be applied to a value during data entry. Consider a blob of text displayed on the page which forbids the use of markup. As I do data entry I may like to see what I am entering being displayed in the preview with the tags stripped (normal behavior today) whereas when I try saving I can be alerted that saving the value with markup is not allowed. This would provide the user with feedback as to why the markup is mysteriously not appearing in the preview. (As for providing this validation feedback while the user entering data, this should be done via JSJS JavaScript, a web scripting language typically executed in the browser. Often used for advanced user interfaces and behaviors., or the validation state be determined by performing validation in an update-transaction request for transactions.)

I’ll also note that REST APIREST API The REST API is an acronym for the RESTful Application Program Interface (API) that uses HTTP requests to GET, PUT, POST and DELETE data. It is how the front end of an application (think “phone app” or “website”) can communicate with the data store (think “database” or “file system”) supports both sanitization and validation for request args, but these are handled in two separate callbacks. The way it works is that any registered sanitize_callbacks are applied first, followed by setting of default values, and then the validate_callbacks are run. See WP_REST_Server::dispatch(). This works fine, but I think we could have more flexibility if the sanitization and validation logic could be in the same method. Perhaps you want to run sanitization before validation (sanitize by stripping tags and validate to ensure the value is not empty), or be more strict by running validation before sanitization (reject any text that contains markup entirely).

So, for you all who develop settings in the Customizer, what are your thoughts on how validation should behave, and how validation should relate to sanitization in the context of the Customizer? What do you think of the APIAPI An API or Application Programming Interface is a software intermediary that allows programs to interact with each other and share data in limited, clearly defined ways. changes I’ve proposed?

#4-6, #customize