Support » Developing with WordPress » Custom fields in custom path in REST API response

  • Resolved semicolon83

    (@semicolon83)


    Hello,

    I have this issue as addressed here: https://stackoverflow.com/questions/57055013/how-to-nest-a-field-under-another-using-register-rest-field-in-wp-rest-api

    So I would like to expose custom fields (eg. created by Advanced Custom Fields, or programmaticaly) to WP REST API. Thats OK, I can accomplish that with register_rest_field function, which also support array values (unlike register_meta function).

    But I can not figure out, how to display the fields under the meta field. They are always shown only in top-level node.

    So instead:

    
    id: 1
    meta: []
    my_custom_field: "some value"
    my_another_custom_field:
        0: "Alfa"
        1: "Bravo"
        2: "Charlie"
    

    I need to expose them in this way:

    
    id: 1
    meta:
        my_custom_field: "some value"
        my_another_custom_field:
            0: "Alfa"
            1: "Bravo"
            2: "Charlie"
    

    Is there a way to do that?

Viewing 6 replies - 1 through 6 (of 6 total)
  • Moderator bcworkz

    (@bcworkz)

    You’d have to serialize/unserialize your array data yourself. Creating a custom route wouldn’t change this requirement of meta data because one simply cannot directly store array data in meta tables. WP normally serializes/unserializes automatically behind the scene, which is what happens with other rest fields. The only difference if using meta is where the data gets transformed. To get data to show up under “meta:” you must register the meta as a string, there is no way to register an array data type.

    If it’s any easier, you could store a JSON representation instead of serializing. Either way, the result needs to be escaped in order to deal with the quotes used in either format.

    semicolon83

    (@semicolon83)

    Thank you for your reply, but I am afraid, I don´t fully understand it.

    You say

    To get data to show up under “meta:” you must register the meta as a string, there is no way to register an array data type.

    So I have to use funcion register_meta (not register_rest_field). But how can I then unserialize the field content?

    If I try sanitize_callback (or auth_callback), they are not called at all

    
    $args = array(
    	'type'              => 'string',
    	'single'            => true,
    	'show_in_rest'      => true,		
    	'sanitize_callback' => function ( $meta_value, $meta_key, $meta_type ) {
    		die('This part is not accessed')
    	}
    );
    register_meta($objectType, $metaItem, $args);
    

    If it’s any easier, you could store a JSON representation

    I want to expose all possible custom fields, that are stored for example by Advanced Custom Fields plugin. So I have no power over storing them as JSON.

    Moderator bcworkz

    (@bcworkz)

    The sanitize_callback is called when data is saved through the API. ACF saves through normal POST requests (post.php), not the API, so the API sanitize_callback is not called.

    If ACF stores array data, it is serialized internally by WP without first externally converting it to a string. Because you have to register the meta field as a string, you will get PHP warnings about array to string conversion and the returned data will be something like: "meta":{"my_another_custom_field":"Array"}
    The underlying data in “Array” is inaccessible.

    In order to actually use saved array data under "meta": API data, you need to store the array data as a serialized string through your own means instead of relying upon ACF or WP to do it:
    update_post_meta((int)$_POST['post_ID'],'my_another_custom_field', serialize(['Alpha','Bravo','Charlie',]));
    Because serialize() returns a string, the API is happy, but an API request will return in part: "meta":{"my_another_custom_field":"a:3:{i:0;s:5:\"Alpha\";i:1;s:5:\"Bravo\";i:2;s:7:\"Charlie\";}"

    How that is unserialized depends on what language you are coding your app in. In PHP we unsurprisingly would use unserialize() after using json_decode() to convert all the JSON data returned by the API into PHP data.

    It looks like you could hook “acf/pre_update_metadata” to perform your own meta data update instead of letting ACF do it. (untested) There is no corollary filter I know of in ACF to convert data back to a proper array when it is gotten, but you could use “get_post_metadata” filter to get your data from the DB and send ACF the data in a form that it is expecting.

    In short, array data saved by ACF and getting array data to appear as meta data in an API response are mutually exclusive. Either store your own array meta data or use a rest field.

    semicolon83

    (@semicolon83)

    Thank you for your exhaustive answer. The problem is, that I have no control over how the data are stored. My code will serve as a plugin and will be installed on many websites with allready stored meta fields.

    I now know, that there is no way for me to expose custom fields under the meta attribute with register_rest_field.

    Last question: It has not to be meta attribute. Is it possible to expose custom fields under another custom attribute, eg. metadata?

    The result will then look something like this:

    
    id: 1
    name: "some_user_name"
    ...
    metadata:
        some_custom_field: some_value
        another_custom_field:
            0: Alpha
            1: Bravo
            2: Charlie
    
    Moderator bcworkz

    (@bcworkz)

    It’s not entirely true that you cannot control how data is stored if it is stored by ACF. ACF offers some filters that let you override how something is saved. In any case, having the API send serialized array data is rather hacky and requires the receiving app to be able to deal with such data.

    Meta fields and rest fields are your only choices with existing routes. What is it about register_rest_field that wouldn’t work? My understanding is it works for any arbitrary data since you create your own callbacks to handle getting and saving. My only experience so far has been with meta fields.

    If neither meta or rest fields work for whatever reasons, one could create a custom route and endpoints. Then you are only limited by what PHP is capable of. Such an endpoint can return any sort of data you could conceive of, but nothing more. To also return the other post data that rest and meta fields are included with, your endpoint callback needs to get all that data as well and compile it into a proper API response.

    Hi @bcworkz
    I am working on such data but the data when I am sending through WP REST API in array format it stores in the database with same field that I already registered but in different rows like in user_meta table it assigns different id’s to the same field name where the data is stored one by one not in one row.
    I want to store data in serialized form how can I do that.
    thanks

Viewing 6 replies - 1 through 6 (of 6 total)
  • You must be logged in to reply to this topic.