[wp-trac] [WordPress Trac] #43208: Separate setting validation from sanitization
WordPress Trac
noreply at wordpress.org
Thu Aug 30 13:25:17 UTC 2018
#43208: Separate setting validation from sanitization
-------------------------------------------------+-------------------------
Reporter: flixos90 | Owner: (none)
Type: enhancement | Status: new
Priority: normal | Milestone: Awaiting
| Review
Component: Options, Meta APIs | Version:
Severity: normal | Resolution:
Keywords: 2nd-opinion has-patch needs-unit- | Focuses:
tests |
-------------------------------------------------+-------------------------
Comment (by flixos90):
[attachment:"43208.6.diff"] ensures the patch applies cleanly again. It
also changes the `validate_option_{$option}` filter into an action, in
accordance which how a similar new hook was handled in #40364. An action
is the proper way to amend a passed-in object. They are passed by
reference, so filtering them through can only have negative side-effects
with invalid filter values.
I also wrote a small test plugin for that, which registers a few different
options with validation adds an interface to them via an options page, a
Customizer section, and the REST API settings controller. You can easily
test the new functionality using it.
{{{
<?php
/*
Plugin Name: Option Validation Tests
Plugin URI: https://make.wordpress.org/
Description: Tests for option validation.
Version: 1.0
Author: WordPress Core Contributors
Author URI: https://make.wordpress.org/
*/
function test_register_settings() {
register_setting(
'option_validation_tests',
'ovt_integer',
array(
'type' => 'integer',
'description' => __( 'An integer option.' ),
'sanitize_callback' => 'absint',
'validate_callback' => function( $errors, $value )
{
test_validate_setting( $errors, $value,
array( 'min' => 3 ) );
},
'show_in_rest' => true,
)
);
register_setting(
'option_validation_tests',
'ovt_email',
array(
'type' => 'string',
'description' => __( 'An email option.' ),
'sanitize_callback' => 'sanitize_email',
'validate_callback' => function( $errors, $value )
{
test_validate_setting( $errors, $value,
array( 'email' => true ) );
},
'show_in_rest' => true,
)
);
register_setting(
'option_validation_tests',
'ovt_bool',
array(
'type' => 'boolean',
'description' => __( 'A boolean option.' ),
'sanitize_callback' => 'boolval',
'validate_callback' => function( $errors, $value )
{
test_validate_setting( $errors, $value,
array( 'checked' => true ) );
},
'show_in_rest' => true,
)
);
register_setting(
'option_validation_tests',
'ovt_enum',
array(
'type' => 'string',
'description' => __( 'An enum option.' ),
'sanitize_callback' => 'strip_tags',
'validate_callback' => function( $errors, $value )
{
test_validate_setting( $errors, $value,
array( 'enum' => array( 'value1', 'value2', 'value3' ) ) );
},
'show_in_rest' => true,
)
);
}
add_action( 'init', 'test_register_settings' );
function test_validate_setting( $errors, $value, $args = array() ) {
if ( isset( $args['enum'] ) && ! in_array( $value, $args['enum'],
true ) ) {
$errors->add( 'value_not_in_enum', sprintf( __( 'The value
%s is not one of the valid choices.' ), esc_html( $value ) ) );
}
if ( isset( $args['min'] ) && (float) $value < (float)
$args['min'] ) {
$errors->add( 'value_too_small', sprintf( __( 'The value
%1$s is smaller than the allowed minimum %2$s.' ), number_format_i18n(
(float) $value ), number_format_i18n( (float) $args['min'] ) ) );
}
if ( isset( $args['max'] ) && (float) $value > (float)
$args['max'] ) {
$errors->add( 'value_too_great', sprintf( __( 'The value
%1$s is greater than the allowed maximum %2$s.' ), number_format_i18n(
(float) $value ), number_format_i18n( (float) $args['max'] ) ) );
}
if ( isset( $args['email'] ) && $args['email'] && ! is_email(
$value ) ) {
$errors->add( 'value_not_an_email', sprintf( __( 'The
value %s is not a valid email address.' ), esc_html( $value ) ) );
}
if ( isset( $args['checked'] ) && $args['checked'] && ! $value ) {
$errors->add( 'value_unchecked', __( 'You must check the
checkbox.' ) );
}
}
function test_add_settings_fields() {
add_settings_section( 'general', __( 'General' ), null,
'option_validation_tests' );
add_settings_section( 'other', __( 'Other' ), null,
'option_validation_tests' );
add_settings_field(
'ovt_integer',
__( 'Integer Option' ),
function() {
?>
<input type="number" name="ovt_integer"
value="<?php echo esc_attr( get_option( 'ovt_integer' ) ); ?>" />
<p class="description"><?php esc_html_e( 'Enter a
value greater than or equal to 3.' ); ?></p>
<?php
},
'option_validation_tests',
'general',
array( 'label_for' => 'ovt_integer' )
);
add_settings_field(
'ovt_email',
__( 'Email Option' ),
function() {
?>
<input type="email" name="ovt_email" value="<?php
echo esc_attr( get_option( 'ovt_email' ) ); ?>" />
<p class="description"><?php esc_html_e( 'Enter an
email address.' ); ?></p>
<?php
},
'option_validation_tests',
'general',
array( 'label_for' => 'ovt_email' )
);
add_settings_field(
'ovt_bool',
__( 'Boolean Option' ),
function() {
?>
<input type="checkbox" name="ovt_bool" <?php
checked( get_option( 'ovt_bool' ) ); ?> />
<p class="description"><?php esc_html_e( 'Check
this checkbox.' ); ?></p>
<?php
},
'option_validation_tests',
'general',
array( 'label_for' => 'ovt_bool' )
);
add_settings_field(
'ovt_enum',
__( 'Enum Option' ),
function() {
?>
<input type="text" name="ovt_enum" value="<?php
echo esc_attr( get_option( 'ovt_enum' ) ); ?>" />
<p class="description"><?php esc_html_e( 'Enter
either value1, value2, or value3.' ); ?></p>
<?php
},
'option_validation_tests',
'other',
array( 'label_for' => 'ovt_enum' )
);
}
add_action( 'admin_init', 'test_add_settings_fields' );
function test_register_settings_page() {
add_options_page( __( 'Option Validation Test' ), __( 'Option
Validation Test' ), 'manage_options', 'option_validation_tests',
'test_render_settings_page' );
}
add_action( 'admin_menu', 'test_register_settings_page' );
function test_render_settings_page() {
?>
<div class="wrap">
<h1><?php _e( 'Option Validation Test' ); ?></h1>
<form action="options.php" method="post"
novalidate="novalidate">
<?php settings_fields( 'option_validation_tests'
); ?>
<?php do_settings_sections(
'option_validation_tests' ); ?>
<?php submit_button(); ?>
</form>
</div>
<?php
}
function test_customize_register( $wp_customize ) {
$wp_customize->add_setting( 'ovt_integer', array( 'type' =>
'option' ) );
$wp_customize->add_setting( 'ovt_email', array( 'type' => 'option'
) );
$wp_customize->add_setting( 'ovt_bool', array( 'type' => 'option'
) );
$wp_customize->add_setting( 'ovt_enum', array( 'type' => 'option'
) );
$wp_customize->add_section(
'option_validation_tests',
array(
'title' => __( 'Option Validation Test' ),
'capability' => 'manage_options',
)
);
$wp_customize->add_control(
'ovt_integer',
array(
'section' => 'option_validation_tests',
'type' => 'number',
'label' => __( 'Integer Option' ),
'description' => __( 'Enter a value greater than
or equal to 3.' ),
)
);
$wp_customize->add_control(
'ovt_email',
array(
'section' => 'option_validation_tests',
'type' => 'email',
'label' => __( 'Email Option' ),
'description' => __( 'Enter an email address.' ),
)
);
$wp_customize->add_control(
'ovt_bool',
array(
'section' => 'option_validation_tests',
'type' => 'checkbox',
'label' => __( 'Boolean Option' ),
'description' => __( 'Check this checkbox.' ),
)
);
$wp_customize->add_control(
'ovt_enum',
array(
'section' => 'option_validation_tests',
'type' => 'text',
'label' => __( 'Enum Option' ),
'description' => __( 'Enter either value1, value2,
or value3.' ),
)
);
}
add_action( 'customize_register', 'test_customize_register' );
}}}
Still looking for feedback on this, I consider it a valuable enhancement
that could make plugin authors' lives a lot easier.
It also opens up possibilities for further improvements: For example,
`$wp_customize->add_setting()` calls could automatically happen for
options that are registered because providing those manually in such a
case is often redundant. If someone registers a control with an option
identifier for an option that is registered and no
`$wp_customize->add_setting()` call is manually made, those could be
"auto-filled".
--
Ticket URL: <https://core.trac.wordpress.org/ticket/43208#comment:7>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform
More information about the wp-trac
mailing list