rest_validate_value_from_schema

The timeline below displays how wordpress function rest_validate_value_from_schema has changed across different WordPress versions. If a version is not listed, refer to the next available version below.

WordPress Version: 6.3

/**
 * Validate a value based on a schema.
 *
 * @since 4.7.0
 * @since 4.9.0 Support the "object" type.
 * @since 5.2.0 Support validating "additionalProperties" against a schema.
 * @since 5.3.0 Support multiple types.
 * @since 5.4.0 Convert an empty string to an empty object.
 * @since 5.5.0 Add the "uuid" and "hex-color" formats.
 *              Support the "minLength", "maxLength" and "pattern" keywords for strings.
 *              Support the "minItems", "maxItems" and "uniqueItems" keywords for arrays.
 *              Validate required properties.
 * @since 5.6.0 Support the "minProperties" and "maxProperties" keywords for objects.
 *              Support the "multipleOf" keyword for numbers and integers.
 *              Support the "patternProperties" keyword for objects.
 *              Support the "anyOf" and "oneOf" keywords.
 *
 * @param mixed  $value The value to validate.
 * @param array  $args  Schema array to use for validation.
 * @param string $param The parameter name, used in error messages.
 * @return true|WP_Error
 */
function rest_validate_value_from_schema($value, $args, $param = '')
{
    if (isset($args['anyOf'])) {
        $matching_schema = rest_find_any_matching_schema($value, $args, $param);
        if (is_wp_error($matching_schema)) {
            return $matching_schema;
        }
        if (!isset($args['type']) && isset($matching_schema['type'])) {
            $args['type'] = $matching_schema['type'];
        }
    }
    if (isset($args['oneOf'])) {
        $matching_schema = rest_find_one_matching_schema($value, $args, $param);
        if (is_wp_error($matching_schema)) {
            return $matching_schema;
        }
        if (!isset($args['type']) && isset($matching_schema['type'])) {
            $args['type'] = $matching_schema['type'];
        }
    }
    $allowed_types = array('array', 'object', 'string', 'number', 'integer', 'boolean', 'null');
    if (!isset($args['type'])) {
        /* translators: %s: Parameter. */
        _doing_it_wrong(__FUNCTION__, sprintf(__('The "type" schema keyword for %s is required.'), $param), '5.5.0');
    }
    if (is_array($args['type'])) {
        $best_type = rest_handle_multi_type_schema($value, $args, $param);
        if (!$best_type) {
            return new WP_Error(
                'rest_invalid_type',
                /* translators: 1: Parameter, 2: List of types. */
                sprintf(__('%1$s is not of type %2$s.'), $param, implode(',', $args['type'])),
                array('param' => $param)
            );
        }
        $args['type'] = $best_type;
    }
    if (!in_array($args['type'], $allowed_types, true)) {
        _doing_it_wrong(
            __FUNCTION__,
            /* translators: 1: Parameter, 2: The list of allowed types. */
            wp_sprintf(__('The "type" schema keyword for %1$s can only be one of the built-in types: %2$l.'), $param, $allowed_types),
            '5.5.0'
        );
    }
    switch ($args['type']) {
        case 'null':
            $is_valid = rest_validate_null_value_from_schema($value, $param);
            break;
        case 'boolean':
            $is_valid = rest_validate_boolean_value_from_schema($value, $param);
            break;
        case 'object':
            $is_valid = rest_validate_object_value_from_schema($value, $args, $param);
            break;
        case 'array':
            $is_valid = rest_validate_array_value_from_schema($value, $args, $param);
            break;
        case 'number':
            $is_valid = rest_validate_number_value_from_schema($value, $args, $param);
            break;
        case 'string':
            $is_valid = rest_validate_string_value_from_schema($value, $args, $param);
            break;
        case 'integer':
            $is_valid = rest_validate_integer_value_from_schema($value, $args, $param);
            break;
        default:
            $is_valid = true;
            break;
    }
    if (is_wp_error($is_valid)) {
        return $is_valid;
    }
    if (!empty($args['enum'])) {
        $enum_contains_value = rest_validate_enum($value, $args, $param);
        if (is_wp_error($enum_contains_value)) {
            return $enum_contains_value;
        }
    }
    /*
     * The "format" keyword should only be applied to strings. However, for backward compatibility,
     * we allow the "format" keyword if the type keyword was not specified, or was set to an invalid value.
     */
    if (isset($args['format']) && (!isset($args['type']) || 'string' === $args['type'] || !in_array($args['type'], $allowed_types, true))) {
        switch ($args['format']) {
            case 'hex-color':
                if (!rest_parse_hex_color($value)) {
                    return new WP_Error('rest_invalid_hex_color', __('Invalid hex color.'));
                }
                break;
            case 'date-time':
                if (!rest_parse_date($value)) {
                    return new WP_Error('rest_invalid_date', __('Invalid date.'));
                }
                break;
            case 'email':
                if (!is_email($value)) {
                    return new WP_Error('rest_invalid_email', __('Invalid email address.'));
                }
                break;
            case 'ip':
                if (!rest_is_ip_address($value)) {
                    /* translators: %s: IP address. */
                    return new WP_Error('rest_invalid_ip', sprintf(__('%s is not a valid IP address.'), $param));
                }
                break;
            case 'uuid':
                if (!wp_is_uuid($value)) {
                    /* translators: %s: The name of a JSON field expecting a valid UUID. */
                    return new WP_Error('rest_invalid_uuid', sprintf(__('%s is not a valid UUID.'), $param));
                }
                break;
        }
    }
    return true;
}

WordPress Version: 5.7

/**
 * Validate a value based on a schema.
 *
 * @since 4.7.0
 * @since 4.9.0 Support the "object" type.
 * @since 5.2.0 Support validating "additionalProperties" against a schema.
 * @since 5.3.0 Support multiple types.
 * @since 5.4.0 Convert an empty string to an empty object.
 * @since 5.5.0 Add the "uuid" and "hex-color" formats.
 *              Support the "minLength", "maxLength" and "pattern" keywords for strings.
 *              Support the "minItems", "maxItems" and "uniqueItems" keywords for arrays.
 *              Validate required properties.
 * @since 5.6.0 Support the "minProperties" and "maxProperties" keywords for objects.
 *              Support the "multipleOf" keyword for numbers and integers.
 *              Support the "patternProperties" keyword for objects.
 *              Support the "anyOf" and "oneOf" keywords.
 *
 * @param mixed  $value The value to validate.
 * @param array  $args  Schema array to use for validation.
 * @param string $param The parameter name, used in error messages.
 * @return true|WP_Error
 */
function rest_validate_value_from_schema($value, $args, $param = '')
{
    if (isset($args['anyOf'])) {
        $matching_schema = rest_find_any_matching_schema($value, $args, $param);
        if (is_wp_error($matching_schema)) {
            return $matching_schema;
        }
        if (!isset($args['type']) && isset($matching_schema['type'])) {
            $args['type'] = $matching_schema['type'];
        }
    }
    if (isset($args['oneOf'])) {
        $matching_schema = rest_find_one_matching_schema($value, $args, $param);
        if (is_wp_error($matching_schema)) {
            return $matching_schema;
        }
        if (!isset($args['type']) && isset($matching_schema['type'])) {
            $args['type'] = $matching_schema['type'];
        }
    }
    $allowed_types = array('array', 'object', 'string', 'number', 'integer', 'boolean', 'null');
    if (!isset($args['type'])) {
        /* translators: %s: Parameter. */
        _doing_it_wrong(__FUNCTION__, sprintf(__('The "type" schema keyword for %s is required.'), $param), '5.5.0');
    }
    if (is_array($args['type'])) {
        $best_type = rest_handle_multi_type_schema($value, $args, $param);
        if (!$best_type) {
            return new WP_Error(
                'rest_invalid_type',
                /* translators: 1: Parameter, 2: List of types. */
                sprintf(__('%1$s is not of type %2$s.'), $param, implode(',', $args['type'])),
                array('param' => $param)
            );
        }
        $args['type'] = $best_type;
    }
    if (!in_array($args['type'], $allowed_types, true)) {
        _doing_it_wrong(
            __FUNCTION__,
            /* translators: 1: Parameter, 2: The list of allowed types. */
            wp_sprintf(__('The "type" schema keyword for %1$s can only be one of the built-in types: %2$l.'), $param, $allowed_types),
            '5.5.0'
        );
    }
    switch ($args['type']) {
        case 'null':
            $is_valid = rest_validate_null_value_from_schema($value, $param);
            break;
        case 'boolean':
            $is_valid = rest_validate_boolean_value_from_schema($value, $param);
            break;
        case 'object':
            $is_valid = rest_validate_object_value_from_schema($value, $args, $param);
            break;
        case 'array':
            $is_valid = rest_validate_array_value_from_schema($value, $args, $param);
            break;
        case 'number':
            $is_valid = rest_validate_number_value_from_schema($value, $args, $param);
            break;
        case 'string':
            $is_valid = rest_validate_string_value_from_schema($value, $args, $param);
            break;
        case 'integer':
            $is_valid = rest_validate_integer_value_from_schema($value, $args, $param);
            break;
        default:
            $is_valid = true;
            break;
    }
    if (is_wp_error($is_valid)) {
        return $is_valid;
    }
    if (!empty($args['enum'])) {
        $enum_contains_value = rest_validate_enum($value, $args, $param);
        if (is_wp_error($enum_contains_value)) {
            return $enum_contains_value;
        }
    }
    // The "format" keyword should only be applied to strings. However, for backward compatibility,
    // we allow the "format" keyword if the type keyword was not specified, or was set to an invalid value.
    if (isset($args['format']) && (!isset($args['type']) || 'string' === $args['type'] || !in_array($args['type'], $allowed_types, true))) {
        switch ($args['format']) {
            case 'hex-color':
                if (!rest_parse_hex_color($value)) {
                    return new WP_Error('rest_invalid_hex_color', __('Invalid hex color.'));
                }
                break;
            case 'date-time':
                if (!rest_parse_date($value)) {
                    return new WP_Error('rest_invalid_date', __('Invalid date.'));
                }
                break;
            case 'email':
                if (!is_email($value)) {
                    return new WP_Error('rest_invalid_email', __('Invalid email address.'));
                }
                break;
            case 'ip':
                if (!rest_is_ip_address($value)) {
                    /* translators: %s: IP address. */
                    return new WP_Error('rest_invalid_ip', sprintf(__('%s is not a valid IP address.'), $param));
                }
                break;
            case 'uuid':
                if (!wp_is_uuid($value)) {
                    /* translators: %s: The name of a JSON field expecting a valid UUID. */
                    return new WP_Error('rest_invalid_uuid', sprintf(__('%s is not a valid UUID.'), $param));
                }
                break;
        }
    }
    return true;
}

