diff --git a/src/wp-includes/option.php b/src/wp-includes/option.php index 3efdcb20cb..cb4852c644 100644 --- a/src/wp-includes/option.php +++ b/src/wp-includes/option.php @@ -2104,12 +2104,14 @@ function register_initial_settings() { * @param array $args { * Data used to describe the setting when registered. * - * @type string $type The type of data associated with this setting. - * Valid values are 'string', 'boolean', 'integer', and 'number'. - * @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()`. + * @type string $type The type of data associated with this setting. + * Valid values are 'string', 'boolean', 'integer', 'number', 'array', and 'object'. + * @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|array $show_in_rest Whether data associated with this setting should be included in the REST API. + * When registering complex settings, this argument may optionally be an + * array with a 'schema' key. + * @type mixed $default Default value when calling `get_option()`. * } */ function register_setting( $option_group, $option_name, $args = array() ) { @@ -2143,6 +2145,11 @@ function register_setting( $option_group, $option_name, $args = array() ) { $args = apply_filters( 'register_setting_args', $args, $defaults, $option_group, $option_name ); $args = wp_parse_args( $args, $defaults ); + // Require an item schema when registering settings with an array type. + if ( false !== $args['show_in_rest'] && 'array' === $args['type'] && ( ! is_array( $args['show_in_rest'] ) || ! isset( $args['show_in_rest']['schema']['items'] ) ) ) { + _doing_it_wrong( __FUNCTION__, __( 'When registering an "array" setting to show in the REST API, you must specify the schema for each array item in "show_in_rest.schema.items".' ), '5.4.0' ); + } + if ( ! is_array( $wp_registered_settings ) ) { $wp_registered_settings = array(); } diff --git a/tests/phpunit/tests/rest-api/rest-settings-controller.php b/tests/phpunit/tests/rest-api/rest-settings-controller.php index 91db9adcac..9f96e83aad 100644 --- a/tests/phpunit/tests/rest-api/rest-settings-controller.php +++ b/tests/phpunit/tests/rest-api/rest-settings-controller.php @@ -38,6 +38,14 @@ class WP_Test_REST_Settings_Controller extends WP_Test_REST_Controller_Testcase $this->endpoint = new WP_REST_Settings_Controller(); } + public function tearDown() { + parent::tearDown(); + + if ( isset( get_registered_settings()['mycustomarraysetting'] ) ) { + unregister_setting( 'somegroup', 'mycustomarraysetting' ); + } + } + public function test_register_routes() { $routes = rest_get_server()->get_routes(); $this->assertArrayHasKey( '/wp/v2/settings', $routes ); @@ -649,4 +657,58 @@ class WP_Test_REST_Settings_Controller extends WP_Test_REST_Controller_Testcase public function test_get_item_schema() { } + + /** + * @ticket 42875 + */ + public function test_register_setting_issues_doing_it_wrong_when_show_in_rest_is_true() { + $this->setExpectedIncorrectUsage( 'register_setting' ); + + register_setting( + 'somegroup', + 'mycustomarraysetting', + array( + 'type' => 'array', + 'show_in_rest' => true, + ) + ); + } + + /** + * @ticket 42875 + */ + public function test_register_setting_issues_doing_it_wrong_when_show_in_rest_omits_schema() { + $this->setExpectedIncorrectUsage( 'register_setting' ); + + register_setting( + 'somegroup', + 'mycustomarraysetting', + array( + 'type' => 'array', + 'show_in_rest' => array( + 'prepare_callback' => 'rest_sanitize_value_from_schema', + ), + ) + ); + } + + /** + * @ticket 42875 + */ + public function test_register_setting_issues_doing_it_wrong_when_show_in_rest_omits_schema_items() { + $this->setExpectedIncorrectUsage( 'register_setting' ); + + register_setting( + 'somegroup', + 'mycustomarraysetting', + array( + 'type' => 'array', + 'show_in_rest' => array( + 'schema' => array( + 'default' => array( 'Hi!' ), + ), + ), + ) + ); + } }