admin管理员组

文章数量:1126377

I’m extending a REST endpoint with register_rest_field();

The field I’m registering should accept an email address or an empty string.

I’m using the JSONschema to check and validate the format, like the below code:

register_rest_field(
    'my_custom_post', 
    'my_email_field', 
    array(
        'schema' => array(
        'type' => array('string','null'),
            'format' => 'email',
        'description' => 'Email address to use for contact',
        'context' => array('view','edit','embed'),
         ),
     'get_callback' => 'myemail_custom_get_callback',
     'update_callback' => 'myemail_custom_update_callback'
     )
);

The issue I have is that even if I put in the schema 'type' => array('string','null') I can’t POST a request with this field left empty, because WP always respond with rest_invalid_param and rest_invalid_email .

Only if I remove the'format' => 'email' argument, WP accepts both an empty field or a string as expected, but this way I can’t check if it’s a valid email anymore.

By reading here (especially the last example in that paragraph) I can’t see whats wrong with my schema. Could it be a bug?

I’m extending a REST endpoint with register_rest_field();

The field I’m registering should accept an email address or an empty string.

I’m using the JSONschema to check and validate the format, like the below code:

register_rest_field(
    'my_custom_post', 
    'my_email_field', 
    array(
        'schema' => array(
        'type' => array('string','null'),
            'format' => 'email',
        'description' => 'Email address to use for contact',
        'context' => array('view','edit','embed'),
         ),
     'get_callback' => 'myemail_custom_get_callback',
     'update_callback' => 'myemail_custom_update_callback'
     )
);

The issue I have is that even if I put in the schema 'type' => array('string','null') I can’t POST a request with this field left empty, because WP always respond with rest_invalid_param and rest_invalid_email .

Only if I remove the'format' => 'email' argument, WP accepts both an empty field or a string as expected, but this way I can’t check if it’s a valid email anymore.

By reading here https://developer.wordpress.org/rest-api/extending-the-rest-api/schema/#format (especially the last example in that paragraph) I can’t see whats wrong with my schema. Could it be a bug?

Share Improve this question asked Jan 18, 2024 at 12:53 StefanoStefano 1,2711 gold badge11 silver badges15 bronze badges
Add a comment  | 

2 Answers 2

Reset to default 4

even if I put in the schema 'type' => array('string','null') I can’t POST a request with this field left empty, because WP always respond with rest_invalid_param and rest_invalid_email

Actually, adding the 'null' there does not mean that any empty-ish values like '' and 0 will be allowed. It just means that an actual null value is allowed, apart from string. E.g. (these are JSON-encoded data)

  • {"my_email_field":"[email protected]"}
  • {"my_email_field":null}
  • {"my_email_field":""} ❌ (value is empty, but it's not a null)
  • {"my_email_field":"null"} ❌ (invalid email address..)

So if you had sent a null, you would have not received those errors.

But then, a null will unfortunately not pass the isset( $request[ $field_name ] ) validation in WP_REST_Controller::update_additional_fields_for_object(), hence the update callback will never be called. (See source on GitHub)

  • So maybe the WordPress core team should do something about that.. e.g. use array_key_exists() instead..

But as stated in @birgire's answer, you can use the anyOf or oneOf property to achieve what you were trying to do. (See source on GitHub)

Here's an example which requires the value to be an empty string where the length is exactly 0, or a non-empty string which must be a properly-formatted email address:

'schema' => array(
    'type'        => 'string',
    'oneOf'       => array(
        // Requires an empty string.
        array(
            'type'      => 'string',
            'maxLength' => 0,
        ),
        // Or if it's not empty, then it must be a valid email address.
        array(
            'type'   => 'string',
            'format' => 'email',
        ),
    ),
    'description' => 'Email address to use for contact',
    // Your other args.
),

Another one that you might want to try is, a custom validate callback which can be passed via arg_options.validate_callback like so:

  • Supplying the custom validate callback:

    'schema'          => array(
        'type'        => 'string',
        'arg_options' => array(
            'validate_callback' => 'myemail_custom_validate_callback',
        ),
        'description' => 'Email address to use for contact',
        // Your other args.
    ),
    
  • Sample callback:

    function myemail_custom_validate_callback( $value, $request, $param ) {
        // Requires an empty string or a valid email address.
        if ( 0 === strlen( $value ) || is_email( $value ) ) {
            return true;
        }
    
        return new WP_Error(
            'rest_invalid_param',
            sprintf( '%s is not a valid email address', $param )
        );
    }
    

Note: Specifying a custom validate callback means the default/core ones (e.g. rest_validate_value_from_schema()) would no longer be used, unless explicitly called from within your callback.

It looks like is_email() will return false for input less than 6 chars according to docs. Try instead for example anyOf or oneOf in the schema to separate the null type and the is_email check: (untested)

array(
    'schema' => array(
        'anyOf' => array(
            array(
                'type'   => 'string',
                'format' => 'email',
                …etc
            ),
            array(
                'type' => 'null',
                …etc
            ),
          ),
       ),
    ),
),

本文标签: REST API Schema how to allows for both empty string or email string