WordPress Version: 5.6

/**
 * Validate a value based on a schema.
 *
 * @since 4.7.0
 * @since 4.9.0 Support the "object" type.
 * @since 5.2.0 Support validating "additionalProperties" against a schema.
 * @since 5.3.0 Support multiple types.
 * @since 5.4.0 Convert an empty string to an empty object.
 * @since 5.5.0 Add the "uuid" and "hex-color" formats.
 *              Support the "minLength", "maxLength" and "pattern" keywords for strings.
 *              Support the "minItems", "maxItems" and "uniqueItems" keywords for arrays.
 *              Validate required properties.
 * @since 5.6.0 Support the "minProperties" and "maxProperties" keywords for objects.
 *              Support the "multipleOf" keyword for numbers and integers.
 *              Support the "patternProperties" keyword for objects.
 *              Support the "anyOf" and "oneOf" keywords.
 *
 * @param mixed  $value The value to validate.
 * @param array  $args  Schema array to use for validation.
 * @param string $param The parameter name, used in error messages.
 * @return true|WP_Error
 */
function rest_validate_value_from_schema($value, $args, $param = '')
{
    if (isset($args['anyOf'])) {
        $matching_schema = rest_find_any_matching_schema($value, $args, $param);
        if (is_wp_error($matching_schema)) {
            return $matching_schema;
        }
        if (!isset($args['type']) && isset($matching_schema['type'])) {
            $args['type'] = $matching_schema['type'];
        }
    }
    if (isset($args['oneOf'])) {
        $matching_schema = rest_find_one_matching_schema($value, $args, $param);
        if (is_wp_error($matching_schema)) {
            return $matching_schema;
        }
        if (!isset($args['type']) && isset($matching_schema['type'])) {
            $args['type'] = $matching_schema['type'];
        }
    }
    $allowed_types = array('array', 'object', 'string', 'number', 'integer', 'boolean', 'null');
    if (!isset($args['type'])) {
        /* translators: %s: Parameter. */
        _doing_it_wrong(__FUNCTION__, sprintf(__('The "type" schema keyword for %s is required.'), $param), '5.5.0');
    }
    if (is_array($args['type'])) {
        $best_type = rest_handle_multi_type_schema($value, $args, $param);
        if (!$best_type) {
            return new WP_Error(
                'rest_invalid_type',
                /* translators: 1: Parameter, 2: List of types. */
                sprintf(__('%1$s is not of type %2$s.'), $param, implode(',', $args['type'])),
                array('param' => $param)
            );
        }
        $args['type'] = $best_type;
    }
    if (!in_array($args['type'], $allowed_types, true)) {
        _doing_it_wrong(
            __FUNCTION__,
            /* translators: 1: Parameter, 2: The list of allowed types. */
            wp_sprintf(__('The "type" schema keyword for %1$s can only be one of the built-in types: %2$l.'), $param, $allowed_types),
            '5.5.0'
        );
    }
    if ('array' === $args['type']) {
        if (!rest_is_array($value)) {
            return new WP_Error(
                'rest_invalid_type',
                /* translators: 1: Parameter, 2: Type name. */
                sprintf(__('%1$s is not of type %2$s.'), $param, 'array'),
                array('param' => $param)
            );
        }
        $value = rest_sanitize_array($value);
        if (isset($args['items'])) {
            foreach ($value as $index => $v) {
                $is_valid = rest_validate_value_from_schema($v, $args['items'], $param . '[' . $index . ']');
                if (is_wp_error($is_valid)) {
                    return $is_valid;
                }
            }
        }
        if (isset($args['minItems']) && count($value) < $args['minItems']) {
            return new WP_Error('rest_invalid_param', sprintf(
                /* translators: 1: Parameter, 2: Number. */
                _n('%1$s must contain at least %2$s item.', '%1$s must contain at least %2$s items.', $args['minItems']),
                $param,
                number_format_i18n($args['minItems'])
            ));
        }
        if (isset($args['maxItems']) && count($value) > $args['maxItems']) {
            return new WP_Error('rest_invalid_param', sprintf(
                /* translators: 1: Parameter, 2: Number. */
                _n('%1$s must contain at most %2$s item.', '%1$s must contain at most %2$s items.', $args['maxItems']),
                $param,
                number_format_i18n($args['maxItems'])
            ));
        }
        if (!empty($args['uniqueItems']) && !rest_validate_array_contains_unique_items($value)) {
            /* translators: 1: Parameter. */
            return new WP_Error('rest_invalid_param', sprintf(__('%1$s has duplicate items.'), $param));
        }
    }
    if ('object' === $args['type']) {
        if (!rest_is_object($value)) {
            return new WP_Error(
                'rest_invalid_type',
                /* translators: 1: Parameter, 2: Type name. */
                sprintf(__('%1$s is not of type %2$s.'), $param, 'object'),
                array('param' => $param)
            );
        }
        $value = rest_sanitize_object($value);
        if (isset($args['required']) && is_array($args['required'])) {
            // schema version 4
            foreach ($args['required'] as $name) {
                if (!array_key_exists($name, $value)) {
                    /* translators: 1: Property of an object, 2: Parameter. */
                    return new WP_Error('rest_property_required', sprintf(__('%1$s is a required property of %2$s.'), $name, $param));
                }
            }
        } elseif (isset($args['properties'])) {
            // schema version 3
            foreach ($args['properties'] as $name => $property) {
                if (isset($property['required']) && true === $property['required'] && !array_key_exists($name, $value)) {
                    /* translators: 1: Property of an object, 2: Parameter. */
                    return new WP_Error('rest_property_required', sprintf(__('%1$s is a required property of %2$s.'), $name, $param));
                }
            }
        }
        foreach ($value as $property => $v) {
            if (isset($args['properties'][$property])) {
                $is_valid = rest_validate_value_from_schema($v, $args['properties'][$property], $param . '[' . $property . ']');
                if (is_wp_error($is_valid)) {
                    return $is_valid;
                }
                continue;
            }
            $pattern_property_schema = rest_find_matching_pattern_property_schema($property, $args);
            if (null !== $pattern_property_schema) {
                $is_valid = rest_validate_value_from_schema($v, $pattern_property_schema, $param . '[' . $property . ']');
                if (is_wp_error($is_valid)) {
                    return $is_valid;
                }
                continue;
            }
            if (isset($args['additionalProperties'])) {
                if (false === $args['additionalProperties']) {
                    /* translators: %s: Property of an object. */
                    return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not a valid property of Object.'), $property));
                }
                if (is_array($args['additionalProperties'])) {
                    $is_valid = rest_validate_value_from_schema($v, $args['additionalProperties'], $param . '[' . $property . ']');
                    if (is_wp_error($is_valid)) {
                        return $is_valid;
                    }
                }
            }
        }
        if (isset($args['minProperties']) && count($value) < $args['minProperties']) {
            return new WP_Error('rest_invalid_param', sprintf(
                /* translators: 1: Parameter, 2: Number. */
                _n('%1$s must contain at least %2$s property.', '%1$s must contain at least %2$s properties.', $args['minProperties']),
                $param,
                number_format_i18n($args['minProperties'])
            ));
        }
        if (isset($args['maxProperties']) && count($value) > $args['maxProperties']) {
            return new WP_Error('rest_invalid_param', sprintf(
                /* translators: 1: Parameter, 2: Number. */
                _n('%1$s must contain at most %2$s property.', '%1$s must contain at most %2$s properties.', $args['maxProperties']),
                $param,
                number_format_i18n($args['maxProperties'])
            ));
        }
    }
    if ('null' === $args['type']) {
        if (null !== $value) {
            return new WP_Error(
                'rest_invalid_type',
                /* translators: 1: Parameter, 2: Type name. */
                sprintf(__('%1$s is not of type %2$s.'), $param, 'null'),
                array('param' => $param)
            );
        }
        return true;
    }
    if (!empty($args['enum'])) {
        if (!in_array($value, $args['enum'], true)) {
            /* translators: 1: Parameter, 2: List of valid values. */
            return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not one of %2$s.'), $param, implode(', ', $args['enum'])));
        }
    }
    if (in_array($args['type'], array('integer', 'number'), true)) {
        if (!is_numeric($value)) {
            return new WP_Error(
                'rest_invalid_type',
                /* translators: 1: Parameter, 2: Type name. */
                sprintf(__('%1$s is not of type %2$s.'), $param, $args['type']),
                array('param' => $param)
            );
        }
        if (isset($args['multipleOf']) && fmod($value, $args['multipleOf']) !== 0.0) {
            /* translators: 1: Parameter, 2: Multiplier. */
            return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be a multiple of %2$s.'), $param, $args['multipleOf']));
        }
    }
    if ('integer' === $args['type'] && !rest_is_integer($value)) {
        return new WP_Error(
            'rest_invalid_type',
            /* translators: 1: Parameter, 2: Type name. */
            sprintf(__('%1$s is not of type %2$s.'), $param, 'integer'),
            array('param' => $param)
        );
    }
    if ('boolean' === $args['type'] && !rest_is_boolean($value)) {
        return new WP_Error(
            'rest_invalid_type',
            /* translators: 1: Parameter, 2: Type name. */
            sprintf(__('%1$s is not of type %2$s.'), $param, 'boolean'),
            array('param' => $param)
        );
    }
    if ('string' === $args['type']) {
        if (!is_string($value)) {
            return new WP_Error(
                'rest_invalid_type',
                /* translators: 1: Parameter, 2: Type name. */
                sprintf(__('%1$s is not of type %2$s.'), $param, 'string'),
                array('param' => $param)
            );
        }
        if (isset($args['minLength']) && mb_strlen($value) < $args['minLength']) {
            return new WP_Error('rest_invalid_param', sprintf(
                /* translators: 1: Parameter, 2: Number of characters. */
                _n('%1$s must be at least %2$s character long.', '%1$s must be at least %2$s characters long.', $args['minLength']),
                $param,
                number_format_i18n($args['minLength'])
            ));
        }
        if (isset($args['maxLength']) && mb_strlen($value) > $args['maxLength']) {
            return new WP_Error('rest_invalid_param', sprintf(
                /* translators: 1: Parameter, 2: Number of characters. */
                _n('%1$s must be at most %2$s character long.', '%1$s must be at most %2$s characters long.', $args['maxLength']),
                $param,
                number_format_i18n($args['maxLength'])
            ));
        }
        if (isset($args['pattern']) && !rest_validate_json_schema_pattern($args['pattern'], $value)) {
            /* translators: 1: Parameter, 2: Pattern. */
            return new WP_Error('rest_invalid_pattern', sprintf(__('%1$s does not match pattern %2$s.'), $param, $args['pattern']));
        }
    }
    // The "format" keyword should only be applied to strings. However, for backward compatibility,
    // we allow the "format" keyword if the type keyword was not specified, or was set to an invalid value.
    if (isset($args['format']) && (!isset($args['type']) || 'string' === $args['type'] || !in_array($args['type'], $allowed_types, true))) {
        switch ($args['format']) {
            case 'hex-color':
                if (!rest_parse_hex_color($value)) {
                    return new WP_Error('rest_invalid_hex_color', __('Invalid hex color.'));
                }
                break;
            case 'date-time':
                if (!rest_parse_date($value)) {
                    return new WP_Error('rest_invalid_date', __('Invalid date.'));
                }
                break;
            case 'email':
                if (!is_email($value)) {
                    return new WP_Error('rest_invalid_email', __('Invalid email address.'));
                }
                break;
            case 'ip':
                if (!rest_is_ip_address($value)) {
                    /* translators: %s: IP address. */
                    return new WP_Error('rest_invalid_param', sprintf(__('%s is not a valid IP address.'), $param));
                }
                break;
            case 'uuid':
                if (!wp_is_uuid($value)) {
                    /* translators: %s: The name of a JSON field expecting a valid UUID. */
                    return new WP_Error('rest_invalid_uuid', sprintf(__('%s is not a valid UUID.'), $param));
                }
                break;
        }
    }
    if (in_array($args['type'], array('number', 'integer'), true) && (isset($args['minimum']) || isset($args['maximum']))) {
        if (isset($args['minimum']) && !isset($args['maximum'])) {
            if (!empty($args['exclusiveMinimum']) && $value <= $args['minimum']) {
                /* translators: 1: Parameter, 2: Minimum number. */
                return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be greater than %2$d'), $param, $args['minimum']));
            } elseif (empty($args['exclusiveMinimum']) && $value < $args['minimum']) {
                /* translators: 1: Parameter, 2: Minimum number. */
                return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be greater than or equal to %2$d'), $param, $args['minimum']));
            }
        } elseif (isset($args['maximum']) && !isset($args['minimum'])) {
            if (!empty($args['exclusiveMaximum']) && $value >= $args['maximum']) {
                /* translators: 1: Parameter, 2: Maximum number. */
                return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be less than %2$d'), $param, $args['maximum']));
            } elseif (empty($args['exclusiveMaximum']) && $value > $args['maximum']) {
                /* translators: 1: Parameter, 2: Maximum number. */
                return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be less than or equal to %2$d'), $param, $args['maximum']));
            }
        } elseif (isset($args['maximum']) && isset($args['minimum'])) {
            if (!empty($args['exclusiveMinimum']) && !empty($args['exclusiveMaximum'])) {
                if ($value >= $args['maximum'] || $value <= $args['minimum']) {
                    /* translators: 1: Parameter, 2: Minimum number, 3: Maximum number. */
                    return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be between %2$d (exclusive) and %3$d (exclusive)'), $param, $args['minimum'], $args['maximum']));
                }
            } elseif (empty($args['exclusiveMinimum']) && !empty($args['exclusiveMaximum'])) {
                if ($value >= $args['maximum'] || $value < $args['minimum']) {
                    /* translators: 1: Parameter, 2: Minimum number, 3: Maximum number. */
                    return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be between %2$d (inclusive) and %3$d (exclusive)'), $param, $args['minimum'], $args['maximum']));
                }
            } elseif (!empty($args['exclusiveMinimum']) && empty($args['exclusiveMaximum'])) {
                if ($value > $args['maximum'] || $value <= $args['minimum']) {
                    /* translators: 1: Parameter, 2: Minimum number, 3: Maximum number. */
                    return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be between %2$d (exclusive) and %3$d (inclusive)'), $param, $args['minimum'], $args['maximum']));
                }
            } elseif (empty($args['exclusiveMinimum']) && empty($args['exclusiveMaximum'])) {
                if ($value > $args['maximum'] || $value < $args['minimum']) {
                    /* translators: 1: Parameter, 2: Minimum number, 3: Maximum number. */
                    return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be between %2$d (inclusive) and %3$d (inclusive)'), $param, $args['minimum'], $args['maximum']));
                }
            }
        }
    }
    return true;
}

