admin管理员组

文章数量:1125596

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 />

}

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 />

}

Share Improve this question edited Jun 26, 2023 at 15:42 Gayle F. asked Jun 26, 2023 at 14:32 Gayle F.Gayle F. 213 bronze badges 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 Commented 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. Commented 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 Commented Jun 26, 2023 at 14:58
  • developer.wordpress.org/block-editor/reference-guides/block-api/…, likewise developer.wordpress.org/block-editor/how-to-guides/… were both the first 2 search results – Tom J Nowell Commented Jun 26, 2023 at 14:59
  • 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 Commented Jun 26, 2023 at 15:20
 |  Show 4 more comments

1 Answer 1

Reset to default 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
})

本文标签: plugin developmentuseBlockProps() nests wrapper with class name inside block wrapper in the editor