Building a Featured Gallery component for Gutenberg

I’m building a Featured Gallery component for Gutenberg. As a guide, I’m using the existing Featured Image component from Gutenberg. Basically, instead of storing a single image id, the component stores an array of image ids in a dedicated meta field (of type array) called _featured_gallery.
Apparently, the getting and setting part is working, but I’m unable to show the grid of selected images (the featured-gallery-grid part in the code).
Any ideas? My knowledge of Gutenberg and React is limited, so I’m a bit lost here. Any help would be appreciated.

FeaturedGallery:

/**
 * WordPress dependencies
 */
const { __ } = wp.i18n;
const {
    BaseControl,
    Button,
    withNotices,
} = wp.components;
const { compose } = wp.compose;
const { withSelect, withDispatch } = wp.data;
const { MediaUpload, MediaUploadCheck }  = wp.blockEditor;

/**
 * Internal dependencies
 */

import GalleryImage from './gallery-image';

const ALLOWED_MEDIA_TYPES = [ 'image' ];

function FeaturedGallery( {
    currentPostId,
    featuredGalleryIds,
    onUpdateGallery,
    noticeUI,
} ) {
    const instructions = (
        <p>
            { __(
                'To edit the featured gallery, you need permission to upload media.', 'my-featured-gallery'
            ) }
        </p>
    );

    return (
        <BaseControl
            className="my-featured-gallery"
        >
            { noticeUI }
            <div className="editor-post-featured-gallery">
                <MediaUploadCheck fallback={ instructions }>
                    <div className="editor-post-featured-gallery__container">
                        { !! featuredGalleryIds && (
                            <ul className="featured-gallery-grid">
                            { featuredGalleryIds.forEach( ( img, index ) => {
                                <li>
                                    <GalleryImage
                                        id={ img }
                                    />
                                </li>
                            } ) }
                            </ul>
                        ) }
                    </div>
                    <MediaUpload
                        title={ __( 'Featured gallery', 'my-featured-gallery' ) }
                        multiple
                        onSelect={ onUpdateGallery }
                        allowedTypes={ ALLOWED_MEDIA_TYPES }
                        render={ ( { open } ) => (
                                <Button
                                    onClick={ open }
                                    isSecondary
                                >
                                    { 
                                        __( 'Add gallery images', 'my-featured-gallery' )
                                    }
                                </Button>
                        ) }
                        value={ featuredGalleryIds }
                    />
                </MediaUploadCheck>
            </div>
        </BaseControl>            
    );
}

const applyWithSelect = withSelect( ( select ) => {
    const { getPostType } = select( 'core' );
    const { getCurrentPostId, getEditedPostAttribute } = select(
        'core/editor'
    );
    const meta = getEditedPostAttribute( 'meta' );
    const featuredGalleryIds = meta._featured_gallery;

    return {
        currentPostId: getCurrentPostId(),
        postType: getPostType( getEditedPostAttribute( 'type' ) ),
        featuredGalleryIds,
    };
} );

const applyWithDispatch = withDispatch( ( dispatch ) => {
        const { editPost } = dispatch( 'core/editor' );
        return {
            onUpdateGallery( images ) {
                const items = images.map( ( item ) => item['id'] );
                const meta = { _featured_gallery: items };
                editPost( { meta } );
            },
        };
    }
);

export default compose(
    withNotices,
    applyWithSelect,
    applyWithDispatch,
)( FeaturedGallery );

GalleryImage:

/**
 * WordPress dependencies
 */
const { withSelect } = wp.data;
const { compose } = wp.compose;

/**
 * Internal dependencies
 */

function GalleryImage( {
    id,
    image
} ) {

    return (
        <figure>
            { image && ( <div className="img-container">
                <img
                    src={ image.media_details.sizes.thumbnail.source_url }
                    width={ image.media_details.sizes.thumbnail.width }
                    height={ image.media_details.sizes.thumbnail.height }
                    alt={ __( 'Thumbnail of the image.', 'my-featured-gallery' ) }
                    style={ {
                        display: 'block',
                        marginBottom: '8px',
                    } }
                />
            </div> ) }
        </figure>
    );

}

const applyWithSelect = withSelect( ( select, ownProps ) => {
    const { getMedia } = select( 'core' );
    const { id } = ownProps;
    return {
        image: id ? getMedia( parseInt( id, 10 ) ) : null,
    };
} );
    
export default compose( [
    applyWithSelect
] )( GalleryImage );

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

In your GalleryImage

const { withSelect } = wp.data;
const { compose } = wp.compose;

// You should define __
const { __ } = wp.i18n;

In your FeaturedGallery

  • You need to return the element, and set a key for the element (which is a list item): ( I also removed the index because it’s not being used.. if we define a variable, it should be used. 🙂 )

    And because an element should be returned, then you should use map() because forEach() doesn’t return anything and only applies a function to each element in the array.

    { featuredGalleryIds.map( ( img ) => {
        return (
            <li key={ img }>
                <GalleryImage
                    id={ img }
                />
            </li>
        );
    } ) }
    

    Alternate/simpler version — this is basically same as above, but you’d use the above if you want to perform some logic before the return line:

    { featuredGalleryIds.map( ( img ) => (
        <li key={ img }>
            <GalleryImage
                id={ img }
            />
        </li>
    ) ) }
    
  • Then (not a major issue, but) in the applyWithDispatch(), you should use the dot notation (item.id) and not the array notation (item['id']).
    const items = images.map( ( item ) => item.id );    // like this
    const items = images.map( ( item ) => item['id'] ); // not this
    


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x