WordPress Version: 5.5

/**
 * Validate a value based on a schema.
 *
 * @since 4.7.0
 * @since 4.9.0 Support the "object" type.
 * @since 5.2.0 Support validating "additionalProperties" against a schema.
 * @since 5.3.0 Support multiple types.
 * @since 5.4.0 Convert an empty string to an empty object.
 * @since 5.5.0 Add the "uuid" and "hex-color" formats.
 *              Support the "minLength", "maxLength" and "pattern" keywords for strings.
 *              Support the "minItems", "maxItems" and "uniqueItems" keywords for arrays.
 *              Validate required properties.
 *
 * @param mixed  $value The value to validate.
 * @param array  $args  Schema array to use for validation.
 * @param string $param The parameter name, used in error messages.
 * @return true|WP_Error
 */
function rest_validate_value_from_schema($value, $args, $param = '')
{
    $allowed_types = array('array', 'object', 'string', 'number', 'integer', 'boolean', 'null');
    if (!isset($args['type'])) {
        /* translators: 1. Parameter */
        _doing_it_wrong(__FUNCTION__, sprintf(__('The "type" schema keyword for %s is required.'), $param), '5.5.0');
    }
    if (is_array($args['type'])) {
        $best_type = rest_handle_multi_type_schema($value, $args, $param);
        if (!$best_type) {
            /* translators: 1: Parameter, 2: List of types. */
            return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not of type %2$s.'), $param, implode(',', $args['type'])));
        }
        $args['type'] = $best_type;
    }
    if (!in_array($args['type'], $allowed_types, true)) {
        _doing_it_wrong(
            __FUNCTION__,
            /* translators: 1. Parameter 2. The list of allowed types. */
            wp_sprintf(__('The "type" schema keyword for %1$s can only be one of the built-in types: %2$l.'), $param, $allowed_types),
            '5.5.0'
        );
    }
    if ('array' === $args['type']) {
        if (!rest_is_array($value)) {
            /* translators: 1: Parameter, 2: Type name. */
            return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not of type %2$s.'), $param, 'array'));
        }
        $value = rest_sanitize_array($value);
        if (isset($args['items'])) {
            foreach ($value as $index => $v) {
                $is_valid = rest_validate_value_from_schema($v, $args['items'], $param . '[' . $index . ']');
                if (is_wp_error($is_valid)) {
                    return $is_valid;
                }
            }
        }
        if (isset($args['minItems']) && count($value) < $args['minItems']) {
            /* translators: 1: Parameter, 2: Number. */
            return new WP_Error('rest_invalid_param', sprintf(__('%1$s must contain at least %2$s items.'), $param, number_format_i18n($args['minItems'])));
        }
        if (isset($args['maxItems']) && count($value) > $args['maxItems']) {
            /* translators: 1: Parameter, 2: Number. */
            return new WP_Error('rest_invalid_param', sprintf(__('%1$s must contain at most %2$s items.'), $param, number_format_i18n($args['maxItems'])));
        }
        if (!empty($args['uniqueItems']) && !rest_validate_array_contains_unique_items($value)) {
            /* translators: 1: Parameter */
            return new WP_Error('rest_invalid_param', sprintf(__('%1$s has duplicate items.'), $param));
        }
    }
    if ('object' === $args['type']) {
        if (!rest_is_object($value)) {
            /* translators: 1: Parameter, 2: Type name. */
            return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not of type %2$s.'), $param, 'object'));
        }
        $value = rest_sanitize_object($value);
        if (isset($args['required']) && is_array($args['required'])) {
            // schema version 4
            foreach ($args['required'] as $name) {
                if (!array_key_exists($name, $value)) {
                    /* translators: 1: Property of an object, 2: Parameter. */
                    return new WP_Error('rest_property_required', sprintf(__('%1$s is a required property of %2$s.'), $name, $param));
                }
            }
        } elseif (isset($args['properties'])) {
            // schema version 3
            foreach ($args['properties'] as $name => $property) {
                if (isset($property['required']) && true === $property['required'] && !array_key_exists($name, $value)) {
                    /* translators: 1: Property of an object, 2: Parameter. */
                    return new WP_Error('rest_property_required', sprintf(__('%1$s is a required property of %2$s.'), $name, $param));
                }
            }
        }
        foreach ($value as $property => $v) {
            if (isset($args['properties'][$property])) {
                $is_valid = rest_validate_value_from_schema($v, $args['properties'][$property], $param . '[' . $property . ']');
                if (is_wp_error($is_valid)) {
                    return $is_valid;
                }
            } elseif (isset($args['additionalProperties'])) {
                if (false === $args['additionalProperties']) {
                    /* translators: %s: Property of an object. */
                    return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not a valid property of Object.'), $property));
                }
                if (is_array($args['additionalProperties'])) {
                    $is_valid = rest_validate_value_from_schema($v, $args['additionalProperties'], $param . '[' . $property . ']');
                    if (is_wp_error($is_valid)) {
                        return $is_valid;
                    }
                }
            }
        }
    }
    if ('null' === $args['type']) {
        if (null !== $value) {
            /* translators: 1: Parameter, 2: Type name. */
            return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not of type %2$s.'), $param, 'null'));
        }
        return true;
    }
    if (!empty($args['enum'])) {
        if (!in_array($value, $args['enum'], true)) {
            /* translators: 1: Parameter, 2: List of valid values. */
            return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not one of %2$s.'), $param, implode(', ', $args['enum'])));
        }
    }
    if (in_array($args['type'], array('integer', 'number'), true) && !is_numeric($value)) {
        /* translators: 1: Parameter, 2: Type name. */
        return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not of type %2$s.'), $param, $args['type']));
    }
    if ('integer' === $args['type'] && !rest_is_integer($value)) {
        /* translators: 1: Parameter, 2: Type name. */
        return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not of type %2$s.'), $param, 'integer'));
    }
    if ('boolean' === $args['type'] && !rest_is_boolean($value)) {
        /* translators: 1: Parameter, 2: Type name. */
        return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not of type %2$s.'), $param, 'boolean'));
    }
    if ('string' === $args['type']) {
        if (!is_string($value)) {
            /* translators: 1: Parameter, 2: Type name. */
            return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not of type %2$s.'), $param, 'string'));
        }
        if (isset($args['minLength']) && mb_strlen($value) < $args['minLength']) {
            return new WP_Error('rest_invalid_param', sprintf(
                /* translators: 1: Parameter, 2: Number of characters. */
                _n('%1$s must be at least %2$s character long.', '%1$s must be at least %2$s characters long.', $args['minLength']),
                $param,
                number_format_i18n($args['minLength'])
            ));
        }
        if (isset($args['maxLength']) && mb_strlen($value) > $args['maxLength']) {
            return new WP_Error('rest_invalid_param', sprintf(
                /* translators: 1: Parameter, 2: Number of characters. */
                _n('%1$s must be at most %2$s character long.', '%1$s must be at most %2$s characters long.', $args['maxLength']),
                $param,
                number_format_i18n($args['maxLength'])
            ));
        }
        if (isset($args['pattern'])) {
            $pattern = str_replace('#', '\#', $args['pattern']);
            if (!preg_match('#' . $pattern . '#u', $value)) {
                /* translators: 1: Parameter, 2: Pattern. */
                return new WP_Error('rest_invalid_pattern', sprintf(__('%1$s does not match pattern %2$s.'), $param, $args['pattern']));
            }
        }
    }
    // The "format" keyword should only be applied to strings. However, for backward compatibility,
    // we allow the "format" keyword if the type keyword was not specified, or was set to an invalid value.
    if (isset($args['format']) && (!isset($args['type']) || 'string' === $args['type'] || !in_array($args['type'], $allowed_types, true))) {
        switch ($args['format']) {
            case 'hex-color':
                if (!rest_parse_hex_color($value)) {
                    return new WP_Error('rest_invalid_hex_color', __('Invalid hex color.'));
                }
                break;
            case 'date-time':
                if (!rest_parse_date($value)) {
                    return new WP_Error('rest_invalid_date', __('Invalid date.'));
                }
                break;
            case 'email':
                if (!is_email($value)) {
                    return new WP_Error('rest_invalid_email', __('Invalid email address.'));
                }
                break;
            case 'ip':
                if (!rest_is_ip_address($value)) {
                    /* translators: %s: IP address. */
                    return new WP_Error('rest_invalid_param', sprintf(__('%s is not a valid IP address.'), $param));
                }
                break;
            case 'uuid':
                if (!wp_is_uuid($value)) {
                    /* translators: %s is the name of a JSON field expecting a valid uuid. */
                    return new WP_Error('rest_invalid_uuid', sprintf(__('%s is not a valid UUID.'), $param));
                }
                break;
        }
    }
    if (in_array($args['type'], array('number', 'integer'), true) && (isset($args['minimum']) || isset($args['maximum']))) {
        if (isset($args['minimum']) && !isset($args['maximum'])) {
            if (!empty($args['exclusiveMinimum']) && $value <= $args['minimum']) {
                /* translators: 1: Parameter, 2: Minimum number. */
                return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be greater than %2$d'), $param, $args['minimum']));
            } elseif (empty($args['exclusiveMinimum']) && $value < $args['minimum']) {
                /* translators: 1: Parameter, 2: Minimum number. */
                return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be greater than or equal to %2$d'), $param, $args['minimum']));
            }
        } elseif (isset($args['maximum']) && !isset($args['minimum'])) {
            if (!empty($args['exclusiveMaximum']) && $value >= $args['maximum']) {
                /* translators: 1: Parameter, 2: Maximum number. */
                return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be less than %2$d'), $param, $args['maximum']));
            } elseif (empty($args['exclusiveMaximum']) && $value > $args['maximum']) {
                /* translators: 1: Parameter, 2: Maximum number. */
                return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be less than or equal to %2$d'), $param, $args['maximum']));
            }
        } elseif (isset($args['maximum']) && isset($args['minimum'])) {
            if (!empty($args['exclusiveMinimum']) && !empty($args['exclusiveMaximum'])) {
                if ($value >= $args['maximum'] || $value <= $args['minimum']) {
                    /* translators: 1: Parameter, 2: Minimum number, 3: Maximum number. */
                    return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be between %2$d (exclusive) and %3$d (exclusive)'), $param, $args['minimum'], $args['maximum']));
                }
            } elseif (empty($args['exclusiveMinimum']) && !empty($args['exclusiveMaximum'])) {
                if ($value >= $args['maximum'] || $value < $args['minimum']) {
                    /* translators: 1: Parameter, 2: Minimum number, 3: Maximum number. */
                    return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be between %2$d (inclusive) and %3$d (exclusive)'), $param, $args['minimum'], $args['maximum']));
                }
            } elseif (!empty($args['exclusiveMinimum']) && empty($args['exclusiveMaximum'])) {
                if ($value > $args['maximum'] || $value <= $args['minimum']) {
                    /* translators: 1: Parameter, 2: Minimum number, 3: Maximum number. */
                    return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be between %2$d (exclusive) and %3$d (inclusive)'), $param, $args['minimum'], $args['maximum']));
                }
            } elseif (empty($args['exclusiveMinimum']) && empty($args['exclusiveMaximum'])) {
                if ($value > $args['maximum'] || $value < $args['minimum']) {
                    /* translators: 1: Parameter, 2: Minimum number, 3: Maximum number. */
                    return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be between %2$d (inclusive) and %3$d (inclusive)'), $param, $args['minimum'], $args['maximum']));
                }
            }
        }
    }
    return true;
}

