I have a custom meta box for saving values from two input fields into a single post meta field.
The data is saved serialized in the DB:
get_post_meta( $post->ID, '_custom_key', true )
will return:
a:2:{s:5:"email";s:10:"[email protected]";s:6:"number";i:15;}
Now, with Gutenberg, I want to move that whole custom meta box into a separate sidebar plugin. So in order to do this, first, I had to add the __back_compat_meta_box
argument when adding the meta box, so it won't appear in Sidebar -> Settings -> Document
anymore:
add_meta_box(
'options',
'Options',
[ $this, 'renderOptionsBox' ],
[ 'post', 'page', 'attachement' ], // the meta field is registered for multiple post types
'side',
'high',
[ '__back_compat_meta_box' => true ]
);
For the meta field (_custom_key
) to work with the block editor, it has to be registered using the register_meta
function:
register_meta( string $object_type, string $meta_key, array $args, string|array $deprecated = null )
My questions are:
- [updated] How can I register the custom meta field for all of the post types in this list
[ 'post', 'page', 'attachement' ]
? - How can I still follow the same serialized way of saving the data in a single field if the types ($args->type) supported when registering a meta are only 'string', 'boolean', 'integer', and 'number'?
Right now if I just register the _custom_key
meta using:
register_meta( 'post', '_custom_key', [
'show_in_rest' => true,
'single' => true,
'type' => 'string',
'auth_callback' => function () {
return current_user_can( 'edit_posts' );
}
]);
I will get a Notice: Array to string conversion in .../wp-includes/rest-api/fields/class-wp-rest-meta-fields.php
because already saved data from the DB is serialized.
and typing in the console: wp.data.select( 'core/editor' ).getCurrentPost().meta;
will return a string: {_custom_key: "Array"}
.
I have a custom meta box for saving values from two input fields into a single post meta field.
The data is saved serialized in the DB:
get_post_meta( $post->ID, '_custom_key', true )
will return:
a:2:{s:5:"email";s:10:"[email protected]";s:6:"number";i:15;}
Now, with Gutenberg, I want to move that whole custom meta box into a separate sidebar plugin. So in order to do this, first, I had to add the __back_compat_meta_box
argument when adding the meta box, so it won't appear in Sidebar -> Settings -> Document
anymore:
add_meta_box(
'options',
'Options',
[ $this, 'renderOptionsBox' ],
[ 'post', 'page', 'attachement' ], // the meta field is registered for multiple post types
'side',
'high',
[ '__back_compat_meta_box' => true ]
);
For the meta field (_custom_key
) to work with the block editor, it has to be registered using the register_meta
function:
register_meta( string $object_type, string $meta_key, array $args, string|array $deprecated = null )
My questions are:
- [updated] How can I register the custom meta field for all of the post types in this list
[ 'post', 'page', 'attachement' ]
? - How can I still follow the same serialized way of saving the data in a single field if the types ($args->type) supported when registering a meta are only 'string', 'boolean', 'integer', and 'number'?
Right now if I just register the _custom_key
meta using:
register_meta( 'post', '_custom_key', [
'show_in_rest' => true,
'single' => true,
'type' => 'string',
'auth_callback' => function () {
return current_user_can( 'edit_posts' );
}
]);
I will get a Notice: Array to string conversion in .../wp-includes/rest-api/fields/class-wp-rest-meta-fields.php
because already saved data from the DB is serialized.
and typing in the console: wp.data.select( 'core/editor' ).getCurrentPost().meta;
will return a string: {_custom_key: "Array"}
.
2 Answers
Reset to default 1Here's an answer to question 1 that uses register_post_meta
. It's also the start of an answer to question 2 by use of the prepare_callback
option in show_in_rest
.
add_action( 'init', 'wpse_89033_register_custom_meta' );
function wpse_89033_register_custom_meta() {
$post_types = [
'post',
'page',
'attachment',
];
foreach ( $post_types as $post_type ) {
register_post_meta(
$post_type,
'_custom_key',
array(
'type' => 'string',
'single' => true,
'auth_callback' => function() {
return current_user_can( 'edit_posts' );
},
'show_in_rest' => [
'prepare_callback' => function( $value ) {
return wp_json_encode( $value );
}
],
)
);
}
}
The documentation for show_in_rest
(see register_meta
) says it's a boolean parameter. But it will accept an options array. To see the options, look at the body of get_registered_fields
, in particular the value of $default_args
. The prepare_callback
overrides prepare_value
, the method in WP_REST_Meta_Fields
that converted your custom meta value from an array to a string. With our callback, that array will instead be encoded as JSON.
On the JavaScript side, here are some key declarations.
// Get the custom meta
let customMeta = wp.data.select('core/editor').getEditedPostAttribute('meta');
// Parse the meta so you can do some JS with it
let parsed = JSON.parse(customMeta._custom_key);
// Do some JS with the parsed meta...
// Stringify the parsed meta before dispatching it
let stringified = JSON.stringify(parsed);
/*
* Dispatch (update) the meta (and don't forget to
* save/publish/update the post to ensure the meta goes in the database)
*/
wp.data.dispatch('core/editor').editPost({meta: {_custom_key: stringified}});
Back in PHP land, getting and updating your custom meta will now work differently. When you call get_post_meta
, you're used to getting an array, and you'll probably still want one sometimes. But if you last updated your custom meta via the WP REST API, you're getting a JSON string. In that case, you'll have to use json_decode
. One approach would be to wrap calls to get_post_meta
like so:
function wpse_89033_get_custom_meta( $post_id, $meta_key ) {
$post_meta = get_post_meta( $post_id, $meta_key, true );
// If $post_meta is a string that's not empty
if ( $post_meta && is_string( $post_meta ) ) {
/*
* Use the decoded JSON string or else the original string
* if decoding fails, e.g., if the string isn't JSON
*/
$post_meta = json_decode( $post_meta, true ) ?: $post_meta;
}
return $post_meta;
}
If you make changes to your custom meta as an array, don't worry about re-encoding before calling update_post_meta
. The prepare_callback
will handle re-encoding.
About updating in PHP, calling update_post_meta
during save_post
, as shown in the official plugin handbook, appears to override updates made via the WP REST API. So one more thing to consider is conditioning any save_post
update to your custom meta on whether the post is being edited in Gutenberg. If it is, leave the update to the REST API.
In WordPress 5.3 you can now register meta with the array
and object
meta type. Here is the post from Make WordPress Core which gives all the details with examples:
- https://make.wordpress/core/2019/10/03/wp-5-3-supports-object-and-array-meta-types-in-the-rest-api/
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745091970a4610745.html
register_meta()
does not support array values), but in regards to 1,object_type
is not the same aspost_type
. The object type refers to whether it's for a post type, user or term. If you want to register it for specific post types, setobject_type
topost
andobject_subtype
(in the args array) to the post type. – Jacob Peattie Commented Mar 6, 2019 at 13:39object_subtype
still accepts only a string. Does that mean that I have to register the meta for each post I want? – Vlad Commented Mar 6, 2019 at 14:50