0

I'm trying the create a custom carousel block and I would like to have the same functionality that the gallery core block.

When I chose the images for the first time, everything works fine, but when I try to add extra images it actually wipes off the first ones and substitutes for the latest chosen ones.

export const carouselBlock = (
registerBlockType('gutenberg/custom-carousel', {
    title: 'Carousel',
    description: 'Block to generate a custom carousel',
    icon: 'images-alt2',
    category: 'layout',

    attributes: {
        selectedImages: {
            type: 'string',
            default: {},
        }
    },

    edit({ attributes, setAttributes}){
        const { selectedImages } = attributes;

        function onSelectImages(media) {
            const imagesUrl = values({...media}).map((item, i) => {
                return ({id: item.id, url:item.url});
            })
            setAttributes({ selectedImages: (values({...imagesUrl})) });
        }

        return (
            <div>
                {selectedImages.length > 0 &&
                    <figure className='wp-block-gallery columns-3'>
                        <ul className="blocks-gallery-grid">
                            {selectedImages.map((image, i) => {
                                return (
                                    <li key={i} className='blocks-gallery-item'>
                                        <figure>
                                            <img 
                                                src={image.url}
                                            />
                                        </figure>
                                    </li>
                                )
                            })}
                        </ul>
                    </figure>
                }
                <div className='carousel-block'>
                    <MediaUploadCheck>
                        <MediaUpload
                            onSelect={(media) => onSelectImages(media)}
                            // value={media => selectedImages.push(media)}
                            multiple={'add'}
                            render={ ( { open } ) => (
                                <IconButton 
                                    onClick={open}
                                    icon="upload"
                                    className="editor-media-placeholder__button is-button is-default is-large"
                                >
                                    Open Media Library
                                </IconButton>
                            ) }
                        />
                    </MediaUploadCheck>
                </div>
            </div>
        );
    },
    save({attributes}){
        const { selectedImages } = attributes;

        return (
            <div>
                {selectedImages.map((image, i) => {
                    return (<p key={i}>{image}</p>)
                })}
            </div>
        )
    }

})

)

I also tried to extend the gallery like so:

enter image description here

but then the user won't know that the gallery also can be a carousel unless he clicks on the block.

Is there a way that I can "clone" a core block? (situation 1) Or that I can change its name? (situation 2)

Thanks in advance!

Dani

4
  • Would it be useful to add a style to the gallery block instead? I also wouldn't use gutenberg as your blocks namespace. Also, you declare that the selectedImages attribute is a string, but then iterate over it as an array 🤔, is that intentional?
    – Tom J Nowell
    Feb 26, 2020 at 13:18
  • Hi @TomJNowell , in the second situation I do add a class to the gallery block, then with this class I can parse it in the frontend to my custom component, but the block name is still Gallery, so the user would only know that can have a carousel if it clicks in this block. For your second question, I don't really know how to answer...cause the truth is that I'm new to wordpress
    – danihazler
    Feb 26, 2020 at 13:55
  • @TomJNowell, do you think I could use something like const BLOCK_TEMPLATE = ['core/gallery']; and then add to my block like: <div className='carousel-block'> <InnerBlocks allowedBlock={BLOCKS_TEMPLATE} /> </div> ?
    – danihazler
    Feb 26, 2020 at 17:11
  • Yes, but that would be a fundamentally different approach, you'd have no control over the gallery blocks internals, users would still need to add a gallery, and could add multiple galleries, at that point you might as well use a block style, or add a CSS class via the existing sidebar option
    – Tom J Nowell
    Feb 27, 2020 at 10:25

1 Answer 1

1

There may be several other issues interacting here, but the big one is here:

        function onSelectImages(media) {
            const imagesUrl = values({...media}).map((item, i) => {
                return ({id: item.id, url:item.url});
            })
            setAttributes({ selectedImages: (values({...imagesUrl})) });
        }

When images are picked, you grab the images and set them as the selected images. This is not the same as adding them, You need to fetch the existing selected Images and append the two.

The assumption is that media contains all the selected images, and that you've added images. This is incorrect.

Instead, you've chosen images, and it's the images you chose that are in media, and you're setting it. Unless you re-chose the images from before, they aren't in there.

What you're currently doing is the equivalent of something like this in PHP:

$images = [];

function on_new_images( $new_images ) {
     $new_urls_ids = foreach new images get URLs and IDs...
     $images = $new_urls_ids;
}

When really what you want is more like this:

$images = [];

function on_new_images( $new_images ) {
     $new_urls = foreach new images get URLs...
     $images = array_merge( $images, $new_urls );
}

But the JS equivalent

1
  • thank you so much for your answer, I'll have a look at it. :)
    – danihazler
    Feb 26, 2020 at 14:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.