WordPress Version: 5.4

/**
 * Validate a value based on a schema.
 *
 * @since 4.7.0
 *
 * @param mixed  $value The value to validate.
 * @param array  $args  Schema array to use for validation.
 * @param string $param The parameter name, used in error messages.
 * @return true|WP_Error
 */
function rest_validate_value_from_schema($value, $args, $param = '')
{
    if (is_array($args['type'])) {
        foreach ($args['type'] as $type) {
            $type_args = $args;
            $type_args['type'] = $type;
            if (true === rest_validate_value_from_schema($value, $type_args, $param)) {
                return true;
            }
        }
        /* translators: 1: Parameter, 2: List of types. */
        return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not of type %2$s.'), $param, implode(',', $args['type'])));
    }
    if ('array' === $args['type']) {
        if (!is_null($value)) {
            $value = wp_parse_list($value);
        }
        if (!wp_is_numeric_array($value)) {
            /* translators: 1: Parameter, 2: Type name. */
            return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not of type %2$s.'), $param, 'array'));
        }
        foreach ($value as $index => $v) {
            $is_valid = rest_validate_value_from_schema($v, $args['items'], $param . '[' . $index . ']');
            if (is_wp_error($is_valid)) {
                return $is_valid;
            }
        }
    }
    if ('object' === $args['type']) {
        if ('' === $value) {
            $value = array();
        }
        if ($value instanceof stdClass) {
            $value = (array) $value;
        }
        if ($value instanceof JsonSerializable) {
            $value = $value->jsonSerialize();
        }
        if (!is_array($value)) {
            /* translators: 1: Parameter, 2: Type name. */
            return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not of type %2$s.'), $param, 'object'));
        }
        foreach ($value as $property => $v) {
            if (isset($args['properties'][$property])) {
                $is_valid = rest_validate_value_from_schema($v, $args['properties'][$property], $param . '[' . $property . ']');
                if (is_wp_error($is_valid)) {
                    return $is_valid;
                }
            } elseif (isset($args['additionalProperties'])) {
                if (false === $args['additionalProperties']) {
                    /* translators: %s: Property of an object. */
                    return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not a valid property of Object.'), $property));
                }
                if (is_array($args['additionalProperties'])) {
                    $is_valid = rest_validate_value_from_schema($v, $args['additionalProperties'], $param . '[' . $property . ']');
                    if (is_wp_error($is_valid)) {
                        return $is_valid;
                    }
                }
            }
        }
    }
    if ('null' === $args['type']) {
        if (null !== $value) {
            /* translators: 1: Parameter, 2: Type name. */
            return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not of type %2$s.'), $param, 'null'));
        }
        return true;
    }
    if (!empty($args['enum'])) {
        if (!in_array($value, $args['enum'], true)) {
            /* translators: 1: Parameter, 2: List of valid values. */
            return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not one of %2$s.'), $param, implode(', ', $args['enum'])));
        }
    }
    if (in_array($args['type'], array('integer', 'number')) && !is_numeric($value)) {
        /* translators: 1: Parameter, 2: Type name. */
        return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not of type %2$s.'), $param, $args['type']));
    }
    if ('integer' === $args['type'] && round(floatval($value)) !== floatval($value)) {
        /* translators: 1: Parameter, 2: Type name. */
        return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not of type %2$s.'), $param, 'integer'));
    }
    if ('boolean' === $args['type'] && !rest_is_boolean($value)) {
        /* translators: 1: Parameter, 2: Type name. */
        return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not of type %2$s.'), $param, 'boolean'));
    }
    if ('string' === $args['type'] && !is_string($value)) {
        /* translators: 1: Parameter, 2: Type name. */
        return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not of type %2$s.'), $param, 'string'));
    }
    if (isset($args['format'])) {
        switch ($args['format']) {
            case 'date-time':
                if (!rest_parse_date($value)) {
                    return new WP_Error('rest_invalid_date', __('Invalid date.'));
                }
                break;
            case 'email':
                if (!is_email($value)) {
                    return new WP_Error('rest_invalid_email', __('Invalid email address.'));
                }
                break;
            case 'ip':
                if (!rest_is_ip_address($value)) {
                    /* translators: %s: IP address. */
                    return new WP_Error('rest_invalid_param', sprintf(__('%s is not a valid IP address.'), $param));
                }
                break;
        }
    }
    if (in_array($args['type'], array('number', 'integer'), true) && (isset($args['minimum']) || isset($args['maximum']))) {
        if (isset($args['minimum']) && !isset($args['maximum'])) {
            if (!empty($args['exclusiveMinimum']) && $value <= $args['minimum']) {
                /* translators: 1: Parameter, 2: Minimum number. */
                return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be greater than %2$d'), $param, $args['minimum']));
            } elseif (empty($args['exclusiveMinimum']) && $value < $args['minimum']) {
                /* translators: 1: Parameter, 2: Minimum number. */
                return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be greater than or equal to %2$d'), $param, $args['minimum']));
            }
        } elseif (isset($args['maximum']) && !isset($args['minimum'])) {
            if (!empty($args['exclusiveMaximum']) && $value >= $args['maximum']) {
                /* translators: 1: Parameter, 2: Maximum number. */
                return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be less than %2$d'), $param, $args['maximum']));
            } elseif (empty($args['exclusiveMaximum']) && $value > $args['maximum']) {
                /* translators: 1: Parameter, 2: Maximum number. */
                return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be less than or equal to %2$d'), $param, $args['maximum']));
            }
        } elseif (isset($args['maximum']) && isset($args['minimum'])) {
            if (!empty($args['exclusiveMinimum']) && !empty($args['exclusiveMaximum'])) {
                if ($value >= $args['maximum'] || $value <= $args['minimum']) {
                    /* translators: 1: Parameter, 2: Minimum number, 3: Maximum number. */
                    return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be between %2$d (exclusive) and %3$d (exclusive)'), $param, $args['minimum'], $args['maximum']));
                }
            } elseif (empty($args['exclusiveMinimum']) && !empty($args['exclusiveMaximum'])) {
                if ($value >= $args['maximum'] || $value < $args['minimum']) {
                    /* translators: 1: Parameter, 2: Minimum number, 3: Maximum number. */
                    return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be between %2$d (inclusive) and %3$d (exclusive)'), $param, $args['minimum'], $args['maximum']));
                }
            } elseif (!empty($args['exclusiveMinimum']) && empty($args['exclusiveMaximum'])) {
                if ($value > $args['maximum'] || $value <= $args['minimum']) {
                    /* translators: 1: Parameter, 2: Minimum number, 3: Maximum number. */
                    return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be between %2$d (exclusive) and %3$d (inclusive)'), $param, $args['minimum'], $args['maximum']));
                }
            } elseif (empty($args['exclusiveMinimum']) && empty($args['exclusiveMaximum'])) {
                if ($value > $args['maximum'] || $value < $args['minimum']) {
                    /* translators: 1: Parameter, 2: Minimum number, 3: Maximum number. */
                    return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be between %2$d (inclusive) and %3$d (inclusive)'), $param, $args['minimum'], $args['maximum']));
                }
            }
        }
    }
    return true;
}

