2

I'm trying to add a tailwind class to the block wrapper of a custom block I'm developing.

However, useBlockProps({className: 'h-full'}) generates an additional wrapper with the tailwind class name instead of adding the class to the block wrapper which is what I presumed it does.

I'm not able to figure out if this is expected behaviour from the sparse documentation on this hook. If it is, is there another way I could simply add a class to the block wrapper? If not, where am I going wrong? Code and image of outputted html below.

I should also add that I'm working with a dynamic block so I only need to add the class to the block wrapper in the editor and not on the front end.

import { registerBlockType } from "@wordpress/blocks"
import { Button,PanelBody,PanelRow } from "@wordpress/components"
import { InspectorControls,MediaUpload,MediaUploadCheck } from "@wordpress/block-editor"
import { useBlockProps,useInnerBlocksProps,InnerBlocks } from '@wordpress/block-editor';



registerBlockType("custom-cafe-theme/custom-column",{
    title: "Custom Column",
    attributes: {
        imgID: { type: "number" },
        imgUrl: { type: 'string',default: '' },

    },
    edit: EditComponent,
    save: SaveComponent
})

function EditComponent(props) {

    const blockProps = useBlockProps({ className: 'h-full' });
    const innerBlocksProps = useInnerBlocksProps({ className: 'grid gap-8 px-6 py-16' });

    function onImageSelect(image) {
        props.setAttributes({ imgID: image.id,imgUrl: image.url })
    }

    function removeImage() {
        props.setAttributes({ imgID: 0,imgUrl: '' })

    }


    return (
        <>
            <InspectorControls>
                <PanelBody>
                    <PanelRow>
                        <MediaUploadCheck>
                            <MediaUpload onSelect={onImageSelect} value={props.attributes.imgID} render={({ open }) => {
                                return <Button onClick={open}>Upload or Replace Image</Button>
                            }} />
                        </MediaUploadCheck>
                    </PanelRow>
                    <PanelRow>
                        <MediaUploadCheck>
                            <Button onClick={removeImage}>Remove Image</Button>
                        </MediaUploadCheck>
                    </PanelRow>
                </PanelBody>
            </InspectorControls>
            <div {...blockProps}>
                <div className="w-full min-h-[300px] bg-no-repeat bg-cover bg-center grid justify-center items-center text-center md:h-full md:min-h-[400px]" style={{ backgroundImage: `url('${props.attributes.imgUrl}')` }}>
                    <div {...innerBlocksProps}></div>
                </div>
            </div>
        </>
    )
}

function SaveComponent() {

    return <InnerBlocks.Content />

}

outputted html - editor screen

9
  • your save component is missing the proper usage of the useBlockProps hook, that's not how that hook works, or how the examples in the official docs work either.
    – Tom J Nowell
    Jun 26, 2023 at 14:37
  • Thank you for letting me know. I'm having trouble figuring out what the save component should look like for a dynamic block but I'll go back to the docs in case I've missed something.
    – Gayle F.
    Jun 26, 2023 at 14:57
  • when you say "dynamic" what do you mean? Do you mean for a block that isn't rendered in PHP? Do the official docs examples not show it?
    – Tom J Nowell
    Jun 26, 2023 at 14:58
  • 1
    oooh, in that case what you want to do may not be possible, there's zero documentation on how to render inner blocks from PHP because it's generally assumed it's not possible, and little to no tools or help is provided by the API. You're very much neck deep in highly experimental territory. At an absolute minimum though you aren't supposed to have a save component for a server rendered block. If your block is just a container though ( column ) then I don't see the need for PHP rendering, especially when it's a <div> with an inline style attribute, this could be simplified to a single <div>
    – Tom J Nowell
    Jun 26, 2023 at 15:20

1 Answer 1

1

I was bitten by this as well, and it caused me much frustration. I had exactly the same nested block duplication problem that you described above.

I was able to solve this issue by specifying an apiVersion for my custom block.

E.g.:

registerBlockType("custom-cafe-theme/custom-column",{
    apiVersion: 2, // or 3
    title: "Custom Column",
    attributes: {
        imgID: { type: "number" },
        imgUrl: { type: 'string',default: '' },

    },
    edit: EditComponent,
    save: SaveComponent
})

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.