: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
return in_array( $maybe_bool, $valid_boolean_values, true );
if ( is_int( $maybe_bool ) ) {
return in_array( $maybe_bool, array( 0, 1 ), true );
* Determines if a given value is integer-like.
* @param mixed $maybe_integer The value being evaluated.
* @return bool True if an integer, otherwise false.
function rest_is_integer( $maybe_integer ) {
return is_numeric( $maybe_integer ) && round( (float) $maybe_integer ) === (float) $maybe_integer;
* Determines if a given value is array-like.
* @param mixed $maybe_array The value being evaluated.
function rest_is_array( $maybe_array ) {
if ( is_scalar( $maybe_array ) ) {
$maybe_array = wp_parse_list( $maybe_array );
return wp_is_numeric_array( $maybe_array );
* Converts an array-like value to an array.
* @param mixed $maybe_array The value being evaluated.
* @return array Returns the array extracted from the value.
function rest_sanitize_array( $maybe_array ) {
if ( is_scalar( $maybe_array ) ) {
return wp_parse_list( $maybe_array );
if ( ! is_array( $maybe_array ) ) {
// Normalize to numeric array so nothing unexpected is in the keys.
return array_values( $maybe_array );
* Determines if a given value is object-like.
* @param mixed $maybe_object The value being evaluated.
* @return bool True if object like, otherwise false.
function rest_is_object( $maybe_object ) {
if ( '' === $maybe_object ) {
if ( $maybe_object instanceof stdClass ) {
if ( $maybe_object instanceof JsonSerializable ) {
$maybe_object = $maybe_object->jsonSerialize();
return is_array( $maybe_object );
* Converts an object-like value to an array.
* @param mixed $maybe_object The value being evaluated.
* @return array Returns the object extracted from the value as an associative array.
function rest_sanitize_object( $maybe_object ) {
if ( '' === $maybe_object ) {
if ( $maybe_object instanceof stdClass ) {
return (array) $maybe_object;
if ( $maybe_object instanceof JsonSerializable ) {
$maybe_object = $maybe_object->jsonSerialize();
if ( ! is_array( $maybe_object ) ) {
* Gets the best type for a value.
* @param mixed $value The value to check.
* @param string[] $types The list of possible types.
* @return string The best matching type, an empty string if no types match.
function rest_get_best_type_for_value( $value, $types ) {
'array' => 'rest_is_array',
'object' => 'rest_is_object',
'integer' => 'rest_is_integer',
'number' => 'is_numeric',
'boolean' => 'rest_is_boolean',
* Both arrays and objects allow empty strings to be converted to their types.
* But the best answer for this type is a string.
if ( '' === $value && in_array( 'string', $types, true ) ) {
foreach ( $types as $type ) {
if ( isset( $checks[ $type ] ) && $checks[ $type ]( $value ) ) {
* Handles getting the best type for a multi-type schema.
* This is a wrapper for {@see rest_get_best_type_for_value()} that handles
* backward compatibility for schemas that use invalid types.
* @param mixed $value The value to check.
* @param array $args The schema array to use.
* @param string $param The parameter name, used in error messages.
function rest_handle_multi_type_schema( $value, $args, $param = '' ) {
$allowed_types = array( 'array', 'object', 'string', 'number', 'integer', 'boolean', 'null' );
$invalid_types = array_diff( $args['type'], $allowed_types );
/* translators: 1: Parameter, 2: List of allowed types. */
wp_sprintf( __( 'The "type" schema keyword for %1$s can only contain the built-in types: %2$l.' ), $param, $allowed_types ),
$best_type = rest_get_best_type_for_value( $value, $args['type'] );
if ( ! $invalid_types ) {
// Backward compatibility for previous behavior which allowed the value if there was an invalid type used.
$best_type = reset( $invalid_types );
* Checks if an array is made up of unique items.
* @param array $input_array The array to check.
* @return bool True if the array contains unique items, false otherwise.
function rest_validate_array_contains_unique_items( $input_array ) {
foreach ( $input_array as $item ) {
$stabilized = rest_stabilize_value( $item );
$key = serialize( $stabilized );
if ( ! isset( $seen[ $key ] ) ) {
* Stabilizes a value following JSON Schema semantics.
* For lists, order is preserved. For objects, properties are reordered alphabetically.
* @param mixed $value The value to stabilize. Must already be sanitized. Objects should have been converted to arrays.
* @return mixed The stabilized value.
function rest_stabilize_value( $value ) {
if ( is_scalar( $value ) || is_null( $value ) ) {
if ( is_object( $value ) ) {
_doing_it_wrong( __FUNCTION__, __( 'Cannot stabilize objects. Convert the object to an array first.' ), '5.5.0' );
foreach ( $value as $k => $v ) {
$value[ $k ] = rest_stabilize_value( $v );
* Validates if the JSON Schema pattern matches a value.
* @param string $pattern The pattern to match against.
* @param string $value The value to check.
* @return bool True if the pattern matches the given value, false otherwise.
function rest_validate_json_schema_pattern( $pattern, $value ) {
$escaped_pattern = str_replace( '#', '\\#', $pattern );
return 1 === preg_match( '#' . $escaped_pattern . '#u', $value );
* Finds the schema for a property using the patternProperties keyword.
* @param string $property The property name to check.
* @param array $args The schema array to use.
* @return array|null The schema of matching pattern property, or null if no patterns match.
function rest_find_matching_pattern_property_schema( $property, $args ) {
if ( isset( $args['patternProperties'] ) ) {
foreach ( $args['patternProperties'] as $pattern => $child_schema ) {
if ( rest_validate_json_schema_pattern( $pattern, $property ) ) {
* Formats a combining operation error into a WP_Error object.
* @param string $param The parameter name.
* @param array $error The error details.
function rest_format_combining_operation_error( $param, $error ) {
$position = $error['index'];
$reason = $error['error_object']->get_error_message();
if ( isset( $error['schema']['title'] ) ) {
$title = $error['schema']['title'];
'rest_no_matching_schema',
/* translators: 1: Parameter, 2: Schema title, 3: Reason. */
sprintf( __( '%1$s is not a valid %2$s. Reason: %3$s' ), $param, $title, $reason ),
array( 'position' => $position )
'rest_no_matching_schema',
/* translators: 1: Parameter, 2: Reason. */
sprintf( __( '%1$s does not match the expected format. Reason: %2$s' ), $param, $reason ),
array( 'position' => $position )
* Gets the error of combining operation.
* @param array $value The value to validate.
* @param string $param The parameter name, used in error messages.
* @param array $errors The errors array, to search for possible error.
* @return WP_Error The combining operation error.
function rest_get_combining_operation_error( $value, $param, $errors ) {
// If there is only one error, simply return it.
if ( 1 === count( $errors ) ) {
return rest_format_combining_operation_error( $param, $errors[0] );
// Filter out all errors related to type validation.
$filtered_errors = array();
foreach ( $errors as $error ) {
$error_code = $error['error_object']->get_error_code();
$error_data = $error['error_object']->get_error_data();
if ( 'rest_invalid_type' !== $error_code || ( isset( $error_data['param'] ) && $param !== $error_data['param'] ) ) {
$filtered_errors[] = $error;
// If there is only one error left, simply return it.
if ( 1 === count( $filtered_errors ) ) {
return rest_format_combining_operation_error( $param, $filtered_errors[0] );
// If there are only errors related to object validation, try choosing the most appropriate one.
if ( count( $filtered_errors ) > 1 && 'object' === $filtered_errors[0]['schema']['type'] ) {
foreach ( $filtered_errors as $error ) {
if ( isset( $error['schema']['properties'] ) ) {
$n = count( array_intersect_key( $error['schema']['properties'], $value ) );
if ( null !== $result ) {
return rest_format_combining_operation_error( $param, $result );
// If each schema has a title, include those titles in the error message.
$schema_titles = array();
foreach ( $errors as $error ) {
if ( isset( $error['schema']['title'] ) ) {
$schema_titles[] = $error['schema']['title'];
if ( count( $schema_titles ) === count( $errors ) ) {
/* translators: 1: Parameter, 2: Schema titles. */
return new WP_Error( 'rest_no_matching_schema', wp_sprintf( __( '%1$s is not a valid %2$l.' ), $param, $schema_titles ) );
/* translators: %s: Parameter. */
return new WP_Error( 'rest_no_matching_schema', sprintf( __( '%s does not match any of the expected formats.' ), $param ) );
* Finds the matching schema among the "anyOf" schemas.
* @param mixed $value The value to validate.
* @param array $args The schema array to use.
* @param string $param The parameter name, used in error messages.
* @return array|WP_Error The matching schema or WP_Error instance if all schemas do not match.
function rest_find_any_matching_schema( $value, $args, $param ) {
foreach ( $args['anyOf'] as $index => $schema ) {
if ( ! isset( $schema['type'] ) && isset( $args['type'] ) ) {
$schema['type'] = $args['type'];
$is_valid = rest_validate_value_from_schema( $value, $schema, $param );
if ( ! is_wp_error( $is_valid ) ) {
'error_object' => $is_valid,
return rest_get_combining_operation_error( $value, $param, $errors );
* Finds the matching schema among the "oneOf" schemas.
* @param mixed $value The value to validate.
* @param array $args The schema array to use.
* @param string $param The parameter name, used in error messages.
* @param bool $stop_after_first_match Optional. Whether the process should stop after the first successful match.
* @return array|WP_Error The matching schema or WP_Error instance if the number of matching schemas is not equal to one.
function rest_find_one_matching_schema( $value, $args, $param, $stop_after_first_match = false ) {
$matching_schemas = array();
foreach ( $args['oneOf'] as $index => $schema ) {
if ( ! isset( $schema['type'] ) && isset( $args['type'] ) ) {
$schema['type'] = $args['type'];
$is_valid = rest_validate_value_from_schema( $value, $schema, $param );
if ( ! is_wp_error( $is_valid ) ) {
if ( $stop_after_first_match ) {
$matching_schemas[] = array(
'schema_object' => $schema,
'error_object' => $is_valid,
if ( ! $matching_schemas ) {
return rest_get_combining_operation_error( $value, $param, $errors );
if ( count( $matching_schemas ) > 1 ) {
$schema_positions = array();
$schema_titles = array();
foreach ( $matching_schemas as $schema ) {
$schema_positions[] = $schema['index'];
if ( isset( $schema['schema_object']['title'] ) ) {
$schema_titles[] = $schema['schema_object']['title'];
// If each schema has a title, include those titles in the error message.
if ( count( $schema_titles ) === count( $matching_schemas ) ) {
'rest_one_of_multiple_matches',
/* translators: 1: Parameter, 2: Schema titles. */
wp_sprintf( __( '%1$s matches %2$l, but should match only one.' ), $param, $schema_titles ),
array( 'positions' => $schema_positions )
'rest_one_of_multiple_matches',
/* translators: %s: Parameter. */
sprintf( __( '%s matches more than one of the expected formats.' ), $param ),
array( 'positions' => $schema_positions )
return $matching_schemas[0]['schema_object'];
* Checks the equality of two values, following JSON Schema semantics.
* Property order is ignored for objects.
* Values must have been previously sanitized/coerced to their native types.