WordPress Version: 5.3

/**
 * Validate a value based on a schema.
 *
 * @since 4.7.0
 *
 * @param mixed  $value The value to validate.
 * @param array  $args  Schema array to use for validation.
 * @param string $param The parameter name, used in error messages.
 * @return true|WP_Error
 */
function rest_validate_value_from_schema($value, $args, $param = '')
{
    if (is_array($args['type'])) {
        foreach ($args['type'] as $type) {
            $type_args = $args;
            $type_args['type'] = $type;
            if (true === rest_validate_value_from_schema($value, $type_args, $param)) {
                return true;
            }
        }
        /* translators: 1: Parameter, 2: List of types. */
        return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not of type %2$s'), $param, implode(',', $args['type'])));
    }
    if ('array' === $args['type']) {
        if (!is_null($value)) {
            $value = wp_parse_list($value);
        }
        if (!wp_is_numeric_array($value)) {
            /* translators: 1: Parameter, 2: Type name. */
            return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not of type %2$s.'), $param, 'array'));
        }
        foreach ($value as $index => $v) {
            $is_valid = rest_validate_value_from_schema($v, $args['items'], $param . '[' . $index . ']');
            if (is_wp_error($is_valid)) {
                return $is_valid;
            }
        }
    }
    if ('object' === $args['type']) {
        if ($value instanceof stdClass) {
            $value = (array) $value;
        }
        if ($value instanceof JsonSerializable) {
            $value = $value->jsonSerialize();
        }
        if (!is_array($value)) {
            /* translators: 1: Parameter, 2: Type name. */
            return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not of type %2$s.'), $param, 'object'));
        }
        foreach ($value as $property => $v) {
            if (isset($args['properties'][$property])) {
                $is_valid = rest_validate_value_from_schema($v, $args['properties'][$property], $param . '[' . $property . ']');
                if (is_wp_error($is_valid)) {
                    return $is_valid;
                }
            } elseif (isset($args['additionalProperties'])) {
                if (false === $args['additionalProperties']) {
                    /* translators: %s: Property of an object. */
                    return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not a valid property of Object.'), $property));
                }
                if (is_array($args['additionalProperties'])) {
                    $is_valid = rest_validate_value_from_schema($v, $args['additionalProperties'], $param . '[' . $property . ']');
                    if (is_wp_error($is_valid)) {
                        return $is_valid;
                    }
                }
            }
        }
    }
    if ('null' === $args['type']) {
        if (null !== $value) {
            /* translators: 1: Parameter, 2: Type name. */
            return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not of type %2$s.'), $param, 'null'));
        }
        return true;
    }
    if (!empty($args['enum'])) {
        if (!in_array($value, $args['enum'], true)) {
            /* translators: 1: Parameter, 2: List of valid values. */
            return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not one of %2$s.'), $param, implode(', ', $args['enum'])));
        }
    }
    if (in_array($args['type'], array('integer', 'number')) && !is_numeric($value)) {
        /* translators: 1: Parameter, 2: Type name. */
        return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not of type %2$s.'), $param, $args['type']));
    }
    if ('integer' === $args['type'] && round(floatval($value)) !== floatval($value)) {
        /* translators: 1: Parameter, 2: Type name. */
        return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not of type %2$s.'), $param, 'integer'));
    }
    if ('boolean' === $args['type'] && !rest_is_boolean($value)) {
        /* translators: 1: Parameter, 2: Type name. */
        return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not of type %2$s.'), $param, 'boolean'));
    }
    if ('string' === $args['type'] && !is_string($value)) {
        /* translators: 1: Parameter, 2: Type name. */
        return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not of type %2$s.'), $param, 'string'));
    }
    if (isset($args['format'])) {
        switch ($args['format']) {
            case 'date-time':
                if (!rest_parse_date($value)) {
                    return new WP_Error('rest_invalid_date', __('Invalid date.'));
                }
                break;
            case 'email':
                if (!is_email($value)) {
                    return new WP_Error('rest_invalid_email', __('Invalid email address.'));
                }
                break;
            case 'ip':
                if (!rest_is_ip_address($value)) {
                    /* translators: %s: IP address. */
                    return new WP_Error('rest_invalid_param', sprintf(__('%s is not a valid IP address.'), $param));
                }
                break;
        }
    }
    if (in_array($args['type'], array('number', 'integer'), true) && (isset($args['minimum']) || isset($args['maximum']))) {
        if (isset($args['minimum']) && !isset($args['maximum'])) {
            if (!empty($args['exclusiveMinimum']) && $value <= $args['minimum']) {
                /* translators: 1: Parameter, 2: Minimum number. */
                return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be greater than %2$d'), $param, $args['minimum']));
            } elseif (empty($args['exclusiveMinimum']) && $value < $args['minimum']) {
                /* translators: 1: Parameter, 2: Minimum number. */
                return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be greater than or equal to %2$d'), $param, $args['minimum']));
            }
        } elseif (isset($args['maximum']) && !isset($args['minimum'])) {
            if (!empty($args['exclusiveMaximum']) && $value >= $args['maximum']) {
                /* translators: 1: Parameter, 2: Maximum number. */
                return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be less than %2$d'), $param, $args['maximum']));
            } elseif (empty($args['exclusiveMaximum']) && $value > $args['maximum']) {
                /* translators: 1: Parameter, 2: Maximum number. */
                return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be less than or equal to %2$d'), $param, $args['maximum']));
            }
        } elseif (isset($args['maximum']) && isset($args['minimum'])) {
            if (!empty($args['exclusiveMinimum']) && !empty($args['exclusiveMaximum'])) {
                if ($value >= $args['maximum'] || $value <= $args['minimum']) {
                    /* translators: 1: Parameter, 2: Minimum number, 3: Maximum number. */
                    return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be between %2$d (exclusive) and %3$d (exclusive)'), $param, $args['minimum'], $args['maximum']));
                }
            } elseif (empty($args['exclusiveMinimum']) && !empty($args['exclusiveMaximum'])) {
                if ($value >= $args['maximum'] || $value < $args['minimum']) {
                    /* translators: 1: Parameter, 2: Minimum number, 3: Maximum number. */
                    return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be between %2$d (inclusive) and %3$d (exclusive)'), $param, $args['minimum'], $args['maximum']));
                }
            } elseif (!empty($args['exclusiveMinimum']) && empty($args['exclusiveMaximum'])) {
                if ($value > $args['maximum'] || $value <= $args['minimum']) {
                    /* translators: 1: Parameter, 2: Minimum number, 3: Maximum number. */
                    return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be between %2$d (exclusive) and %3$d (inclusive)'), $param, $args['minimum'], $args['maximum']));
                }
            } elseif (empty($args['exclusiveMinimum']) && empty($args['exclusiveMaximum'])) {
                if ($value > $args['maximum'] || $value < $args['minimum']) {
                    /* translators: 1: Parameter, 2: Minimum number, 3: Maximum number. */
                    return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be between %2$d (inclusive) and %3$d (inclusive)'), $param, $args['minimum'], $args['maximum']));
                }
            }
        }
    }
    return true;
}

