我如何解决这个 Wordpress Custom Gutenberg 块问题,在成功保存后加载一次渲染?

How can I fix this Wordpress Custom Gutenburg block problem with rendering once loading after it successfully saves?

正如标题所述,我正在自学如何为 wordpress 开发创建自定义 Gutenburg Block,并且我编写了以下代码。保存时它可以正常运行,但是当您重新加载保存的页面时,您会收到控制台错误并显示

This block contains unexpected or invalid content.

当您点击解析时,它会显示以下内容:

//  Import CSS.
import './editor.scss';
import './style.scss';

const { __ } = wp.i18n; // Import __() from wp.i18n
const { registerBlockType } = wp.blocks; // Import registerBlockType() from wp.blocks
const { RichText } = wp.blockEditor
const { withColors } = wp.blockEditor
const { PanelColorSettings} = wp.blockEditor;
const { InspectorControls } = wp.blockEditor;
const { PanelBody } = wp.components;


registerBlockType( 'cgb/block-my-block', {

    title: __( 'my-block - CGB Block' ), 
    icon: 'shield', 
    category: 'common', 
    keywords: [
        __( 'my-block — CGB Block' ),
        __( 'CGB Example' ),
        __( 'create-guten-block' ),
    ],
    attributes: {
        align: {
            type: 'string',
            default: 'full',
        },
        link_text: {
            selector: 'a', 
            source: 'children',  
        },
        link_url: {
                selector: 'a',  
                source: 'attribute', 
                attribute: 'href', 
        },
        txtColor: {
            type: 'string'
        },
        bgcolor: {
            type: 'string'
        },
    },
    supports: {
        align:true,
        //align: ['wide','full'], // limit only to these
    },

    getEditWrapperProps() {
        return {
            'data-align': 'full',
        };
    },

    edit: ( props ) => {

        let link_text = props.attributes.link_text 
        let link_url = props.attributes.link_url 
        let txtColor = props.attributes.txtColor
        let bgColor = props.attributes.bgColor

        function onChangeContentURL ( content ) {
            props.setAttributes({link_url: content})
        }

        function onChangeContentName ( content ) {
                props.setAttributes({link_text: content})
        }    
        
        function onChangeBGColor ( content ) {
            props.setAttributes({bgColor: content})
        }  

        function onChangeColor ( content ) {
            props.setAttributes({txtColor: content})
        }    

        return (
            
            
            <div className={ props.className } style={{ backgroundColor:bgColor, color: txtColor }}>


            <InspectorControls key= { 'inspector' } >
                    <PanelBody>

                    <PanelColorSettings 
                        title={ __('Title Color', 'tar') }
                        colorSettings= { [ 
                            {
                            value: txtColor,
                            onChange: (colorValue) => onChangeColor ( colorValue ),
                            label: __('Color', 'tar'),
                            },
                         ] }
                    />

                    <PanelColorSettings 
                        title={ __('Background Color', 'tar') }
                        colorSettings= { [ 
                            {
                            value: bgColor,
                            onChange: (colorValue) => onChangeBGColor ( colorValue ),
                            label: __('Color', 'tar'),
                            },
                         ] }
                    />

                </PanelBody>
            </InspectorControls>


                <p>Sample Link Block</p>
                <label>Name:</label>
                <RichText
                        className={props.className} // Automatic class: gutenberg-blocks-sample-block-editable
                        onChange={onChangeContentName} // onChange event callback
                        value={link_text} // Binding
                        placeholder="Name of the link"
                />
                <label>URL:</label>
                <RichText
                        format="string"             // Default is 'element'. Wouldn't work for a tag attribute
                        className={props.className} // Automatic class: gutenberg-blocks-sample-block-editable
                        onChange={onChangeContentURL} // onChange event callback
                        value={link_url} // Binding
                        placeholder="URL of the link"
                />   
                <p>— Hello from the backend.!!</p>

            </div>
        );
    },

    /**
     * The save function defines the way in which the different attributes should be combined
     * into the final markup, which is then serialized by Gutenberg into post_content.
     *
     * The "save" property must be specified and must be a valid function.
     *
     * @link https://wordpress.org/gutenberg/handbook/block-api/block-edit-save/
     *
     * @param {Object} props Props.
     * @returns {Mixed} JSX Frontend HTML.
     */
    save: ( props ) => {
        let txtColor = props.attributes.txtColor
        let bgColor = props.attributes.bgColor

        return (
            <div className={ props.className } style={{ backgroundColor:bgColor, color:txtColor }} >
                <p>— Hello from the frontend.</p>
                <a href={props.attributes.link_url}>{props.attributes.link_text}</a>
                </div>
        );
    },
} );

控制台错误看起来像 POST 和 SAVE 数据不同导致错误。

消息是:

Block validation: Block validation failed for `cgb/block-my-block` ({name: "cgb/block-my-block", icon: {…}, attributes: {…}, keywords: Array(3), save: ƒ, …}).

Content generated by `save` function:

