0

What is the best practice to do this in Gutenberg/JavaScript:

update_post_meta( $page_id, '_custom_post_meta', 'Some data to be saved' );
  • I need to do this from a sidebar box
  • Custom meta is registered, and I can update it for currently edited post
  • I need to do it for another post, not the one currently edited

Here is the use case:

const UpdateMeta = () => {

    const { editPost } = useDispatch( 'core/editor' );
    const onChange = ( value ) => {
        editPost( { // I am updating currently edited post here, and that's fine
            meta: { _custom_meta : JSON.stringify( value ) },
        } );

        // But, I would like to change some other post meta, selected by thID
    };

    return (
        <FormTokenField
            value={ selectedContinents }
            suggestions={ suggestionsList }
            __experimentalShowHowTo={false}
            onChange={ onChange }
            displayTransform={ prepare }
        />
    );
}


const Component = () => (
    <PluginDocumentSettingPanel
        title={ 'My Sidebar Box' }>
        <UpdateMeta/>
    </PluginDocumentSettingPanel>
);


registerPlugin( 'my-plugin-name', {
    icon: '',
    render: Component,
} );

I excluded nonrelevant parts of the code.

Update: I am sharing full code here (code is WIP, please ignore eventual mistakes and deficiencies:

const { registerPlugin } = wp.plugins;
const { FormTokenField } = wp.components;
const { PluginDocumentSettingPanel } = wp.editPost;
const { useSelect, useDispatch } = wp.data;
const { useState } = wp.element;
let targetType = '';

const RelatedDifferentTypePosts = () => {

    const postType = wp.data.select( 'core/editor' ).getCurrentPostType();

    switch ( postType ) {
            case 'display':
                targetType = 'event';
                break;
            case 'event':
                targetType = 'display';
                break;
    }

    const postMetaField = `_assigned_${  targetType  }s`;

    const isLoading = useSelect( ( select ) => {
        return select( 'core/data' ).isResolving( 'core', 'getEntityRecords',  [
            'postType', targetType
        ] );
    } );

    const assignedPosts = useSelect(
        ( select ) => select( 'core/editor' ).getEditedPostAttribute( 'meta' )[postMetaField], []
    );

    const targetPostsRaw = useSelect(
        ( select ) => select( 'core' ).getEntityRecords( 'postType', targetType ), []
    );

    let valueTitlePair = [];
    if ( targetPostsRaw ) {
        valueTitlePair = targetPostsRaw.map( ( postItem ) => {
            const tempObj = {};
            tempObj.id = postItem.id;
            tempObj.slug = postItem.slug;
            return tempObj;
        } );
    }

    const slugs = assignedPosts ? Array.from( JSON.parse( assignedPosts ), ( item ) => { return item.slug; } ) : [];
    const [ selectedPosts, setSelectedPosts ] = useState( slugs );

    let suggestionsList;
    if ( targetPostsRaw ) {
        suggestionsList = Array.from( targetPostsRaw, ( postItem ) => {
            return postItem.slug;
        } );
    }

    const { editPost } = useDispatch( 'core/editor' );
    const onChange = ( value ) => {

        /* Prevent entering non existing Events */
        value = value.filter( ( entry ) => suggestionsList.includes( entry ) );

        setSelectedPosts( value );
        value = valueTitlePair.filter( pair => value.includes( pair.slug ) );

        editPost( {
            meta: { [ postMetaField ] : JSON.stringify( value ) },
        } );
    };

    const prepare = ( token ) => {
        return token.replaceAll( '-', ' ' ).replace( /(^\w|\s\w)/g, m => m.toUpperCase() );
    };

    if ( isLoading ) {
        return <h3>Loading...</h3>;
    }

    return (
        <FormTokenField
            value={ selectedPosts }
            suggestions={ suggestionsList }
            __experimentalShowHowTo={false}
            onChange={ onChange }
            displayTransform={ prepare }
        />
    );
};

/**
 * Component
 */
const Component = () => (
    <PluginDocumentSettingPanel
        title={ `Related ${ targetType.charAt( 0 ).toUpperCase() + targetType.slice( 1 ) }s` }>
        <RelatedDifferentTypePosts/>
    </PluginDocumentSettingPanel>
);

registerPlugin( 'related-posts-of-different-type', {
    icon: '',
    render: Component,
} );
9
  • 1
    where are you doing this from? Is it a blocks edit component? A sidebar panel? Have you registered your meta? And is this for meta on the currently edited post?
    – Tom J Nowell
    Commented Sep 27, 2022 at 10:55
  • I apologize for lack of information, I thought it would be easier for people to understand and reply if I keep it short. I updated the question.
    – Tahi Reu
    Commented Sep 27, 2022 at 15:09
  • are parts still missing? I see references to variables that dont exist and you mention thID in a comment but it never appears in the code. What are you trying to do that requires this? Why do you need to modify other posts that aren't the post being edited?
    – Tom J Nowell
    Commented Sep 27, 2022 at 17:37
  • 1
    I just added the full code, I hope that helps.
    – Tahi Reu
    Commented Sep 28, 2022 at 9:14
  • 1
    restricting user creation of terms and eliminating the taxonomy management pages are doable and would make good questions on their own, I'd recommend asking them if they haven't been asked already even if you don't pursue that path
    – Tom J Nowell
    Commented Sep 28, 2022 at 12:03

1 Answer 1

0

I was able to do this using the Backbone JavaScript Client provided as part of the wp-api core scripts.

You can fetch a post, update its meta, and save it. Make sure you wp_enqueue_script( 'wp-api' ) or add it to your script's dependencies so the API is available in JavaScript at wp.api.

Example:

const post = new wp.api.models.Post( { id: 123 } );
post.fetch().done( () => {
    post.setMeta( 'your_meta_field', 'your_meta_string_content' );
    post.save().done( () => {
        // Any actions to perform after the meta has been saved.
    } );
} );

The Backbone Client methods don't have great documentation at the time of this writing, but you can inspect them in the source. For example, setMeta() is here: https://github.com/WordPress/WordPress/blob/master/wp-includes/js/wp-api.js#L543-L553

Be careful since the API returns promises for most methods; it's easy to make a mistake (e.g., trying to set the post meta before the post has been fetched, which won't do anything).

Also note that the REST API has endpoints for each post type, so you will need to use different models for each. For example, wp.api.models.Post, wp.api.models.Page, wp.api.models.YourCustomPostTypes, etc. You may have to save that info along with the ID so you know which endpoint to use.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.