Transition from (classical) serialized custom meta field to (gutenberg) rest enabled meta

I have a custom meta box for saving values from two input fields into a single post meta field.The data is saved seriali

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:

  1. [updated] How can I register the custom meta field for all of the post types in this list [ 'post', 'page', 'attachement' ]?
  2. 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:

  1. [updated] How can I register the custom meta field for all of the post types in this list [ 'post', 'page', 'attachement' ]?
  2. 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"}.

Share Improve this question edited Mar 6, 2019 at 14:53 Vlad asked Mar 6, 2019 at 13:20 VladVlad 1214 bronze badges 3
  • 1 I don't know the answer to 2 (as far as I can tell, register_meta() does not support array values), but in regards to 1, object_type is not the same as post_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, set object_type to post and object_subtype (in the args array) to the post type. – Jacob Peattie Commented Mar 6, 2019 at 13:39
  • object_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
  • Seems that way. – Jacob Peattie Commented Mar 6, 2019 at 14:59
Add a comment  | 

2 Answers 2

Reset to default 1

Here'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

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信