WordPress Version: 5.1

/**
 * Validate a value based on a schema.
 *
 * @since 4.7.0
 *
 * @param mixed  $value The value to validate.
 * @param array  $args  Schema array to use for validation.
 * @param string $param The parameter name, used in error messages.
 * @return true|WP_Error
 */
function rest_validate_value_from_schema($value, $args, $param = '')
{
    if ('array' === $args['type']) {
        if (!is_null($value)) {
            $value = wp_parse_list($value);
        }
        if (!wp_is_numeric_array($value)) {
            /* translators: 1: parameter, 2: type name */
            return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not of type %2$s.'), $param, 'array'));
        }
        foreach ($value as $index => $v) {
            $is_valid = rest_validate_value_from_schema($v, $args['items'], $param . '[' . $index . ']');
            if (is_wp_error($is_valid)) {
                return $is_valid;
            }
        }
    }
    if ('object' === $args['type']) {
        if ($value instanceof stdClass) {
            $value = (array) $value;
        }
        if (!is_array($value)) {
            /* translators: 1: parameter, 2: type name */
            return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not of type %2$s.'), $param, 'object'));
        }
        foreach ($value as $property => $v) {
            if (isset($args['properties'][$property])) {
                $is_valid = rest_validate_value_from_schema($v, $args['properties'][$property], $param . '[' . $property . ']');
                if (is_wp_error($is_valid)) {
                    return $is_valid;
                }
            } elseif (isset($args['additionalProperties']) && false === $args['additionalProperties']) {
                return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not a valid property of Object.'), $property));
            }
        }
    }
    if (!empty($args['enum'])) {
        if (!in_array($value, $args['enum'], true)) {
            /* translators: 1: parameter, 2: list of valid values */
            return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not one of %2$s.'), $param, implode(', ', $args['enum'])));
        }
    }
    if (in_array($args['type'], array('integer', 'number')) && !is_numeric($value)) {
        /* translators: 1: parameter, 2: type name */
        return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not of type %2$s.'), $param, $args['type']));
    }
    if ('integer' === $args['type'] && round(floatval($value)) !== floatval($value)) {
        /* translators: 1: parameter, 2: type name */
        return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not of type %2$s.'), $param, 'integer'));
    }
    if ('boolean' === $args['type'] && !rest_is_boolean($value)) {
        /* translators: 1: parameter, 2: type name */
        return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not of type %2$s.'), $value, 'boolean'));
    }
    if ('string' === $args['type'] && !is_string($value)) {
        /* translators: 1: parameter, 2: type name */
        return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not of type %2$s.'), $param, 'string'));
    }
    if (isset($args['format'])) {
        switch ($args['format']) {
            case 'date-time':
                if (!rest_parse_date($value)) {
                    return new WP_Error('rest_invalid_date', __('Invalid date.'));
                }
                break;
            case 'email':
                if (!is_email($value)) {
                    return new WP_Error('rest_invalid_email', __('Invalid email address.'));
                }
                break;
            case 'ip':
                if (!rest_is_ip_address($value)) {
                    /* translators: %s: IP address */
                    return new WP_Error('rest_invalid_param', sprintf(__('%s is not a valid IP address.'), $value));
                }
                break;
        }
    }
    if (in_array($args['type'], array('number', 'integer'), true) && (isset($args['minimum']) || isset($args['maximum']))) {
        if (isset($args['minimum']) && !isset($args['maximum'])) {
            if (!empty($args['exclusiveMinimum']) && $value <= $args['minimum']) {
                /* translators: 1: parameter, 2: minimum number */
                return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be greater than %2$d'), $param, $args['minimum']));
            } elseif (empty($args['exclusiveMinimum']) && $value < $args['minimum']) {
                /* translators: 1: parameter, 2: minimum number */
                return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be greater than or equal to %2$d'), $param, $args['minimum']));
            }
        } elseif (isset($args['maximum']) && !isset($args['minimum'])) {
            if (!empty($args['exclusiveMaximum']) && $value >= $args['maximum']) {
                /* translators: 1: parameter, 2: maximum number */
                return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be less than %2$d'), $param, $args['maximum']));
            } elseif (empty($args['exclusiveMaximum']) && $value > $args['maximum']) {
                /* translators: 1: parameter, 2: maximum number */
                return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be less than or equal to %2$d'), $param, $args['maximum']));
            }
        } elseif (isset($args['maximum']) && isset($args['minimum'])) {
            if (!empty($args['exclusiveMinimum']) && !empty($args['exclusiveMaximum'])) {
                if ($value >= $args['maximum'] || $value <= $args['minimum']) {
                    /* translators: 1: parameter, 2: minimum number, 3: maximum number */
                    return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be between %2$d (exclusive) and %3$d (exclusive)'), $param, $args['minimum'], $args['maximum']));
                }
            } elseif (empty($args['exclusiveMinimum']) && !empty($args['exclusiveMaximum'])) {
                if ($value >= $args['maximum'] || $value < $args['minimum']) {
                    /* translators: 1: parameter, 2: minimum number, 3: maximum number */
                    return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be between %2$d (inclusive) and %3$d (exclusive)'), $param, $args['minimum'], $args['maximum']));
                }
            } elseif (!empty($args['exclusiveMinimum']) && empty($args['exclusiveMaximum'])) {
                if ($value > $args['maximum'] || $value <= $args['minimum']) {
                    /* translators: 1: parameter, 2: minimum number, 3: maximum number */
                    return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be between %2$d (exclusive) and %3$d (inclusive)'), $param, $args['minimum'], $args['maximum']));
                }
            } elseif (empty($args['exclusiveMinimum']) && empty($args['exclusiveMaximum'])) {
                if ($value > $args['maximum'] || $value < $args['minimum']) {
                    /* translators: 1: parameter, 2: minimum number, 3: maximum number */
                    return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be between %2$d (inclusive) and %3$d (inclusive)'), $param, $args['minimum'], $args['maximum']));
                }
            }
        }
    }
    return true;
}

