验证错误:扩展Gutenberg图库块

时间:2018-09-10 作者:Andreas

我想把古腾堡core/gallery 阻止在前端的“我的图像库”中添加一些新功能。我已经创建了一个单独的插件来处理这个任务。我已使用以下代码注册了我的脚本:

function mt_enqueue_gutenberg(){

  wp_enqueue_script(
        \'mt-gallery-block\',
        plugins_url( \'gallery-block.js\',__FILE__),
        array( \'wp-blocks\', \'wp-i18n\', \'wp-element\' )
    );

    //Script and stylesheet loaded on frontend only
    if(!is_admin()){
      wp_enqueue_script(
        \'mt-gallery-frontend-script\',
        plugins_url( \'gallery.js\', __FILE__),
        array( \'mt-gallery-block\' )
      );

      wp_enqueue_style(
        \'mt-gallery-frontend-style\',
        plugins_url( \'gallery.css\', __FILE__),
        array( \'mt-gallery-block\' )
      );
    }
}

add_action( \'enqueue_block_editor_assets\', \'mt_enqueue_gutenberg\');
在我的gallery-block.js 文件我正在使用blocks.getSaveElement 用于编辑块的HTML-输出到前端。

//Filter hook
wp.hooks.addFilter(
    \'blocks.getSaveElement\',
    \'wpse-298225\',
    mt_gallerySaveElement
)

function mt_gallerySaveElement( element, blockType, attributes ) {
    //returns the element without changing it, if it is not the gallery block
    if ( blockType.name !== \'core/gallery\' ) {
        return element;
    }

    //Creates div element with nested img\'s
    var newElement = wp.element.createElement(
        \'div\',
        {
            \'className\': \'gallery-grid\',
            \'data-total-slides\': attributes.images.length
        },
        //Loops through each image in the gallery and creates an img-element
        attributes.images.map(
            function( image, index ) {
              return wp.element.createElement(
                        \'img\',
                        {
                            \'src\': image.url,
                            \'alt\': image.alt,
                            \'className\': \'gallery-item\',
                            \'data-slide-no\': index,
                            \'data-caption\': image.caption[0]
                        }
                    )

              }

        )
    )

    return newElement
}
除了我重新加载古腾堡编辑器外,其他一切都正常工作。重新加载页面时,出现验证错误,不允许编辑库块。(参见下面的屏幕截图)

Gallery block - before and after reload

下面我提供了重新加载页面后控制台日志的屏幕截图:

Validation error - console log

我很确定发生了错误,因为我的输出与库的预期结构不符,因此当我重新加载页面时,WordPress在库块内看不到任何图像。

So, my question is: How can I fix this validation error?

Assuming the error is caused by the difference between my HTML structure and the expected gallery structure: How can I make Gutenberg recognize my HTML structure as a gallery?

如有任何建议,将不胜感激。

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

Answering my own question:

根据建议WebElaine 我创建了一个全新的块来解决这个问题。为了简化这项任务,我使用create-guten-block by Ahmad Awais, 这很容易设置。

在初始化中。php我确保将我的JavaScript和额外的CSS排入前端。这应该是直截了当的。我建议阅读Learning Gutenberg series on css-tricks.com. 这对我的入门很有帮助。

重要的部分是我如何创建gallery块。在块中。js(由create guten block创建)我已解构MediaUpload 从…起wp.editor, 和Button 从…起wp.components.

const { MediaUpload } = wp.editor; //Import MediaUpload from wp.editor
const { Button } = wp.components; //Import Button from wp.components
我用一个标题、一个图标、一个类别、一些关键字和一个类型数组的图像属性来注册块。这将包含库中的图像

 registerBlockType( \'cgb/block-my-test-block\', {
    title: __( \'MT - Gallery\' ), // Block title.
    icon: \'format-gallery\', // Block icon from Dashicons → https://developer.wordpress.org/resource/dashicons/.
    category: \'common\', // Block category
    keywords: [ //Keywords
        __(\'materialtheme\'),
        __(\'photos\'),
        __(\'images\')
    ],
    attributes: { //Attributes
        images : { //Images array
            type: \'array\',
        }
},
我的编辑功能(编辑器中显示的块部分)如下所示:

edit({ attributes, className, setAttributes }) {

        //Destructuring the images array attribute
        const {images = []} = attributes;


        // This removes an image from the gallery
        const removeImage = (removeImage) => {
                    //filter the images
                    const newImages = images.filter( (image) => {
                        //If the current image is equal to removeImage the image will be returnd
                        if(image.id != removeImage.id) {
                            return image;
                        }
                    });

                    //Saves the new state
                    setAttributes({
                        images:newImages,
                    })
        }


        //Displays the images
        const displayImages = (images) => {
            return (
                //Loops throug the images
                images.map( (image) => {
                    return (
                    <div className="gallery-item-container">
                            <img className=\'gallery-item\' src={image.url} key={ images.id } />
                            <div className=\'remove-item\' onClick={() => removeImage(image)}><span class="dashicons dashicons-trash"></span></div>
                            <div className=\'caption-text\'>{image.caption[0]}</div>
                    </div>
                    )
                })

            )
        }

        //JSX to return
        return (
            <div>
                <div className="gallery-grid">
                    {displayImages(images)}
                </div>
                <br/>
                <MediaUpload
                        onSelect={(media) => {setAttributes({images: [...images, ...media]});}}
                        type="image"
                        multiple={true}
                        value={images}
                        render={({open}) => (
                            <Button className="select-images-button is-button is-default is-large" onClick={open}>
                                Add images
                            </Button>
                        )}
                    />
            </div>

        );
    },
在这里,我使用MediaUploadButton 对象请注意,我已设置multipletrue, 它允许我选择多个图像。要以这种方式选择多个图像,必须按住CTRL键,就像在文件资源管理器(Windows)中选择多个文件一样。

在保存功能中,我映射图像并将所需属性添加到img-标签

save({attributes}) {
    //Destructuring the images array attribute
    const { images = [] } = attributes;

    // Displays the images
    const displayImages = (images) => {
        return (
            images.map( (image,index) => {
                return (
                        <img
                            className=\'gallery-item\'
                            key={images.id}
                            src={image.url}
                            data-slide-no={index}
                            data-caption={image.caption[0]}
                            alt={image.alt}
                            />
                )
            })
        )
    }

    //JSX to return
    return (
        <div>
        <div className="gallery-grid" data-total-slides={images.length}>{ displayImages(images) }</div>
        </div>
    );

},
我的完整代码来自block。js如下所示:

/**
 * BLOCK: my-test-block
 *
 * Registering a basic block with Gutenberg.
 * Simple block, renders and saves the same content without any interactivity.
 */

import \'./style.scss\';
import \'./editor.scss\';

const { __ } = wp.i18n; // Import __() from wp.i18n
const { registerBlockType } = wp.blocks; // Import registerBlockType() from wp.blocks
const { MediaUpload } = wp.editor; //Import MediaUpload from wp.editor
const { Button } = wp.components; //Import Button from wp.components


/**
 * Register: aa Gutenberg Block.
 *
 * Registers a new block provided a unique name and an object defining its
 * behavior. Once registered, the block is made editor as an option to any
 * editor interface where blocks are implemented.
 *
 * @link https://wordpress.org/gutenberg/handbook/block-api/
 * @param  {string}   name     Block name.
 * @param  {Object}   settings Block settings.
 * @return {?WPBlock}          The block, if it has been successfully
 *                             registered; otherwise `undefined`.
 */

registerBlockType( \'cgb/block-my-test-block\', {
    title: __( \'MT - Gallery\' ), // Block title.
    icon: \'format-gallery\', // Block icon from Dashicons → https://developer.wordpress.org/resource/dashicons/.
    category: \'common\', // Block category
    keywords: [ //Keywords
        __(\'materialtheme\'),
        __(\'photos\'),
        __(\'images\')
    ],
    attributes: { //Attributes
        images : { //Images array
            type: \'array\',
        }
},

    /**
     * The edit function describes the structure of your block in the context of the editor.
     * This represents what the editor will render when the block is used.
     *
     * The "edit" property must be a valid function.
     *
     * @link https://wordpress.org/gutenberg/handbook/block-api/block-edit-save/
     */
    edit({ attributes, className, setAttributes }) {

        //Destructuring the images array attribute
        const {images = []} = attributes;


        // This removes an image from the gallery
        const removeImage = (removeImage) => {
                    //filter the images
                    const newImages = images.filter( (image) => {
                        //If the current image is equal to removeImage the image will be returnd
                        if(image.id != removeImage.id) {
                            return image;
                        }
                    });

                    //Saves the new state
                    setAttributes({
                        images:newImages,
                    })
        }


        //Displays the images
        const displayImages = (images) => {
            return (
                //Loops throug the images
                images.map( (image) => {
                    return (
                    <div className="gallery-item-container">
                            <img className=\'gallery-item\' src={image.url} key={ images.id } />
                            <div className=\'remove-item\' onClick={() => removeImage(image)}><span class="dashicons dashicons-trash"></span></div>
                            <div className=\'caption-text\'>{image.caption[0]}</div>
                    </div>
                    )
                })

            )
        }

        //JSX to return
        return (
            <div>
                <div className="gallery-grid">
                    {displayImages(images)}
                </div>
                <br/>
                <MediaUpload
                        onSelect={(media) => {setAttributes({images: [...images, ...media]});}}
                        type="image"
                        multiple={true}
                        value={images}
                        render={({open}) => (
                            <Button className="select-images-button is-button is-default is-large" onClick={open}>
                                Add images
                            </Button>
                        )}
                    />
            </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/
     */
    save({attributes}) {
        //Destructuring the images array attribute
        const { images = [] } = attributes;

        // Displays the images
        const displayImages = (images) => {
            return (
                images.map( (image,index) => {
                    return (
                            <img
                                className=\'gallery-item\'
                                key={images.id}
                                src={image.url}
                                data-slide-no={index}
                                data-caption={image.caption[0]}
                                alt={image.alt}
                                />
                    )
                })
            )
        }

        //JSX to return
        return (
            <div>
            <div className="gallery-grid" data-total-slides={images.length}>{ displayImages(images) }</div>
            </div>
        );

    },
} );
添加一些样式后,我的图库在编辑器中显示如下:

enter image description here

SO网友:omukiguy

2年后https://wordpress.stackexchange.com/a/313969/102683 仍然是最终的答案。

使用导入WordPress组件的新方法进行更新。

import { __ } from \'@wordpress/i18n\';
import { MediaUpload } from \'@wordpress/block-editor\';
import { Button } from \'@wordpress/components\';
import { registerBlockType } from \'@wordpress/blocks\';

结束