I’ve covered adding custom fields to REST API responses before. While my original post from a few years ago is still largely valid, there are new improvements. I’d like to share what’s changed.
When I wrote that post, the only way to add a custom field to a response was using register_rest_field and adding your own read, write and schema handlers. That method still works. But, you can also use register_meta(), which handles the callbacks for you. If your custom fields are stored using the WordPress object’s standard meta API, for example, user meta for users, then this new method is simpler and generally better than the older way.
If you want to provide custom fields in your response that does not correspond to meta fields, then the old method, using register_rest_field directly makes sense. That’s for cases when you need to calculate a field or store it in an alternative location in the database.
Here is what you need to know now.
A Simple, And Powerful New Way
I’ve written about using register_meta() before. Originally this function’s job was simply to specify functions to be used in sanitizing meta fields value when writing and reading them. That’s still something you can and should do with register_meta.
In the past, we used a third argument for register meta that was a callable representing the sanitization function for the meta key. For example, this code causes the function absint to be called whenever the user meta field ‘xp’ is updated:
<?php register_meta( 'user', 'xp', 'absint' );
That still works. But we can now pass an array for the third argument. Here is the same thing with an array for the third argument:
<?php register_meta('user', 'xp', [ 'sanitize_callback' => 'absint', ] );
This does the same thing, but we can also add an argument for show_in_rest. With that one line, the user endpoints will now show xp as a child of meta.
<?php register_meta('user', 'xp', [ 'sanitize_callback' => 'absint', 'show_in_rest' => true, ] );
The result of adding the sanitization callback of absint is all data will be saved as a positive integer. We want the REST API to communicate that via its schema so clients and humans using the API will know that. So, let’s set the type to “integer” and describe the field in a human-readable way using description.
<?php register_meta('user', 'xp', [ 'sanitize_callback' => 'absint', 'show_in_rest' => true, 'type' => 'integer', 'description' => 'The total experience points earned by this user, as a positive integer', ] );
Now we have described the custom field to the client and humans, the key assumptions about the field have been documented and are programmatically enforced.
What About Auth?
I mentioned this will show that field to everyone who can access the endpoint. That means that anyone who can read users can see this field, and anyone who can edit users can edit this field.
You can register and authorization callback here. Just keep in mind, it will apply to all reads and writes of that meta key, which may or may not be a good thing. If you don’t want this, you can get more fine grain control using register_meta_field.
Here I added an “auth_callback” that checks if the current user has a custom capability:
That’s it. While it’s pretty simple to work with, register_meta can do a lot. For the most part, if you need to make a meta field available via the WordPress REST API — and by extension to Gutenberg — this is all you need.
That is if your custom field is post, comment, user, term, or other data supplied by the WordPress meta API. Don’t forget custom tables can also register meta, Pippin Williamson has a great article on how. The function register_rest_field() is the alternative for when a “custom field” of a REST API response is more custom, for example when the Meta API is not being used.
This article and the earlier articles on register_meta() and register_rest_field() should give you what you need to work with custom fields — meta fields and other non-standard data — via the WordPress REST API.