<div class="wp-block-cgb-block-my-block alignfull" style="color:#000000"><p>— Hello from the frontend.</p><a></a></div>

Content retrieved from post body:

<div class="wp-block-cgb-block-my-block alignfull" style="background-color:#cd2653;color:#000000"><p>— Hello from the frontend.</p><a></a></div>

所以在我看来问题似乎出在根元素上的保存函数样式标签上。

<div className={ props.className } style={{ backgroundColor:bgColor, color:txtColor }} >

我删除了一种样式,只留下另一种样式,而且效果很好。把另一个放回去,它就坏了。我是否错误地包含了这种多种样式?如果是这样,添加保存在根元素上的多个样式的约定是什么?我也是新手,正在学习教程并阅读 Gutenburg github 文档。如果有什么基本的我做错了,请告诉我。

块验证问题是由一个小拼写错误引起的,您的属性 bgcolor(区分大小写)在 edit() 和 save() 中被称为 bgColor

您的代码表明您在创建自己的自定义古腾堡块方面走在了正确的道路上,因此我想分享一个建议,即使用 array destructuringprops 让您的代码更容易阅读和维护。您也可以删除仅调用 setAttributes() 的自定义 onChange 函数,转而直接调用 setAttributes,这样可以减少您需要编写的代码量,也可以减少拼写错误的几率。

例如:

//  Import CSS.
import './editor.scss';
import './style.scss';

const { __ } = wp.i18n; // Import __() from wp.i18n
const { registerBlockType } = wp.blocks; // Import registerBlockType() from wp.blocks
const { RichText } = wp.blockEditor
const { withColors } = wp.blockEditor
const { PanelColorSettings } = wp.blockEditor;
const { InspectorControls } = wp.blockEditor;
const { PanelBody } = wp.components;


registerBlockType('cgb/block-my-block', {

title: __('my-block - CGB Block'),
icon: 'shield',
category: 'common',
keywords: [
    __('my-block — CGB Block'),
    __('CGB Example'),
    __('create-guten-block'),
],
attributes: {
    align: {
        type: 'string',
        default: 'full',
    },
    link_text: {
        selector: 'a',
        source: 'children',
    },
    link_url: {
        selector: 'a',
        source: 'attribute',
        attribute: 'href',
    },
    txtColor: {
        type: 'string',
    },
    bgColor: {
        type: 'string',
    },
},
supports: {
    align: true,
    //align: ['wide','full'], // limit only to these
},

getEditWrapperProps() {
    return {
        'data-align': 'full',
    };
},
// Use array destructuring of props
edit: ({ attributes, className, setAttributes } = props) => {

    // Use array destructuring of the attributes
    const { link_text, link_url, txtColor, bgColor } = attributes;
    
    // Removed custom onChange functions that just call setAttributes

    return (

        <div className={className} style={{ backgroundColor: bgColor, color: txtColor }}>

            <InspectorControls key={'inspector'} >

                <PanelBody>

                    <PanelColorSettings
                        title={__('Title Color', 'tar')}
                        colorSettings={[
                            {
                                value: txtColor,
                                onChange: (colorValue) => setAttributes({ txtColor: colorValue }),
                                label: __('Color', 'tar'),
                            },
                        ]}
                    />

                    <PanelColorSettings
                        title={__('Background Color', 'tar')}
                        colorSettings={[
                            {
                                value: bgColor,
                                onChange: (colorValue) => setAttributes({ bgColor: colorValue }),
                                label: __('Color', 'tar'),
                            },
                        ]}
                    />

                </PanelBody>

            </InspectorControls>

            <p>Sample Link Block</p>
            <label>Name:</label>
            <RichText
                className={className} // Automatic class: gutenberg-blocks-sample-block-editable
                onChange={(content) => setAttributes({ link_text: content })} // onChange event callback
                value={link_text} // Binding
                placeholder="Name of the link"
            />
            <label>URL:</label>
            <RichText
                format="string" // Default is 'element'. Wouldn't work for a tag attribute
                className={className} // Automatic class: gutenberg-blocks-sample-block-editable
                onChange={(content) => setAttributes({ link_url: content })} // onChange event callback
                value={link_url} // Binding
                placeholder="URL of the link"
            />
            <p>— Hello from the backend.!!</p>

        </div>
    );
},

/**
 * The save function defines the way in which the different attributes should be combined
 * into the final markup, which is then serialized by Gutenberg into post_content.
 *
 * The "save" property must be specified and must be a valid function.
 *
 * @link https://wordpress.org/gutenberg/handbook/block-api/block-edit-save/
 *
 * @param {Object} props Props.
 * @returns {Mixed} JSX Frontend HTML.
 */
// Use array destructuring of props
save: ({ attributes, className } = props) => {

    // Use array destructuring of the attributes
    const { txtColor, bgColor, link_url, link_text } = attributes;

    return (
        <div className={className} style={{ backgroundColor: bgColor, color: txtColor }}>
            <p>— Hello from the frontend.</p>
            <a href={link_url}>{link_text}</a>
        </div >
    );
},
});