0

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

1 Answer 1

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
    
2
  • 1
    PS: Lol, sorry about the paragraph I deleted.. I thought I already removed it! xD
    – Sally CJ
    Jul 11, 2020 at 14:49
  • 1
    Thank you very much!
    – leemon
    Jul 11, 2020 at 15:12

Your Answer

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

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