How to update a meta field of type array in Gutenberg

The question:

In a plugin I’m building for Gutenberg, I register a meta field named _related_posts, which stores an array of post ids:

PHP:

function register_meta_fields() {
    register_post_meta( '', '_related_posts', array(
        'show_in_rest' => true,
        'single'       => true,
        'type'         => 'array',
        'show_in_rest' => array(
            'schema' => array(
                'type'  => 'array',
                'items' => array(
                    'type' => 'integer',
                ),
            ),
        ),
        'auth_callback' => function() {
            return current_user_can( 'edit_posts' );
        }
    ) );
}

I’m using the useEntityProp hook to get and set this meta field in JS:

JS:

const [ meta, setMeta ] = useEntityProp(
    'postType',
    'post',
    'meta'
);

I have a onUpdateRelatedPosts() function that gets called when the user selects a post from a list:

JS:

function onUpdateRelatedPosts( post ) {
    setMeta( { ...meta, '_related_posts': [post.id] } );
}

This function takes a post object as an argument and stores its id in the _related_posts meta field, but I can’t get it to work as I want. It doesn’t append the id at the end of the array but replaces the whole meta field with the added id.

What am I doing wrong?

The Solutions:

Below are the methods you can try. The first solution is probably the best. Try others if the first one doesn’t work. Senior developers aren’t just copying/pasting – they read the methods carefully & apply them wisely to each case.

Method 1

When you do this: '_related_posts': [post.id], you’re actually overriding the entire array or the meta value, so to instead append an item to the existing array, you can use the spread (...) syntax like so: '_related_posts': [ ...meta._related_posts, post.id ].

But you may want not want to update the meta if the selected post ID is already in the current meta value, i.e.

// Add the post (ID) if it's not already in the list.
if ( meta._related_posts.indexOf( post.id ) < 0 ) {
    setMeta( { ...meta, '_related_posts': [ ...meta._related_posts, post.id ] } );
}

That’s just a suggestion (to avoid duplicate values), though.

And BTW, for property names that do not contain characters that are not alphanumeric or underscore (_), it’s not mandatory to enclode the property name in quotes. So for example in your case, _related_posts: (as opposed to having the quotes: '_related_posts':) would be fine. 🙂


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Comment