diff --git a/src/wp-includes/option.php b/src/wp-includes/option.php index f58bc6c5bf..5311df507a 100644 --- a/src/wp-includes/option.php +++ b/src/wp-includes/option.php @@ -56,6 +56,9 @@ function get_option( $option, $default = false ) { if ( defined( 'WP_SETUP_CONFIG' ) ) return false; + // Distinguish between `false` as a default, and not passing one. + $passed_default = func_num_args() > 1; + if ( ! wp_installing() ) { // prevent non-existent options from triggering multiple queries $notoptions = wp_cache_get( 'notoptions', 'options' ); @@ -67,12 +70,14 @@ function get_option( $option, $default = false ) { * * @since 3.4.0 * @since 4.4.0 The `$option` parameter was added. + * @since 4.7.0 The `$passed_default` parameter was added to distinguish between a `false` value and the default parameter value. * * @param mixed $default The default value to return if the option does not exist * in the database. * @param string $option Option name. + * @param bool $passed_default Was `get_option()` passed a default value? */ - return apply_filters( "default_option_{$option}", $default, $option ); + return apply_filters( "default_option_{$option}", $default, $option, $passed_default ); } $alloptions = wp_load_alloptions(); @@ -97,7 +102,7 @@ function get_option( $option, $default = false ) { wp_cache_set( 'notoptions', $notoptions, 'options' ); /** This filter is documented in wp-includes/option.php */ - return apply_filters( 'default_option_' . $option, $default, $option ); + return apply_filters( 'default_option_' . $option, $default, $option, $passed_default ); } } } @@ -109,7 +114,7 @@ function get_option( $option, $default = false ) { $value = $row->option_value; } else { /** This filter is documented in wp-includes/option.php */ - return apply_filters( 'default_option_' . $option, $default, $option ); + return apply_filters( 'default_option_' . $option, $default, $option, $passed_default ); } } @@ -1835,6 +1840,7 @@ function register_initial_settings() { * @type string $description A description of the data attached to this setting. * @type callable $sanitize_callback A callback function that sanitizes the option's value. * @type bool $show_in_rest Whether data associated with this setting should be included in the REST API. + * @type mixed $default Default value when calling `get_option()`. * } */ function register_setting( $option_group, $option_name, $args = array() ) { @@ -1886,6 +1892,9 @@ function register_setting( $option_group, $option_name, $args = array() ) { if ( ! empty( $args['sanitize_callback'] ) ) { add_filter( "sanitize_option_{$option_name}", $args['sanitize_callback'] ); } + if ( array_key_exists( 'default', $args ) ) { + add_filter( "default_option_{$option_name}", 'filter_default_option', 10, 3 ); + } $wp_registered_settings[ $option_name ] = $args; } @@ -1950,3 +1959,29 @@ function get_registered_settings() { return $wp_registered_settings; } + +/** + * Filter the default value for the option. + * + * For settings which register a default setting in `register_setting()`, this + * function is added as a filter to `default_option_{$option}`. + * + * @since 4.7.0 + * + * @param mixed $default Existing default value to return. + * @param string $option Option name. + * @param bool $passed_default Was `get_option()` passed a default value? + * @return mixed Filtered default value. + */ +function filter_default_option( $default, $option, $passed_default ) { + if ( $passed_default ) { + return $default; + } + + $registered = get_registered_settings(); + if ( empty( $registered[ $option ] ) ) { + return $default; + } + + return $registered[ $option ]['default']; +} diff --git a/tests/phpunit/tests/option/registration.php b/tests/phpunit/tests/option/registration.php index 29958035db..7e18e09afb 100644 --- a/tests/phpunit/tests/option/registration.php +++ b/tests/phpunit/tests/option/registration.php @@ -39,6 +39,28 @@ class Tests_Option_Registration extends WP_UnitTestCase { return 'S-M-R-T'; } + /** + * @ticket 38176 + */ + public function test_register_with_default() { + register_setting( 'test_group', 'test_default', array( + 'default' => 'Fuck Cancer' + )); + + $this->assertEquals( 'Fuck Cancer', get_option( 'test_default' ) ); + } + + /** + * @ticket 38176 + */ + public function test_register_with_default_override() { + register_setting( 'test_group', 'test_default', array( + 'default' => 'Fuck Cancer' + )); + + $this->assertEquals( 'Fuck Leukemia', get_option( 'test_default', 'Fuck Leukemia' ) ); + } + /** * @expectedDeprecated register_setting */