• Ome

    (@midasbliss)


    I am trying to create an image slider with useInnerBlocksProps but, I can not get it to work. I am able to get the block to work when using InnerBlocks, but this adds unnecessary div wraps. The useInnerBlocksProps eliminates the divs.

    The current issue is that I’m unable to get the useInnerBlocksProps to output my slider-images. The console shows that an array of image exist, but it’s not sending to the editor or save. I’m relatively new to creating custom blocks. I’d really appreciate some help. Thank you. My code below;

    (function (blocks, blockEditor, components, i18n ) {
      const { createElement, Fragment, useState, useEffect } = wp.element;
      const { ToolbarGroup, ToolbarButton, PanelBody, SelectControl, RangeControl, ToggleControl  } = components;
      const { InspectorControls, BlockControls, MediaPlaceholder, BlockIcon, MediaUpload, MediaUploadCheck, useBlockProps,useInnerBlocksProps, InnerBlocks } = blockEditor;
      const el = createElement;
      const { __ } = wp.i18n;
      const { createHigherOrderComponent } = wp.compose;
    
      blocks.registerBlockType('pixie/slider', {
        apiVersion: 2,
        title: 'Pixie Slider',
        icon: 'format-gallery',
        category: 'media',
    
        attributes: {
          images: {
            type: 'array',
            default: [],
          },
          pixieId: {
            type: 'string',
          }
        },
        supports: {
          html: false,
          align: true,
          spacing: {
            margin: [
              "top",
              "bottom"
            ],
            padding: true,
            __experimentalDefaultControls: {
              padding: true
            }
          },
          __experimentalBorder: {
            color: true,
            style: true,
            width: true,
            __experimentalDefaultControls: {
              color: true,
              style: true,
              width: true
            }
          }
        },
        edit: function (props) {
          const { attributes, className, setAttributes, isSelected, clientId } = props;
          const { images } = attributes;
          const selectedImages = images || [];
          const hasSelectedImages = selectedImages.length > 0;
          const ALLOWED_BLOCKS =  ['pixie/slider-image'];
          const MY_TEMPLATE = selectedImages.map((image, index) => [ 'pixie/slider-image', { src: image.url, mediaId: image.id, key:index } ]);
          const blockProps = useBlockProps( { className: 'pixie-wrapper' } );
          const innerBlocksProps = useInnerBlocksProps( blockProps, { allowedBlocks: ALLOWED_BLOCKS, template: MY_TEMPLATE, orientation: "horizontal" } );
    
          console.log(MY_TEMPLATE);
          console.log(innerBlocksProps);
          
          return el(
            Fragment,
            null,
            isSelected && el(
              BlockControls,
              null,
              el(ToolbarGroup, null,
                el(MediaUploadCheck, null,
                  el(MediaUpload, {
                    multiple: true,
                    gallery: true,
                    addToGallery: true,
                    onSelect: function(newImages) {
                      setAttributes({ images: newImages });
                    },
                    allowedTypes: ['image'],
                    value: selectedImages.map(function (image) {
                      return image.id;
                    }),
                    render: function (_ref) {
                      var open = _ref.open;
                      return el(ToolbarButton, { onClick: open }, hasSelectedImages ? "Edit" : "Add");
                    }
                  })
                )
              )
            ),
    
            el(
              'div',
              { className: className },
              el(
                'div',
                {...innerBlocksProps},
                  !hasSelectedImages && el(MediaPlaceholder, {
                    labels: { title: 'Slider Images', instructions: 'Drag images, upload new ones or select files from your library.' },
                    onSelect: function(newImages) {
                      setAttributes({ images: newImages });
                    },
                    accept: 'image/*',
                    allowedTypes: ['image'],
                    multiple: true,
                    gallery: true,
                    icon: el(BlockIcon, { icon: 'format-gallery' })
                  })
              )
            )
          );
        },
        save: function (props) {
          const {className } = props;
          const newClassName = className || '';
          const selectedImages = images || [];
          const blockProps = useBlockProps.save( { className: 'pixie-wrapper' } );
          const innerBlocksProps = useInnerBlocksProps.save( blockProps );
    
          return 
            el(
              'div',
              {...innerBlocksProps}
            )
          );
        }
      });
    })(window.wp.blocks, window.wp.blockEditor, window.wp.components, window.wp.i18n);
    • This topic was modified 1 year, 6 months ago by Ome.
Viewing 2 replies - 1 through 2 (of 2 total)
  • Hi there,

    From the code you provided, you’re using useInnerBlocksProps to render inner blocks within your pixie/slider block. However, you’re also trying to add a MediaPlaceholder component within these inner blocks when no images are selected. This might be causing issues because useInnerBlocksProps is meant to be used solely for rendering inner blocks, and not other components.

    One possible solution is to conditionally render either the MediaPlaceholder or the inner blocks depending on whether images are selected:

        edit: function (props) {
          // ... your code ...
    
          return el(
            Fragment,
            null,
            isSelected && el(
              BlockControls,
              null,
              // ... your code ...
            ),
    
            el(
              'div',
              { className: className },
              hasSelectedImages ? 
              el(
                'div',
                {...innerBlocksProps}
              ) :
              el(MediaPlaceholder, {
                labels: { title: 'Slider Images', instructions: 'Drag images, upload new ones or select files from your library.' },
                onSelect: function(newImages) {
                  setAttributes({ images: newImages });
                },
                accept: 'image/*',
                allowedTypes: ['image'],
                multiple: true,
                gallery: true,
                icon: el(BlockIcon, { icon: 'format-gallery' })
              })
            )
          );
        },

    In the above code, I’ve used the ternary operator ? : to conditionally render either the inner blocks or the MediaPlaceholder based on the hasSelectedImages value.

    Another thing to note is that your save function doesn’t seem to make use of the images attribute, and it doesn’t have access to it currently. If you need to use the images attribute in the save function, you would need to destructure it from the props:

        save: function ({attributes, className}) {
          const {images} = attributes;
          // ... your code ...
        },

    Best regards,

    Christopher Amirian

    Rami

    (@ramchilla)

    Hi Ome,

    I was searching for another problem and came across this post. I don’t know if this will help your overall problem or not, but in the posted code, it looks like there is an extra parenthesis ending towards the bottom. The fifth line from the bottom in the posted code is an extra. Maybe try removing it so the bracket endings match.

    ...
    save: function (props) {
          const {className } = props;
          const newClassName = className || '';
          const selectedImages = images || [];
          const blockProps = useBlockProps.save( { className: 'pixie-wrapper' } );
          const innerBlocksProps = useInnerBlocksProps.save( blockProps );
    
          return 
            el(
              'div',
              {...innerBlocksProps}
            ) // THIS PARENTHESIS IS EXTRA, MAYBE REMOVE?
          );
        }
      });
    })(window.wp.blocks, window.wp.blockEditor, window.wp.components, window.wp.i18n);
Viewing 2 replies - 1 through 2 (of 2 total)
  • The topic ‘Issue using useInnerBlocksProps for custom block’ is closed to new replies.