Make WordPress Core


Ignore:
Timestamp:
05/20/2016 09:09:40 PM (9 years ago)
Author:
westonruter
Message:

Customize: Add setting validation model and control notifications to augment setting sanitization.

When a setting is invalid, not only will it be blocked from being saved but all other settings will be blocked as well. This ensures that Customizer saves aren't partial but are more transactional. User will be displayed the error in a notification so that they can fix and re-attempt saving.

PHP changes:

  • Introduces WP_Customize_Setting::validate(), WP_Customize_Setting::$validate_callback, and the customize_validate_{$setting_id} filter.
  • Introduces WP_Customize_Manager::validate_setting_values() to do validation (and sanitization) for the setting values supplied, returning a list of WP_Error instances for invalid settings.
  • Attempting to save settings that are invalid will result in the save being blocked entirely, with the errors being sent in the customize_save_response. Modifies WP_Customize_Manager::save() to check all settings for validity issues prior to calling their save methods.
  • Introduces WP_Customize_Setting::json() for parity with the other Customizer classes. This includes exporting of the type.
  • Modifies WP_Customize_Manager::post_value() to apply validate after sanitize, and if validation fails, to return the $default.
  • Introduces customize_save_validation_before action which fires right before the validation checks are made prior to saving.

JS changes:

  • Introduces wp.customize.Notification in JS which to represent WP_Error instances returned from the server when setting validation fails.
  • Introduces wp.customize.Setting.prototype.notifications.
  • Introduces wp.customize.Control.prototype.notifications, which are synced with a control's settings' notifications.
  • Introduces wp.customize.Control.prototype.renderNotifications() to re-render a control's notifications in its notification area. This is called automatically when the notifications collection changes.
  • Introduces wp.customize.settingConstructor, allowing custom setting types to be used in the same way that custom controls, panels, and sections can be made.
  • Injects a notification area into existing controls which is populated in response to the control's notifications collection changing. A custom control can customize the placement of the notification area by overriding the new getNotificationsContainerElement method.
  • When a save fails due to setting invalidity, the invalidity errors will be added to the settings to then populate in the controls' notification areas, and the first such invalid control will be focused.

Props westonruter, celloexpressions, mrahmadawais.
See #35210.
See #30937.
Fixes #34893.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/class-wp-customize-setting.php

    r37350 r37476  
    6060     * @var callback
    6161     */
     62    public $validate_callback    = '';
    6263    public $sanitize_callback    = '';
    6364    public $sanitize_js_callback = '';
     
    143144        }
    144145
     146        if ( $this->validate_callback ) {
     147            add_filter( "customize_validate_{$this->id}", $this->validate_callback, 10, 3 );
     148        }
    145149        if ( $this->sanitize_callback ) {
    146150            add_filter( "customize_sanitize_{$this->id}", $this->sanitize_callback, 10, 2 );
     
    465469     *
    466470     * @since 3.4.0
    467      *
    468      * @return false|void False if cap check fails or value isn't set.
     471     * @since 4.6.0 Return the result of updating the value.
     472     *
     473     * @return false|void False if cap check fails or value isn't set or is invalid.
    469474     */
    470475    final public function save() {
    471476        $value = $this->post_value();
    472477
    473         if ( ! $this->check_capabilities() || ! isset( $value ) )
     478        if ( ! $this->check_capabilities() || ! isset( $value ) ) {
    474479            return false;
     480        }
    475481
    476482        /**
     
    484490         * @param WP_Customize_Setting $this WP_Customize_Setting instance.
    485491         */
    486         do_action( 'customize_save_' . $this->id_data[ 'base' ], $this );
     492        do_action( 'customize_save_' . $this->id_data['base'], $this );
    487493
    488494        $this->update( $value );
     
    495501     *
    496502     * @param mixed $default A default value which is used as a fallback. Default is null.
    497      * @return mixed The default value on failure, otherwise the sanitized value.
     503     * @return mixed The default value on failure, otherwise the sanitized and validated value.
    498504     */
    499505    final public function post_value( $default = null ) {
     
    506512     * @since 3.4.0
    507513     *
    508      * @param string|array $value The value to sanitize.
    509      * @return string|array|null Null if an input isn't valid, otherwise the sanitized value.
     514     * @param string|array $value    The value to sanitize.
     515     * @return string|array|null|WP_Error Sanitized value, or `null`/`WP_Error` if invalid.
    510516     */
    511517    public function sanitize( $value ) {
     
    520526         */
    521527        return apply_filters( "customize_sanitize_{$this->id}", $value, $this );
     528    }
     529
     530    /**
     531     * Validate an input.
     532     *
     533     * @since 4.6.0
     534     * @access public
     535     * @see WP_REST_Request::has_valid_params()
     536     *
     537     * @param mixed $value Value to validate.
     538     * @return true|WP_Error
     539     */
     540    public function validate( $value ) {
     541        if ( is_wp_error( $value ) ) {
     542            return $value;
     543        }
     544        if ( is_null( $value ) ) {
     545            return new WP_Error( 'invalid_value', __( 'Invalid value.' ) );
     546        }
     547
     548        $validity = new WP_Error();
     549
     550        /**
     551         * Validate a Customize setting value.
     552         *
     553         * Plugins should amend the `$validity` object via its `WP_Error::add()` method.
     554         *
     555         * @since 4.6.0
     556         *
     557         * @param WP_Error             $validity Filtered from `true` to `WP_Error` when invalid.
     558         * @param mixed                $value    Value of the setting.
     559         * @param WP_Customize_Setting $this     WP_Customize_Setting instance.
     560         */
     561        $validity = apply_filters( "customize_validate_{$this->id}", $validity, $value, $this );
     562
     563        if ( is_wp_error( $validity ) && empty( $validity->errors ) ) {
     564            $validity = true;
     565        }
     566        return $validity;
    522567    }
    523568
     
    701746
    702747    /**
     748     * Get the data to export to the client via JSON.
     749     *
     750     * @since 4.6.0
     751     *
     752     * @return array Array of parameters passed to JavaScript.
     753     */
     754    public function json() {
     755        return array(
     756            'value'     => $this->js_value(),
     757            'transport' => $this->transport,
     758            'dirty'     => $this->dirty,
     759            'type'      => $this->type,
     760        );
     761    }
     762
     763    /**
    703764     * Validate user capabilities whether the theme supports the setting.
    704765     *
Note: See TracChangeset for help on using the changeset viewer.