4

I am playing with Gutenberg and I am a bit confused about how it should save to meta. Here is my custom post and meta:

add_action( 'init', function() {
    register_post_type( 'game', [
        'label' => 'Games',
        'public' => true,
        'supports' => [ 'editor', 'custom-fields' ],
        'show_in_rest' => true,
    ] );

    register_meta( 'game', 'logo', [
        'single' => true,
        'show_in_rest' => true,
        'description'  => 'A meta key associated with a string meta value.',
        'type' => 'string'
    ] );
} );

And my Block JS file:

( function( blocks, i18n, element ) {

    var el = element.createElement;
    var MediaUploadButton = wp.blocks.MediaUploadButton;
    var BlockControls = wp.blocks.BlockControls;

    blocks.registerBlockType( 'game-post/meta', {
        title: i18n.__( 'Game' ),
        description: i18n.__( 'Meta Box for Game' ),
        icon: 'businessman',
        category: 'common',
        attributes: { 
            logo: {
                type: 'string',
                source: 'meta',
                meta: 'logo'
            }   
        },
        edit: function(props) {
            console.log(props.attributes);
            var mediaURL = props.attributes.logo;
            return el('div', {
                classname: mediaURL ? 'image-active' : 'image-inactive'
            }, el('input', {
                defaultValue: mediaURL,
                type: 'text',
                onChange: function(e) {
                    props.setAttributes({ logo: e.target.value });
                }  
            }));
        },
        save: function(props) {
            return el( 'img', { src: props.attributes.logo } );
        }
    } );

} )(
    window.wp.blocks,
    window.wp.i18n,
    window.wp.element,
);

I took the source idea from WP Gutenberg Handbook. The attribute is created etc but the values are empty and the meta field is not saved. And the console log in edit function always returns null because there is no meta attribute. What am I doing wrong? If I change the attribute source to attribute, the field is saved properly.

4 Answers 4

1

The meta value is read when the block loads and assigned to the block attribute. Changes to the block will update the attribute and when the post saves the value will save to the meta. So, as far as I understood, there is no need to actually save anything in the registerBlockType js function. The block only saves to the meta so in the front end nothing will be rendered (unlike non-meta blocks).

So in your case:

add_action( 'init', function() {
    register_post_type( 'game', [
        'label' => 'Games',
        'public' => true,
        'supports' => [ 'editor', 'custom-fields' ],
        'show_in_rest' => true,
    ] );

    register_post_meta( 'game', 'logo', [
        'single' => true,
        'show_in_rest' => true,
        'description'  => 'A meta key associated with a string meta value.',
        'type' => 'string'
    ] );
} );

Notice that I used register_post_meta which was included in version 4.9.8 and allows to use the post type name ("game" in this case). As noticed by @LABCAT in the other answer using register_meta requires the type to be "post" even for custom post types.

Then in the JavaScript file:

registerBlockType( 'game-post/meta', {
    //...
    save: () => null,
});

I hope this helps.

0

I am trying to learn how to do this also. You have incorrectly registered your meta value, it should be:

register_meta( 'post', 'logo', [
    'single' => true,
    'show_in_rest' => true,
    'description'  => 'A meta key associated with a string meta value.',
    'type' => 'string'
] );

See the documentation for the $object_type param here: https://codex.wordpress.org/Function_Reference/register_meta

I don't think will make your JS code work though.

3
  • You are adding meta to default post but I have a custom post game and I want logo meta to only appear on that post type. The problem is that the meta does not save. I believe it is a JS problem.
    – Gasim
    Commented Jun 19, 2018 at 6:23
  • 3
    No, if you read the documentation linked above, the first parameter of register_meta should be 'post' even for custom post types. I got it working that way. You can check your meta field is available using the rest link, eg: example.com/wp-json/wp/v2/book/$ID If logo is not listed as a meta field then it will not save and it won't be listed until you change the first parameter of register_meta.
    – LABCAT
    Commented Jun 19, 2018 at 21:10
  • 1
    Since version 4.9.8 there is register_post_meta which accepts the post type.
    – Alvaro
    Commented Nov 24, 2018 at 21:52
0

Apart from any other errors that might be in your code that some others have pointed out, I've found that accessing attributes defined as "meta" from the save function has issues.

I've posted my own question about it here. and a bug report about it here.

Essentially, while the documentation says "meta attributes can be read and written by a block using the same interface as any attribute" ... it doesn't seem to be true from within the save function.

I've found the attributes (of source "meta") don't appear in the save function until the edit function specifically sets them using setAttribute it during that particular session on the editor page.

(Which means getting alignment between save and edit function output when returning to edit the page is very difficult).

My bug report linked above has more detail on what I've found if you need it.

0

Here is how you can register the post meta to make it accessible to the REST API :

/**
 * Registers the custom_post_meta field.
 *
 * @return void
 */
function register_custom_post_meta_field() {
    register_post_meta(
        'post',
        'custom_post_meta',
        [
            'type'         => 'string',
            'show_in_rest' => true,
            'single'       => true,
        ]
    );
}
add_action( 'init', 'register_custom_post_meta_field' );

Then you'll have to read and update the value on your custom block or component using the approach below:

import { __ } from '@wordpress/i18n';
import { useSelect, useDispatch } from '@wordpress/data';
import { PanelBody, PanelRow, TextControl } from '@wordpress/components';
import { InspectorControls } from '@wordpress/block-editor';

/**
 * My Custom Block
 */
const MyCustomBlock = () => {
    const META_KEY = 'custom_post_meta';
    const { editPost } = useDispatch('core/editor');
    const meta = useSelect((select) =>
        select('core/editor').getEditedPostAttribute('meta')
    );
    const { [META_KEY]: customMeta } = meta;

    const onCustomMetaChange = (newValue) => {
        editPost({
            meta: { ...meta, [META_KEY]: newValue },
        });
    };

    return (
        <div>
            <InspectorControls>
                <PanelBody title={__('Settings', 'textdomain')}>
                    <PanelRow>
                        <TextControl
                            label={__('Custom Meta', 'textdomain')}
                            value={customMeta}
                            onChange={onCustomMetaChange}
                        />
                    </PanelRow>
                </PanelBody>
            </InspectorControls>
        </div>
    );
};

I've created a full guide here on how to create and save post meta in the Gutenberg block editor. I hope this is exactly what everyone is looking for.

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.