Really?

register_meta(), register_rest_field() and the WP REST API

There are two standard ways to add additional data into a post’s object in the WP REST API: register_meta() for post meta which is a string, number or boolean and register_rest_field()for everything else. There’s a bit on the difference between the two in the REST API docs. With Gutenberg, register_meta() is being used more widely and there’s some confusion about it, so let’s look at both in a little more depth.

Overview

register_meta() uses register_rest_field() under the hood — it puts the meta key and meta value into the “meta” field in the object response and the metadata registered can be accessed by Gutenberg using the “meta” attribute.

I always find it easier to see things, so here’s a post’s endpoint to show where each function puts its data.

register_meta_register_rest_field

When the Gutenberg docs say

Attributes may be obtained from a post’s meta rather than from the block’s representation in saved post content. For this, an attribute is required to specify its corresponding meta key under the meta key

They mean the keys listed under “meta” above, the ones which have been registered using register_meta().

In short, if you use register_meta() to register your metakey, you can use the built in functionality in the js function registerBlockType to get and update your data. If not — if you’re using register_rest_field() to register a new key — you’ll need to roll your own.

Why would you ever use register_rest_field() then? You’ll need it when the values you are trying to save aren’t numbers, strings or booleans or if you’re picking up the data somewhere other than the postmeta table.

Let’s look at register_rest_field.

register_rest_field()

I’m assuming some familiarity with this function. Here’s a gist with an overview / reminder of how it works. In short, I’m registering a new field with the response which will have the key registered. In the example above (screenshot below), the key is “mjj_objections”.

Screen Shot 2018-04-18 at 07.32.28

It will show up on all objects which are either “post” or “page”; it’s not possible to do logic regarding custom post types there, it’s not accessible on rest_api_init. NOTE TO SELF: check this. How does register_rest_field know the different between posts and pages? Hmmm. Anyway carrying on.

I haven’t used a schema because if I register it as type=”object” it seems to fail. I haven’t done a deep dive on that; I’m assuming it’s a quick validation check to not allow objects. (Not having a schema avoids that locked door 🙂 ) It’ll go back in when they are allowed.

The “get_callback” calls a function whose return value will be used as the value for the key registered above and returned in the post response (note: I’m going to use post meaning both post and page).

Screen Shot 2018-04-18 at 07.43.25

The “update_callback” will be called when there is a POST request to a post or page and the request contains the registered key. Again, you can do anything you’d like there (would a honeypot field with notifications ever be a good idea I wonder) but it’s most useful in doing what it says on the tin, ie updating the registered key’s value.

Screen Shot 2018-04-18 at 09.04.44

The full request is passed to both of those functions; there’s a lot of information there should you choose to use it.

SO.

How does register_meta() work?

register_meta()

This uses register_rest_field() to register its keys as keys in the “meta” field as above. It only accepts ‘integer’, ‘number’, ‘string’ or  ‘boolean’ as the type.

There’s been a fair amount written about it — the WordPress docs are here and this is a quick overview — but it pretty much does what you’d think. The image below is the beginning of the function.

Screen Shot 2018-04-18 at 09.51.45
not the whole function, just showing the defaults for $args

This is what registers a $meta_key to an $object_type with $args which can be:

  • type: as explained — ‘string’, ‘number’, ‘integer’, ‘boolean’. If you don’t list a type, it defaults to ‘string’. Type is used as a quick and dirty escaping method *if* there is no “prepare_callback” function in the “show_in_rest” value which we’ll get to below, don’t panic. The default escaping simply casts the value to its appropriate type and bails if it’s an object.
  • description: this explains itself?
  • single: true always returns a single value and false always returns an array. If you have multiple rows in the table for a given meta_key and object_id, it will return the first one if this is true. This can lead to some unexpected behaviour if you have multiple rows and think you only have one. I am writing this from experience.
  • sanitize_callback: this is a filter which runs on add_{$object_type}_meta and update_{$object_type}_meta and isn’t REST API specific.
  • auth_callback: a filter which runs in capabilities as `auth_{$object_type}_meta_{$meta_key}` It’s only for editing? This is a rabbit hole — if you are relying on this please test it and let me know how it works for you.
  • show_in_rest: if this is false, the key won’t show up in the rest api. If it’s true it will. Easy enough! But wait, you can pass it an array. NOT SO EASY NOW IS IT. Here are the defaults for that array (in get_registered_fields() here)
    Screen Shot 2018-04-18 at 10.59.08
    default args for show_in_rest (iff show_in_rest is true)

    The default args are simply what were registered before — name, type, single — but it’s possible to set different ones for use by the REST API like show_in_rest => array( [different ones] ). If there’s a schema, adding and updating will be validated against it. The default is built from the type and description. It’s also possible to set a value for the ‘default’ key which will be used if there’s no metadata to show.
    Screen Shot 2018-04-18 at 11.12.52

    Another extra is “prepare_callback” which will be used instead of the default escaping which uses type. This is *only* called when getting the value, not on updating or adding.

And that’s about it. register_meta() gets more complicated the more you get into it without adding any much functionality. The massive limitation is not being able to handle objects or arrays.

Join the newsletter

Subscribe to get the latest content by email.

Powered by ConvertKit. If you give me your email address, you may receive emails from me (JJ) about posts on this site. You can unsubscribe at any time.

Porchy Ltd is a company registered in England, no. 12035925

VAT Registration no. 331196421

Built with WPGraphQL and Gatsby

© 2019 - 2021