WordPress Version: 4.9

/**
 * Validate a value based on a schema.
 *
 * @since 4.7.0
 *
 * @param mixed  $value The value to validate.
 * @param array  $args  Schema array to use for validation.
 * @param string $param The parameter name, used in error messages.
 * @return true|WP_Error
 */
function rest_validate_value_from_schema($value, $args, $param = '')
{
    if ('array' === $args['type']) {
        if (!is_array($value)) {
            $value = preg_split('/[\s,]+/', $value);
        }
        if (!wp_is_numeric_array($value)) {
            /* translators: 1: parameter, 2: type name */
            return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not of type %2$s.'), $param, 'array'));
        }
        foreach ($value as $index => $v) {
            $is_valid = rest_validate_value_from_schema($v, $args['items'], $param . '[' . $index . ']');
            if (is_wp_error($is_valid)) {
                return $is_valid;
            }
        }
    }
    if ('object' === $args['type']) {
        if ($value instanceof stdClass) {
            $value = (array) $value;
        }
        if (!is_array($value)) {
            /* translators: 1: parameter, 2: type name */
            return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not of type %2$s.'), $param, 'object'));
        }
        foreach ($value as $property => $v) {
            if (isset($args['properties'][$property])) {
                $is_valid = rest_validate_value_from_schema($v, $args['properties'][$property], $param . '[' . $property . ']');
                if (is_wp_error($is_valid)) {
                    return $is_valid;
                }
            } elseif (isset($args['additionalProperties']) && false === $args['additionalProperties']) {
                return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not a valid property of Object.'), $property));
            }
        }
    }
    if (!empty($args['enum'])) {
        if (!in_array($value, $args['enum'], true)) {
            /* translators: 1: parameter, 2: list of valid values */
            return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not one of %2$s.'), $param, implode(', ', $args['enum'])));
        }
    }
    if (in_array($args['type'], array('integer', 'number')) && !is_numeric($value)) {
        /* translators: 1: parameter, 2: type name */
        return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not of type %2$s.'), $param, $args['type']));
    }
    if ('integer' === $args['type'] && round(floatval($value)) !== floatval($value)) {
        /* translators: 1: parameter, 2: type name */
        return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not of type %2$s.'), $param, 'integer'));
    }
    if ('boolean' === $args['type'] && !rest_is_boolean($value)) {
        /* translators: 1: parameter, 2: type name */
        return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not of type %2$s.'), $value, 'boolean'));
    }
    if ('string' === $args['type'] && !is_string($value)) {
        /* translators: 1: parameter, 2: type name */
        return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not of type %2$s.'), $param, 'string'));
    }
    if (isset($args['format'])) {
        switch ($args['format']) {
            case 'date-time':
                if (!rest_parse_date($value)) {
                    return new WP_Error('rest_invalid_date', __('Invalid date.'));
                }
                break;
            case 'email':
                if (!is_email($value)) {
                    return new WP_Error('rest_invalid_email', __('Invalid email address.'));
                }
                break;
            case 'ip':
                if (!rest_is_ip_address($value)) {
                    /* translators: %s: IP address */
                    return new WP_Error('rest_invalid_param', sprintf(__('%s is not a valid IP address.'), $value));
                }
                break;
        }
    }
    if (in_array($args['type'], array('number', 'integer'), true) && (isset($args['minimum']) || isset($args['maximum']))) {
        if (isset($args['minimum']) && !isset($args['maximum'])) {
            if (!empty($args['exclusiveMinimum']) && $value <= $args['minimum']) {
                /* translators: 1: parameter, 2: minimum number */
                return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be greater than %2$d'), $param, $args['minimum']));
            } elseif (empty($args['exclusiveMinimum']) && $value < $args['minimum']) {
                /* translators: 1: parameter, 2: minimum number */
                return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be greater than or equal to %2$d'), $param, $args['minimum']));
            }
        } elseif (isset($args['maximum']) && !isset($args['minimum'])) {
            if (!empty($args['exclusiveMaximum']) && $value >= $args['maximum']) {
                /* translators: 1: parameter, 2: maximum number */
                return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be less than %2$d'), $param, $args['maximum']));
            } elseif (empty($args['exclusiveMaximum']) && $value > $args['maximum']) {
                /* translators: 1: parameter, 2: maximum number */
                return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be less than or equal to %2$d'), $param, $args['maximum']));
            }
        } elseif (isset($args['maximum']) && isset($args['minimum'])) {
            if (!empty($args['exclusiveMinimum']) && !empty($args['exclusiveMaximum'])) {
                if ($value >= $args['maximum'] || $value <= $args['minimum']) {
                    /* translators: 1: parameter, 2: minimum number, 3: maximum number */
                    return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be between %2$d (exclusive) and %3$d (exclusive)'), $param, $args['minimum'], $args['maximum']));
                }
            } elseif (empty($args['exclusiveMinimum']) && !empty($args['exclusiveMaximum'])) {
                if ($value >= $args['maximum'] || $value < $args['minimum']) {
                    /* translators: 1: parameter, 2: minimum number, 3: maximum number */
                    return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be between %2$d (inclusive) and %3$d (exclusive)'), $param, $args['minimum'], $args['maximum']));
                }
            } elseif (!empty($args['exclusiveMinimum']) && empty($args['exclusiveMaximum'])) {
                if ($value > $args['maximum'] || $value <= $args['minimum']) {
                    /* translators: 1: parameter, 2: minimum number, 3: maximum number */
                    return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be between %2$d (exclusive) and %3$d (inclusive)'), $param, $args['minimum'], $args['maximum']));
                }
            } elseif (empty($args['exclusiveMinimum']) && empty($args['exclusiveMaximum'])) {
                if ($value > $args['maximum'] || $value < $args['minimum']) {
                    /* translators: 1: parameter, 2: minimum number, 3: maximum number */
                    return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be between %2$d (inclusive) and %3$d (inclusive)'), $param, $args['minimum'], $args['maximum']));
                }
            }
        }
    }
    return true;
}

WordPress Version: 4.8

/**
 * Validate a value based on a schema.
 *
 * @since 4.7.0
 *
 * @param mixed  $value The value to validate.
 * @param array  $args  Schema array to use for validation.
 * @param string $param The parameter name, used in error messages.
 * @return true|WP_Error
 */
