在Gutenberg/JS中使用Dispatch(‘core/EDITOR’).editPost()调用将多个元值设置为数组

时间:2019-10-16 作者:gardinermichael

我试图通过Gutenberg组件将图像的URL和ID存储在帖子的元字段中,但我很难弄清楚如何将这些多个值存储在一个数组中。

我可以毫无问题地将单个值存储为元值。我甚至可以毫无问题地将单个值存储在数组的第一个位置。但我似乎无法找到合适的语法来利用Wordpress将数组存储为元值的能力。

总体目标是覆盖在社交媒体上分享帖子时使用的图像。问题是,我需要将URL和ID都传输到PHP挂钩,以便它能够与插件(SEO框架)正常工作。不幸的是,我不能只存储ID,因为我需要URL来在Gutenberg组件中呈现图像。

完整组件代码:

const OGImage = 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 ) {
            const fallbackInstructions = <p>{ __( \'To edit the OG image, you need permission to upload media.\', \'atlantis\') }</p>;
            const onUpdateImage = img => { props.setMetaValue( img.url ); };
            const onRemoveImage = () => { props.setMetaValue( null ); };
        return (
        <div className="og-image__wrapper">
            <MediaUploadCheck fallback={ fallbackInstructions }>
                <MediaUpload
                    title={ OG_IMAGE_LABEL }
                    onSelect={ onUpdateImage }
                    allowedTypes={ ALLOWED_MEDIA_TYPES }
                    render={ ( { open } ) => (
                        <Button
                            className={ ! props.metaValue ? \'og-image__toggle\' : \'og-image__preview\' }
                            onClick={ open }
                            aria-label={ ! props.metaValue ? null : EDIT_OR_UPDATE_OG_IMAGE_LABEL }>
                            { !! props.metaValue &&
                                    <img className=\'og-image__button\' src={ props.metaValue } alt="" />
                            }
                            { ! props.metaValue && SET_OG_IMAGE_LABEL }
                        </Button>
                    ) }
                />
            </MediaUploadCheck>
            { !! props.metaValue &&
                    <MediaUploadCheck>
                        <MediaUpload
                            title={ OG_IMAGE_LABEL }
                            onSelect={ onUpdateImage }
                            allowedTypes={ ALLOWED_MEDIA_TYPES }
                            render={ ( { open } ) => (
                                <Button onClick={ open } isDefault isLarge>
                                    { REPLACE_OG_IMAGE_LABEL }
                                </Button>
                            ) }
                        />
                    </MediaUploadCheck>
                }
                { !! props.metaValue &&
                    <MediaUploadCheck>
                        <Button onClick={ onRemoveImage } isLink isDestructive>
                            { REMOVE_OG_IMAGE_LABEL }
                        </Button>
                    </MediaUploadCheck>
                }
        </div>
    );
    }
);

export default OGImage;
重要的位:

const OGImage = 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 ) {

            const onUpdateImage = img => { props.setMetaValue( img.url ); };

        return (

            <img className=\'og-image__button\' src={ props.metaValue } alt="" />

    );
    }
);

export default OGImage;

我的最佳解决方案是这样做,但这只存储指定的第一个值(因此在本例中,[img.url]):

const onUpdateImage = img => { props.setMetaValue( img.url, img.id ); };

...

<img className=\'og-image__button\' src={ props.metaValue[0] } alt="" />
甚至:

const onUpdateImage = img => { props.setMetaValue( [img.url, img.id] ); };

...

<img className=\'og-image__button\' src={ props.metaValue[0] } alt="" />
我将元值声明为:

  register_meta(
    \'post\',
    \'_og_image\',
    [
      \'show_in_rest\' => true,
      \'single\' => false,
      \'type\' => \'string\'
    ]
  );

作为最后的努力,我正在考虑将图像URL和ID组合成一个字符串,并在两端对其进行解析。这个解决方案让我觉得很粗糙,我更愿意将这两个值独立存储为一个数组。

这是一个crosspost.

