Search code examples
javascriptwordpresswordpress-gutenberg

Wordpress Gutenberg subscribe not getting updated meta field value


I've been trying to resolve this issue where using the Gutenberg meta box updates, doesn't fetch the new updated meta value.

Meta registration:

add_action('init', function() {

    register_meta('post', 'open_unit', array(
        'type'      => 'string',
        'single'    => true,
        'show_in_rest'  => true,
        'auth_callback' => function() {
            return current_user_can('edit_posts');
        }
    ));
    
    register_meta('post', 'open_active', array(
        'type'      => 'boolean',
        'single'    => true,
        'show_in_rest'  => true,
        'auth_callback' => function() {
            return current_user_can('edit_posts');
        }
    ));

    register_meta('post', 'open_abstract', array(
        'type'      => 'string',
        'single'    => true,
        'show_in_rest'  => true,
        'sanitize_callback' => function($text) {
            return sanitize_text_field($text);
        },
        'auth_callback' => function() {
            return current_user_can('edit_posts');
        }
    ));
});

Enqueue assets:

add_action('enqueue_block_editor_assets', function() {

    $screen = get_current_screen();
    if ($screen->post_type === 'page') return;
    
    wp_enqueue_script(
        'open-panel',
        plugin_dir_url( __FILE__ ) . 'js/admin.js',
        array('wp-i18n', 'wp-blocks', 'wp-edit-post', 'wp-element', 'wp-editor', 'wp-components', 'wp-data', 'wp-plugins', 'wp-edit-post', 'wp-api-fetch'),
        filemtime(dirname( __FILE__ ) . '/js/admin.js')
    );
});

Javascript:

const el = element.createElement;

    const { Fragment } = element;
    const { registerPlugin } = plugins;
    const { PluginDocumentSettingPanel } = editPost;
    const { TextareaControl, ToggleControl, Text } = components;
    const { withSelect, withDispatch, subscribe, registerStore } = data;

    const ActiveCheckboxControl = compose.compose(
        withDispatch(function(dispatch, props) {
            return {
                setMetaValue: function(metaValue) {
                    dispatch('core/editor').editPost(
                        //{ meta: { [props.metaKey]: (openValidate && metaValue) } }
                        { meta: { [props.metaKey]: metaValue } }
                    );
                }
            }
        }),
        withSelect(function(select, props) {
            return {
                metaValue: select('core/editor').getEditedPostAttribute('meta')[props.metaKey],
            }
        }))(function(props) {
            return el(ToggleControl, {
                label: props.title,
                checked: props.metaValue,
                onChange: function(content) {
                    props.setMetaValue(content);
                },
            });
        }
    );


    const AbstractTextControl = compose.compose(
        withDispatch(function(dispatch, props) {
            return {
                setMetaValue: function(metaValue) {
                    dispatch('core/editor').editPost(
                        { meta: { [props.metaKey]: metaValue } }
                    );
                }
            }
        }),
        withSelect(function(select, props) {
            return {
                metaValue: select('core/editor').getEditedPostAttribute('meta')[props.metaKey],
            }
        }))(function(props) {
            return el(TextareaControl, {
                label: props.title,
                value: props.metaValue,
                onChange: function(content) {
                    props.setMetaValue(content);
                }
            });
        }
    );


    registerPlugin('open', {
        render: function() {
            return el(Fragment, {},
                el(PluginDocumentSettingPanel,
                    {
                        name: 'open',
                        title: 'Open'
                    },
                    // Active
                    el(ActiveCheckboxControl,
                        {
                            metaKey: 'open_active',
                            title : 'Show'
                        }
                    ),
                    // Abstract
                    el(AbstractTextControl,
                        {
                            metaKey: 'open_abstract',
                            title : 'Abstract'
                        }
                    )
                )
            );
        }
    });

...

let isSavingChecked = true;
    let editor = data.select('core/editor');
    const getOpenUnit = () => editor.getEditedPostAttribute('meta') ? editor.getEditedPostAttribute('meta').open_unit : null;
    const getOpenActive = () => editor.getEditedPostAttribute('meta') ? editor.getEditedPostAttribute('meta').open_active : false;
    const getOpenAbstract = () => editor.getEditedPostAttribute('meta') ? editor.getEditedPostAttribute('meta').open_abstract : null;
    let openUnit = getOpenUnit();
    let openActive = getOpenActive();
    let openAbstract = getOpenAbstract();
    console.log(openUnit);
    const unsubscribe = subscribe( _.debounce( () => {

        const isSavingPost = editor.isSavingPost();
        const newOpenUnit = getOpenUnit();
        const newOpenActive = getOpenActive();
        const newOpenAbstract = getOpenActive();

        if (isSavingPost) {
            isSavingChecked = false;
        } else {
            if(!isSavingChecked) {
                let post = editor.getCurrentPost();

                let data = {
                    active: openActive ? 'active':'paused',
                    abstract: post.meta.open_abstract,
                    wp_id: post.id,
                    wp_title: post.title,
                    wp_url: post.link,
                    wp_image: post.featured_media
                }

                let openValidation = openValidate(data);

                if (openValidation.valid) {
                    if(openActive !== newOpenActive || openAbstract !== newOpenAbstract || openUnit !== newOpenUnit) {
                        openRemote(data);
                    } else {
                        console.log(newOpenUnit); //This field is not returning the updated meta field from Wordpress
                        openRemoteUpdate(data);
                    }

                } else {
                    wp.data.dispatch('core/notices').removeNotice('OPEN_NOTICE');
                    wp.data.dispatch('core/notices').createNotice(
                        'warning',
                        openValidation.messages.join(', '),
                        { id: 'OPEN_NOTICE', isDismissible: true }
                    );
                }
                isSavingChecked = true;
                openActive = newOpenActive;
                openAbstract = newOpenAbstract;
                openUnit = newOpenUnit;
            }
        }
    }));

I am basically trying to fetch the updated meta field: const getOpenUnit = () => editor.getEditedPostAttribute('meta') ? editor.getEditedPostAttribute('meta').open_unit : null;

But it's currently looking like this in the console where it's null(console.log(openUnit)) or empty(console.log(newOpenUnit)) https://share.getcloudapp.com/E0uYKWGv Lines 195 & 224

Any help or advice would be appreciated!


Solution

  • The easiest way I have found to get and set meta is using useEntityProp() in a function component. It is a lot easier to reason about than using withSelect and withDispatch.

    import { __ } from '@wordpress/i18n';
    import { useSelect } from '@wordpress/data';
    import { useEntityProp } from '@wordpress/core-data';
    import { TextControl } from '@wordpress/components';
    
    export default function MetaComponent(props) {
        const postType = useSelect((select) => {
            return select('core/editor').getCurrentPostType();
        });
    
        const [meta, setMeta] = useEntityProp('postType', postType, 'meta');
    
        return (
            <TextControl
                label={ __('Meta', 'pb') }
                value={ meta.open_abstract ? meta.open_abstract : '' }
                onChange={ (value) => setMeta({open_abstract: value}) }
            />
        );
    }