1

I have registered settings and need it to be showed in REST API.

$args = [
    'show_in_rest' => true
];
register_setting('default_sidebars', 'default_sidebars', $args);

When I save a single value and then request data on endpoint /wp-json/wp/v2/settings, everything works perfectly.

But the problem is that I save serialized data like this.

a:2:{s:4:"post";s:7:"general";s:4:"blog";s:9:"sidebar_1";}

Now I would expect in response something like this:

default_sidebars: {
  post: "general",
  blog: "sidebar_1"
}

But instead I got default_sidebars: null.

What should I do to get my data in REST API?

2

JSON Schema

It's supported if you explicitly register the object JSON schema as:

$args = array(
    'show_in_rest' => array(
        'schema' => array(
            'type'       => 'object',
            'properties' => array(
                'post' => array(
                    'type' => 'string',
                ),
                'blog' => array(
                    'type' => 'string',
                ),
            )
        ),
    ),
);

register_setting( 'default_sidebars', 'default_sidebars', $args );

Resulting in the following object:

default_sidebars: {
  post: "general",
  blog: "sidebar_1"
}

in /wp-json/wp/v2/settings for the serialized option data:

a:2:{s:4:"post";s:7:"general";s:4:"blog";s:9:"sidebar_1";}

See similar object schema support for register_meta() in 5.3:

https://make.wordpress.org/core/2019/10/03/wp-5-3-supports-object-and-array-meta-types-in-the-rest-api/

| improve this answer | |
  • Great, this works perfectly. Thank you. – Tomáš Vavřinka Mar 8 at 9:22
  • Silly me, I should've dug deeper on the type & properties when I actually saw them here yesterday! Anyway, +1 :) – Sally CJ Mar 8 at 10:50
2

Not sure if there's a better way when using the default Settings endpoint, but this works for me.

You can use the rest_pre_get_setting hook to convert the data to a JSON-encoded string:

add_filter( 'rest_pre_get_setting', function ( $value, $name ) {
    if ( 'default_sidebars' === $name ) {
        $value = json_encode( get_option( $name ) );
    }
    return $value;
}, 10, 2 );

Then for example in JavaScript, you can parse the value into an object using JSON.parse():

// Note: I intentionally omitted the authentication/nonce part.
fetch( 'https://example.com/wp-json/wp/v2/settings' )
    .then( res => res.json() )
    .then( settings => console.log( JSON.parse( settings.default_sidebars ) ) );

Or in PHP (e.g. you make the API request from another site using PHP), you can do:

$settings = json_decode( $data ); // assume data is the REST API response body
$default_sidebars = json_decode( $settings->default_sidebars );

Additional Notes

The null value is because get_option() unserializes the data to an array and the REST API controller for the Settings endpoint is using rest_validate_value_from_schema() to validate the option value (i.e. after being unserialized), which when it's not of the currently supported types (string, boolean, integer and number) — see register_setting(), then the function returns an error and the Settings endpoint/controller returns a null for that specific option.

Alternate Solution

You can create a custom REST API endpoint and with the following example, you would make request to /wp-json/myplugin/v1/setting/<option name> where <option name> could be default_sidebars in your case:

add_action( 'rest_api_init', function () {
    register_rest_route( 'myplugin/v1', '/setting/(?P<name>[a-zA-Z0-9\-_]+)', [
        'methods'  => 'GET',
        'callback' => function ( $request ) {
            return get_option( $request->get_param( 'name' ) );
        },
        'permission_callback' => function () {
            return current_user_can( 'manage_options' ); // you should keep this
        },
    ] );
} );
| improve this answer | |
  • 1
    Ok, maybe this is not the most elegant solution, but do the work. Thanks for help! – Tomáš Vavřinka Mar 7 at 17:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.