121 * @param mixed $value Value to prepare. |
121 * @param mixed $value Value to prepare. |
122 * @param array $schema Schema to match. |
122 * @param array $schema Schema to match. |
123 * @return mixed The prepared value. |
123 * @return mixed The prepared value. |
124 */ |
124 */ |
125 protected function prepare_value( $value, $schema ) { |
125 protected function prepare_value( $value, $schema ) { |
126 // If the value is not valid by the schema, set the value to null. Null |
126 /* |
127 // values are specifcally non-destructive so this will not cause overwriting |
127 * If the value is not valid by the schema, set the value to null. |
128 // the current invalid value to null. |
128 * Null values are specifically non-destructive, so this will not cause |
|
129 * overwriting the current invalid value to null. |
|
130 */ |
129 if ( is_wp_error( rest_validate_value_from_schema( $value, $schema ) ) ) { |
131 if ( is_wp_error( rest_validate_value_from_schema( $value, $schema ) ) ) { |
130 return null; |
132 return null; |
131 } |
133 } |
|
134 |
132 return rest_sanitize_value_from_schema( $value, $schema ); |
135 return rest_sanitize_value_from_schema( $value, $schema ); |
133 } |
136 } |
134 |
137 |
135 /** |
138 /** |
136 * Updates settings for the settings object. |
139 * Updates settings for the settings object. |
188 * database. |
191 * database. |
189 */ |
192 */ |
190 if ( is_wp_error( rest_validate_value_from_schema( get_option( $args['option_name'], false ), $args['schema'] ) ) ) { |
193 if ( is_wp_error( rest_validate_value_from_schema( get_option( $args['option_name'], false ), $args['schema'] ) ) ) { |
191 return new WP_Error( |
194 return new WP_Error( |
192 'rest_invalid_stored_value', |
195 'rest_invalid_stored_value', |
|
196 /* translators: %s: Property name. */ |
193 sprintf( __( 'The %s property has an invalid stored value, and cannot be updated to null.' ), $name ), |
197 sprintf( __( 'The %s property has an invalid stored value, and cannot be updated to null.' ), $name ), |
194 array( 'status' => 500 ) |
198 array( 'status' => 500 ) |
195 ); |
199 ); |
196 } |
200 } |
197 |
201 |
245 if ( empty( $rest_args['schema']['type'] ) ) { |
249 if ( empty( $rest_args['schema']['type'] ) ) { |
246 continue; |
250 continue; |
247 } |
251 } |
248 |
252 |
249 /* |
253 /* |
250 * Whitelist the supported types for settings, as we don't want invalid types |
254 * Allow the supported types for settings, as we don't want invalid types |
251 * to be updated with arbitrary values that we can't do decent sanitizing for. |
255 * to be updated with arbitrary values that we can't do decent sanitizing for. |
252 */ |
256 */ |
253 if ( ! in_array( $rest_args['schema']['type'], array( 'number', 'integer', 'string', 'boolean', 'array', 'object' ), true ) ) { |
257 if ( ! in_array( $rest_args['schema']['type'], array( 'number', 'integer', 'string', 'boolean', 'array', 'object' ), true ) ) { |
254 continue; |
258 continue; |
255 } |
259 } |
268 * @since 4.7.0 |
272 * @since 4.7.0 |
269 * |
273 * |
270 * @return array Item schema data. |
274 * @return array Item schema data. |
271 */ |
275 */ |
272 public function get_item_schema() { |
276 public function get_item_schema() { |
|
277 if ( $this->schema ) { |
|
278 return $this->add_additional_fields_schema( $this->schema ); |
|
279 } |
|
280 |
273 $options = $this->get_registered_options(); |
281 $options = $this->get_registered_options(); |
274 |
282 |
275 $schema = array( |
283 $schema = array( |
276 '$schema' => 'http://json-schema.org/draft-04/schema#', |
284 '$schema' => 'http://json-schema.org/draft-04/schema#', |
277 'title' => 'settings', |
285 'title' => 'settings', |
284 $schema['properties'][ $option_name ]['arg_options'] = array( |
292 $schema['properties'][ $option_name ]['arg_options'] = array( |
285 'sanitize_callback' => array( $this, 'sanitize_callback' ), |
293 'sanitize_callback' => array( $this, 'sanitize_callback' ), |
286 ); |
294 ); |
287 } |
295 } |
288 |
296 |
289 return $this->add_additional_fields_schema( $schema ); |
297 $this->schema = $schema; |
|
298 |
|
299 return $this->add_additional_fields_schema( $this->schema ); |
290 } |
300 } |
291 |
301 |
292 /** |
302 /** |
293 * Custom sanitize callback used for all options to allow the use of 'null'. |
303 * Custom sanitize callback used for all options to allow the use of 'null'. |
294 * |
304 * |
295 * By default, the schema of settings will throw an error if a value is set to |
305 * By default, the schema of settings will throw an error if a value is set to |
296 * `null` as it's not a valid value for something like "type => string". We |
306 * `null` as it's not a valid value for something like "type => string". We |
297 * provide a wrapper sanitizer to whitelist the use of `null`. |
307 * provide a wrapper sanitizer to allow the use of `null`. |
298 * |
308 * |
299 * @since 4.7.0 |
309 * @since 4.7.0 |
300 * |
310 * |
301 * @param mixed $value The value for the setting. |
311 * @param mixed $value The value for the setting. |
302 * @param WP_REST_Request $request The request object. |
312 * @param WP_REST_Request $request The request object. |
303 * @param string $param The parameter name. |
313 * @param string $param The parameter name. |
304 * @return mixed|WP_Error |
314 * @return mixed|WP_Error |
305 */ |
315 */ |
306 public function sanitize_callback( $value, $request, $param ) { |
316 public function sanitize_callback( $value, $request, $param ) { |
307 if ( is_null( $value ) ) { |
317 if ( is_null( $value ) ) { |
308 return $value; |
318 return $value; |
309 } |
319 } |
|
320 |
310 return rest_parse_request_arg( $value, $request, $param ); |
321 return rest_parse_request_arg( $value, $request, $param ); |
311 } |
322 } |
312 |
323 |
313 /** |
324 /** |
314 * Recursively add additionalProperties = false to all objects in a schema. |
325 * Recursively add additionalProperties = false to all objects in a schema. |
326 switch ( $schema['type'] ) { |
337 switch ( $schema['type'] ) { |
327 case 'object': |
338 case 'object': |
328 foreach ( $schema['properties'] as $key => $child_schema ) { |
339 foreach ( $schema['properties'] as $key => $child_schema ) { |
329 $schema['properties'][ $key ] = $this->set_additional_properties_to_false( $child_schema ); |
340 $schema['properties'][ $key ] = $this->set_additional_properties_to_false( $child_schema ); |
330 } |
341 } |
|
342 |
331 $schema['additionalProperties'] = false; |
343 $schema['additionalProperties'] = false; |
332 break; |
344 break; |
333 case 'array': |
345 case 'array': |
334 $schema['items'] = $this->set_additional_properties_to_false( $schema['items'] ); |
346 $schema['items'] = $this->set_additional_properties_to_false( $schema['items'] ); |
335 break; |
347 break; |