web-dev-qa-db-fra.com

Erreur de validation: extension du bloc de galerie Gutenberg

J'essaie d'étendre le bloc Gutenberg core/gallery pour ajouter de nouvelles fonctionnalités à ma galerie d'images sur l'interface. J'ai créé un plugin séparé pour gérer cette tâche. J'ai enregistré mon script avec le code suivant:

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');

Dans mon fichier gallery-block.js, j’utilise le filtre blocks.getSaveElement pour éditer la sortie HTML- du bloc vers le client.

//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
}

Tout fonctionne comme prévu sauf lorsque je recharge l’éditeur Gutenberg. Lorsque je recharge la page, une erreur de validation survient et je ne suis pas autorisé à modifier le bloc de la galerie. (Voir les captures d'écran ci-dessous)

 Gallery block - before and after reload 

Ci-dessous, j'ai fourni une capture d'écran du journal de la console après avoir rechargé la page:

 Validation error - console log 

Je suis presque sûr que l'erreur se produit car ma sortie ne correspond pas à la structure attendue de la galerie. WordPress ne voit donc aucune image dans le bloc de la galerie lorsque je recharge la page.

Ma question est donc la suivante: comment puis-je corriger cette erreur de validation?

En supposant que l'erreur soit due à la différence entre ma structure HTML et la structure de galerie attendue: Comment puis-je faire en sorte que Gutenberg reconnaisse ma structure HTML en tant que galerie?

Toutes les suggestions seraient très appréciées. ????

5
Andreas

Répondant à ma propre question:

Comme suggéré par WebElaine j'ai créé un bloc complètement nouveau pour résoudre le problème. Pour faciliter cette tâche, j’ai utilisé create-guten-block d’Ahmad Awais , ce qui est assez facile à configurer.

Dans init.php, je me suis assuré de mettre en file d'attente mon JavaScript et du CSS supplémentaire pour l'interface. Cela devrait être simple. Je recommande de lire le série Learning Gutenberg sur css-tricks.com . Cela m'a été d'une grande aide pour commencer.

La partie importante est la façon dont j'ai créé le bloc de galerie. Dans block.js (créé par create-guten-block), j'ai déstructuré MediaUploadde wp.editor et Buttonde wp.components.

const { MediaUpload } = wp.editor; //Import MediaUpload from wp.editor
const { Button } = wp.components; //Import Button from wp.components

J'inscris le bloc avec un titre, une icône, une catégorie, des mots-clés et un attribut d'images avec le tableau de type. Cela contiendra les images de la galerie

 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',
        }
},

Ma fonction d'édition (la partie du bloc affichée dans l'éditeur) ressemble à ceci:

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>

        );
    },

Ici, je me sers des objets MediaUploadet Buttonname__. Notez que j'ai défini multiplesur truename__, ce qui me permet de sélectionner plusieurs images. Pour sélectionner plusieurs images de cette façon, vous devez maintenir CTRL comme vous le feriez en sélectionnant plusieurs fichiers dans l'explorateur de fichiers (sous Windows).

Dans ma fonction de sauvegarde, je mappe les images et ajoute les attributs souhaités à la balise imgname __-.

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>
    );

},

Mon code complet de block.js ressemble à ceci:

/**
 * 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>
        );

    },
} );

Après avoir ajouté quelques styles, ma galerie ressemble à ceci dans l'éditeur:

enter image description here

7
Andreas