function rest_validate_value_from_schema($value, $args, $param = '')
{
    if ('array' === $args['type']) {
        if (!is_array($value)) {
            $value = preg_split('/[\s,]+/', $value);
        }
        if (!wp_is_numeric_array($value)) {
            /* translators: 1: parameter, 2: type name */
            return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not of type %2$s.'), $param, 'array'));
        }
        foreach ($value as $index => $v) {
            $is_valid = rest_validate_value_from_schema($v, $args['items'], $param . '[' . $index . ']');
            if (is_wp_error($is_valid)) {
                return $is_valid;
            }
        }
    }
    if (!empty($args['enum'])) {
        if (!in_array($value, $args['enum'], true)) {
            /* translators: 1: parameter, 2: list of valid values */
            return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not one of %2$s.'), $param, implode(', ', $args['enum'])));
        }
    }
    if (in_array($args['type'], array('integer', 'number')) && !is_numeric($value)) {
        /* translators: 1: parameter, 2: type name */
        return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not of type %2$s.'), $param, $args['type']));
    }
    if ('integer' === $args['type'] && round(floatval($value)) !== floatval($value)) {
        /* translators: 1: parameter, 2: type name */
        return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not of type %2$s.'), $param, 'integer'));
    }
    if ('boolean' === $args['type'] && !rest_is_boolean($value)) {
        /* translators: 1: parameter, 2: type name */
        return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not of type %2$s.'), $value, 'boolean'));
    }
    if ('string' === $args['type'] && !is_string($value)) {
        /* translators: 1: parameter, 2: type name */
        return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not of type %2$s.'), $param, 'string'));
    }
    if (isset($args['format'])) {
        switch ($args['format']) {
            case 'date-time':
                if (!rest_parse_date($value)) {
                    return new WP_Error('rest_invalid_date', __('Invalid date.'));
                }
                break;
            case 'email':
                if (!is_email($value)) {
                    return new WP_Error('rest_invalid_email', __('Invalid email address.'));
                }
                break;
            case 'ip':
                if (!rest_is_ip_address($value)) {
                    /* translators: %s: IP address */
                    return new WP_Error('rest_invalid_param', sprintf(__('%s is not a valid IP address.'), $value));
                }
                break;
        }
    }
    if (in_array($args['type'], array('number', 'integer'), true) && (isset($args['minimum']) || isset($args['maximum']))) {
        if (isset($args['minimum']) && !isset($args['maximum'])) {
            if (!empty($args['exclusiveMinimum']) && $value <= $args['minimum']) {
                /* translators: 1: parameter, 2: minimum number */
                return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be greater than %2$d'), $param, $args['minimum']));
            } elseif (empty($args['exclusiveMinimum']) && $value < $args['minimum']) {
                /* translators: 1: parameter, 2: minimum number */
                return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be greater than or equal to %2$d'), $param, $args['minimum']));
            }
        } elseif (isset($args['maximum']) && !isset($args['minimum'])) {
            if (!empty($args['exclusiveMaximum']) && $value >= $args['maximum']) {
                /* translators: 1: parameter, 2: maximum number */
                return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be less than %2$d'), $param, $args['maximum']));
            } elseif (empty($args['exclusiveMaximum']) && $value > $args['maximum']) {
                /* translators: 1: parameter, 2: maximum number */
                return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be less than or equal to %2$d'), $param, $args['maximum']));
            }
        } elseif (isset($args['maximum']) && isset($args['minimum'])) {
            if (!empty($args['exclusiveMinimum']) && !empty($args['exclusiveMaximum'])) {
                if ($value >= $args['maximum'] || $value <= $args['minimum']) {
                    /* translators: 1: parameter, 2: minimum number, 3: maximum number */
                    return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be between %2$d (exclusive) and %3$d (exclusive)'), $param, $args['minimum'], $args['maximum']));
                }
            } elseif (empty($args['exclusiveMinimum']) && !empty($args['exclusiveMaximum'])) {
                if ($value >= $args['maximum'] || $value < $args['minimum']) {
                    /* translators: 1: parameter, 2: minimum number, 3: maximum number */
                    return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be between %2$d (inclusive) and %3$d (exclusive)'), $param, $args['minimum'], $args['maximum']));
                }
            } elseif (!empty($args['exclusiveMinimum']) && empty($args['exclusiveMaximum'])) {
                if ($value > $args['maximum'] || $value <= $args['minimum']) {
                    /* translators: 1: parameter, 2: minimum number, 3: maximum number */
                    return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be between %2$d (exclusive) and %3$d (inclusive)'), $param, $args['minimum'], $args['maximum']));
                }
            } elseif (empty($args['exclusiveMinimum']) && empty($args['exclusiveMaximum'])) {
                if ($value > $args['maximum'] || $value < $args['minimum']) {
                    /* translators: 1: parameter, 2: minimum number, 3: maximum number */
                    return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be between %2$d (inclusive) and %3$d (inclusive)'), $param, $args['minimum'], $args['maximum']));
                }
            }
        }
    }
    return true;
}

WordPress Version: 4.7

/**
 * Validate a value based on a schema.
 *
 * @param mixed  $value The value to validate.
 * @param array  $args  Schema array to use for validation.
 * @param string $param The parameter name, used in error messages.
 * @return true|WP_Error
 */
function rest_validate_value_from_schema($value, $args, $param = '')
{
    if ('array' === $args['type']) {
        if (!is_array($value)) {
            $value = preg_split('/[\s,]+/', $value);
        }
        if (!wp_is_numeric_array($value)) {
            /* translators: 1: parameter, 2: type name */
            return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not of type %2$s.'), $param, 'array'));
        }
        foreach ($value as $index => $v) {
            $is_valid = rest_validate_value_from_schema($v, $args['items'], $param . '[' . $index . ']');
            if (is_wp_error($is_valid)) {
                return $is_valid;
            }
        }
    }
    if (!empty($args['enum'])) {
        if (!in_array($value, $args['enum'], true)) {
            /* translators: 1: parameter, 2: list of valid values */
            return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not one of %2$s.'), $param, implode(', ', $args['enum'])));
        }
    }
    if (in_array($args['type'], array('integer', 'number')) && !is_numeric($value)) {
        /* translators: 1: parameter, 2: type name */
        return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not of type %2$s.'), $param, $args['type']));
    }
    if ('integer' === $args['type'] && round(floatval($value)) !== floatval($value)) {
        /* translators: 1: parameter, 2: type name */
        return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not of type %2$s.'), $param, 'integer'));
    }
    if ('boolean' === $args['type'] && !rest_is_boolean($value)) {
        /* translators: 1: parameter, 2: type name */
        return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not of type %2$s.'), $value, 'boolean'));
    }
    if ('string' === $args['type'] && !is_string($value)) {
        /* translators: 1: parameter, 2: type name */
        return new WP_Error('rest_invalid_param', sprintf(__('%1$s is not of type %2$s.'), $param, 'string'));
    }
    if (isset($args['format'])) {
        switch ($args['format']) {
            case 'date-time':
                if (!rest_parse_date($value)) {
                    return new WP_Error('rest_invalid_date', __('Invalid date.'));
                }
                break;
            case 'email':
                // is_email() checks for 3 characters (a@b), but
                // wp_handle_comment_submission() requires 6 characters (a@b.co)
                //
                // https://core.trac.wordpress.org/ticket/38506
                if (!is_email($value) || strlen($value) < 6) {
                    return new WP_Error('rest_invalid_email', __('Invalid email address.'));
                }
                break;
            case 'ip':
                if (!rest_is_ip_address($value)) {
                    /* translators: %s: IP address */
                    return new WP_Error('rest_invalid_param', sprintf(__('%s is not a valid IP address.'), $value));
                }
                break;
        }
    }
    if (in_array($args['type'], array('number', 'integer'), true) && (isset($args['minimum']) || isset($args['maximum']))) {
        if (isset($args['minimum']) && !isset($args['maximum'])) {
            if (!empty($args['exclusiveMinimum']) && $value <= $args['minimum']) {
                /* translators: 1: parameter, 2: minimum number */
                return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be greater than %2$d (exclusive)'), $param, $args['minimum']));
            } elseif (empty($args['exclusiveMinimum']) && $value < $args['minimum']) {
                /* translators: 1: parameter, 2: minimum number */
                return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be greater than %2$d (inclusive)'), $param, $args['minimum']));
            }
        } elseif (isset($args['maximum']) && !isset($args['minimum'])) {
            if (!empty($args['exclusiveMaximum']) && $value >= $args['maximum']) {
                /* translators: 1: parameter, 2: maximum number */
                return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be less than %2$d (exclusive)'), $param, $args['maximum']));
            } elseif (empty($args['exclusiveMaximum']) && $value > $args['maximum']) {
                /* translators: 1: parameter, 2: maximum number */
                return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be less than %2$d (inclusive)'), $param, $args['maximum']));
            }
        } elseif (isset($args['maximum']) && isset($args['minimum'])) {
            if (!empty($args['exclusiveMinimum']) && !empty($args['exclusiveMaximum'])) {
                if ($value >= $args['maximum'] || $value <= $args['minimum']) {
                    /* translators: 1: parameter, 2: minimum number, 3: maximum number */
                    return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be between %2$d (exclusive) and %3$d (exclusive)'), $param, $args['minimum'], $args['maximum']));
                }
            } elseif (empty($args['exclusiveMinimum']) && !empty($args['exclusiveMaximum'])) {
                if ($value >= $args['maximum'] || $value < $args['minimum']) {
                    /* translators: 1: parameter, 2: minimum number, 3: maximum number */
                    return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be between %2$d (inclusive) and %3$d (exclusive)'), $param, $args['minimum'], $args['maximum']));
                }
            } elseif (!empty($args['exclusiveMinimum']) && empty($args['exclusiveMaximum'])) {
                if ($value > $args['maximum'] || $value <= $args['minimum']) {
                    /* translators: 1: parameter, 2: minimum number, 3: maximum number */
                    return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be between %2$d (exclusive) and %3$d (inclusive)'), $param, $args['minimum'], $args['maximum']));
                }
            } elseif (empty($args['exclusiveMinimum']) && empty($args['exclusiveMaximum'])) {
                if ($value > $args['maximum'] || $value < $args['minimum']) {
                    /* translators: 1: parameter, 2: minimum number, 3: maximum number */
                    return new WP_Error('rest_invalid_param', sprintf(__('%1$s must be between %2$d (inclusive) and %3$d (inclusive)'), $param, $args['minimum'], $args['maximum']));
                }
            }
        }
    }
    return true;
}