Tom附录。这曾经奏效过——我想是出于某种奇怪的侥幸——但我无法复制它。图像url正在更改,但图像id拒绝保存在元值中。

PHP

function set_og_image() {
  register_meta(
    \'post\',
    \'og_image_url\',
    [
      \'show_in_rest\' => true,
      \'single\' => true,
      \'type\' => \'string\'
    ]
  );
  register_meta(
    \'post\',
    \'og_image_id\',
    [
      \'show_in_rest\' => true,
      \'single\' => true,
      \'type\' => \'string\' // Solution (thank you to Tom): This needs to be an integer type.
    ]
  );
}

JS公司

const OGImage = compose(
    withDispatch( function( dispatch, props ) {
        return {
            setMetaValue: function( metaKey, metaValue ) {
                dispatch( \'core/editor\' ).editPost(
                    { meta: { [ metaKey ]: metaValue } }
                );
            }
        }
    } ),
    withSelect( function( select, props ) {
        return {
            metaValueURL: select( \'core/editor\' ).getEditedPostAttribute( \'meta\' )[ \'og_image_url\' ],
            metaValueID: select( \'core/editor\' ).getEditedPostAttribute( \'meta\' )[ \'og_image_id\' ]
        }
    } ) )( function( props ) {
            const onUpdateImage = img => {
                props.setMetaValue( \'og_image_url\', img.url );
                props.setMetaValue( \'og_image_id\', img.id );
      };
            const onRemoveImage = () => {
                props.setMetaValue( props.metaKeyURL, null );
                props.setMetaValue( props.metaKeyID, null );
       };
        return (
                ...
    );
    }
);

父组件:

const { __ } = wp.i18n;
const { Fragment } = wp.element;
const { PanelBody, PanelRow } = wp.components;
const { registerPlugin } = wp.plugins;
const { PluginSidebar, PluginSidebarMoreMenuItem } = wp.editPost;

import OGImage from \'./components/og-image\';

const GenericSidebar = props => {
  return (
    <Fragment>
      <PluginSidebarMoreMenuItem target="generic-sidebar">
        {__("Generic Sidebar", "atlantis")}
      </PluginSidebarMoreMenuItem>
      <PluginSidebar
        name="generic-sidebar"
        title={__("Generic Sidebar", "atlantis")}
      >
        <PanelBody title={__("OG Image", "atlantis")} >
          <PanelRow>
            <OGImage
              metaKeyURL = { \'og_image_url\' }
              metaKeyID = { \'og_image_id\' }
             />
          </PanelRow>
        </PanelBody>
      </PluginSidebar>
    </Fragment>
  );
};

registerPlugin("generic-sidebar", {
  icon: "visibility",
  render: GenericSidebar
});

2 个回复
最合适的回答,由SO网友:Tom J Nowell 整理而成

您是否尝试过使用:

            setImage: function( image_url, image_id ) {
                dispatch( \'core/editor\' ).editPost(
                    {
                        meta: {
                            \'og_image_url\': image_url,
                            \'og_image_id\': image_id
                        }
                    }
                );
            }
而不是使用通用的setMetaValue函数?

SO网友:Tom J Nowell

简而言之,你不应该这样做。

Post-meta/etc只存储一个值,为了避免某些人使用PHP序列化数据。如果您传递数组或对象以便core可以存储字符串,core就会自动执行此操作。

问题是,这会让您面临PHP序列化攻击,这是一个安全问题。此外,它使查询这些值变得异常困难。

因此,正确的解决方案是存储2个元键/值对,而不是1个。也就是说打电话register_meta 两次,ID和URL的键名不同。

也可以通过REST API或本地存储检索给定附件ID的URL。您不需要将URL存储在post meta中,就可以显示附件ID预览。古腾堡用特色图片来管理它,所以这是可能的

相关推荐

Query posts only shows 1

我有一个ID数组:var_dump($userPostsInternal); -> string(13) \"128537,128545\" 那我会的$args = array( \'post__in\' => array($userPostsInternal), \'post_type\' => \'post\', \'posts_per_page\' => -1, ); $q = new WP