admin管理员组

文章数量:1309963

The problem: whenever I type something in Advanced->Additional Classes in Gutenberg editor and save the page/post and refresh, those classes disappear. I logged props.className in edit function. It logs the value as expected when I type the class name in the Advanced->Additional Classes field. The problem occurs when I save the post after inputting the class name and refresh the page. I followed the exact same method in other blocks I created and they work just fine.

The Code:

    edit: (props) => {
        const {attributes, setAttributes} = props;
        const headingBgOverlay = Util.getBgOverlay(attributes, 'heading');
        const bodyBgOverlay = Util.getBgOverlay(attributes, 'body');

        useEffect(() => {
            setAttributes({blockId: Util.guidGenerator()});
        }, []);

        useEffect(() => {
            console.log(props)
            console.log(props.className)
            console.log(attributes.className)
            setAttributes({headingBgOverlay});
            setAttributes({bodyBgOverlay});
        }, [attributes]);
        return (
            <Fragment>
                <Fragment>
                    <style>
                        {listIconCss(attributes)}
                    </style>
                    <div className={"atbs atbs-pricing-table " + props.className}
                         id={'atbs-pricing-table-' + attributes.blockId}>
                        <div className="plan"
                             style={{...planCss(attributes)}}>
                            <div className="head" style={{...titleCss(attributes)}}>
                                <RichText style={{...titleTypographyCss(attributes)}} tagName="h2" className={'m-0'}
                                          value={attributes.title}
                                          onChange={(title) => setAttributes({title})}
                                          placeholder={__('Plan name', 'attire-blocks')}/>
                            </div>
                            <div className='atbs_pricing_table_body'>
                                <RichText
                                    style={{...descrCss(attributes)}}
                                    className={'description'} tagName="p" value={attributes.description}
                                    onChange={(description) => setAttributes({description})}
                                    placeholder={__('Description...', 'attire-blocks')}/>
                                <div className="price" style={{...priceCss(attributes)}}>
                                    <RichText style={{fontSize: (attributes.priceFontSize / 2) + 'px'}}
                                              className={'symbol'}
                                              tagName="span" value={attributes.symbol}
                                              onChange={(symbol) => setAttributes({symbol})}
                                              placeholder={__('$')}/>
                                    <RichText className={'amount'}
                                              tagName="span" value={attributes.price}
                                              onChange={(price) => setAttributes({price})}
                                              placeholder={__('99.99')}/>

                                    {attributes.recurring && <RichText
                                        style={{fontSize: `${attributes.descrFontSize}${attributes.descrFontSizeUnit}`}}
                                        tagName="span" value={attributes.recurringTime}
                                        className="recurring"
                                        onChange={(value) => setAttributes({recurringTime: value})}
                                        placeholder={__('/month', 'attire-blocks')}/>}

                                </div>
                                {attributes.showFeatures && <RichText
                                    style={{...listCss(attributes)}}
                                    multiline="li"
                                    tagName="ul"
                                    className="features"
                                    onChange={(nextValues) => setAttributes({features: nextValues})}
                                    value={attributes.features}
                                    placeholder={__('Write list…', 'attire-blocks')}
                                />}

                                <InnerBlocks allowedBlocks={['attire-blocks/buttons']}
                                             template={[['attire-blocks/buttons', {
                                                 buttonAlignment: 'center'
                                             }]]}
                                             templateLock="all"/>
                            </div>
                        </div>
                    </div>
                </Fragment>
            </Fragment>
        );
    },
    save: ({attributes, className}) => {
        //const {attributes} = props;
        return (
            <Fragment>
                <style>
                    {listIconCss(attributes)}
                </style>
                <div className={"atbs atbs-pricing-table " + className}
                     id={'atbs-pricing-table-' + attributes.blockId}>
                    <div className="plan"
                         style={{...planCss(attributes)}}>
                        {attributes.title &&
                        <div className="head" style={{...titleCss(attributes)}}>
                            <RichText.Content style={{...titleTypographyCss(attributes)}} tagName="h2" className={'m-0'}
                                              value={attributes.title}/>
                        </div>}
                        <div className='atbs_pricing_table_body'>
                            {attributes.description &&
                            <RichText.Content
                                style={{...descrCss(attributes)}}
                                className={'description'} tagName="p" value={attributes.description}/>}
                            <div className="price" style={{...priceCss(attributes)}}>
                                <RichText.Content style={{fontSize: (attributes.priceFontSize / 2) + 'px'}}
                                                  className={'symbol'} tagName="span" value={attributes.symbol}/>
                                <RichText.Content
                                    style={{
                                        color: attributes.bodyTextColor,
                                        fontSize: (attributes.priceFontSize) + 'px'
                                    }}
                                    className={'amount'}
                                    tagName="span" value={attributes.price}/>
                                {attributes.recurring && <RichText.Content
                                    style={{fontSize: `${attributes.descrFontSize}${attributes.descrFontSizeUnit}`}}
                                    className="recurring"
                                    tagName="span" value={attributes.recurringTime}/>}
                            </div>
                        </div>
                        {attributes.showFeatures && <RichText.Content
                            style={{...listCss(attributes)}}
                            className={'features'}
                            tagName="ul" value={attributes.features}/>}
                        <InnerBlocks.Content/>
                    </div>
                </div>
            </Fragment>
        );
    }
});

The problem: whenever I type something in Advanced->Additional Classes in Gutenberg editor and save the page/post and refresh, those classes disappear. I logged props.className in edit function. It logs the value as expected when I type the class name in the Advanced->Additional Classes field. The problem occurs when I save the post after inputting the class name and refresh the page. I followed the exact same method in other blocks I created and they work just fine.

The Code:

    edit: (props) => {
        const {attributes, setAttributes} = props;
        const headingBgOverlay = Util.getBgOverlay(attributes, 'heading');
        const bodyBgOverlay = Util.getBgOverlay(attributes, 'body');

        useEffect(() => {
            setAttributes({blockId: Util.guidGenerator()});
        }, []);

        useEffect(() => {
            console.log(props)
            console.log(props.className)
            console.log(attributes.className)
            setAttributes({headingBgOverlay});
            setAttributes({bodyBgOverlay});
        }, [attributes]);
        return (
            <Fragment>
                <Fragment>
                    <style>
                        {listIconCss(attributes)}
                    </style>
                    <div className={"atbs atbs-pricing-table " + props.className}
                         id={'atbs-pricing-table-' + attributes.blockId}>
                        <div className="plan"
                             style={{...planCss(attributes)}}>
                            <div className="head" style={{...titleCss(attributes)}}>
                                <RichText style={{...titleTypographyCss(attributes)}} tagName="h2" className={'m-0'}
                                          value={attributes.title}
                                          onChange={(title) => setAttributes({title})}
                                          placeholder={__('Plan name', 'attire-blocks')}/>
                            </div>
                            <div className='atbs_pricing_table_body'>
                                <RichText
                                    style={{...descrCss(attributes)}}
                                    className={'description'} tagName="p" value={attributes.description}
                                    onChange={(description) => setAttributes({description})}
                                    placeholder={__('Description...', 'attire-blocks')}/>
                                <div className="price" style={{...priceCss(attributes)}}>
                                    <RichText style={{fontSize: (attributes.priceFontSize / 2) + 'px'}}
                                              className={'symbol'}
                                              tagName="span" value={attributes.symbol}
                                              onChange={(symbol) => setAttributes({symbol})}
                                              placeholder={__('$')}/>
                                    <RichText className={'amount'}
                                              tagName="span" value={attributes.price}
                                              onChange={(price) => setAttributes({price})}
                                              placeholder={__('99.99')}/>

                                    {attributes.recurring && <RichText
                                        style={{fontSize: `${attributes.descrFontSize}${attributes.descrFontSizeUnit}`}}
                                        tagName="span" value={attributes.recurringTime}
                                        className="recurring"
                                        onChange={(value) => setAttributes({recurringTime: value})}
                                        placeholder={__('/month', 'attire-blocks')}/>}

                                </div>
                                {attributes.showFeatures && <RichText
                                    style={{...listCss(attributes)}}
                                    multiline="li"
                                    tagName="ul"
                                    className="features"
                                    onChange={(nextValues) => setAttributes({features: nextValues})}
                                    value={attributes.features}
                                    placeholder={__('Write list…', 'attire-blocks')}
                                />}

                                <InnerBlocks allowedBlocks={['attire-blocks/buttons']}
                                             template={[['attire-blocks/buttons', {
                                                 buttonAlignment: 'center'
                                             }]]}
                                             templateLock="all"/>
                            </div>
                        </div>
                    </div>
                </Fragment>
            </Fragment>
        );
    },
    save: ({attributes, className}) => {
        //const {attributes} = props;
        return (
            <Fragment>
                <style>
                    {listIconCss(attributes)}
                </style>
                <div className={"atbs atbs-pricing-table " + className}
                     id={'atbs-pricing-table-' + attributes.blockId}>
                    <div className="plan"
                         style={{...planCss(attributes)}}>
                        {attributes.title &&
                        <div className="head" style={{...titleCss(attributes)}}>
                            <RichText.Content style={{...titleTypographyCss(attributes)}} tagName="h2" className={'m-0'}
                                              value={attributes.title}/>
                        </div>}
                        <div className='atbs_pricing_table_body'>
                            {attributes.description &&
                            <RichText.Content
                                style={{...descrCss(attributes)}}
                                className={'description'} tagName="p" value={attributes.description}/>}
                            <div className="price" style={{...priceCss(attributes)}}>
                                <RichText.Content style={{fontSize: (attributes.priceFontSize / 2) + 'px'}}
                                                  className={'symbol'} tagName="span" value={attributes.symbol}/>
                                <RichText.Content
                                    style={{
                                        color: attributes.bodyTextColor,
                                        fontSize: (attributes.priceFontSize) + 'px'
                                    }}
                                    className={'amount'}
                                    tagName="span" value={attributes.price}/>
                                {attributes.recurring && <RichText.Content
                                    style={{fontSize: `${attributes.descrFontSize}${attributes.descrFontSizeUnit}`}}
                                    className="recurring"
                                    tagName="span" value={attributes.recurringTime}/>}
                            </div>
                        </div>
                        {attributes.showFeatures && <RichText.Content
                            style={{...listCss(attributes)}}
                            className={'features'}
                            tagName="ul" value={attributes.features}/>}
                        <InnerBlocks.Content/>
                    </div>
                </div>
            </Fragment>
        );
    }
});
Share Improve this question edited Jan 5, 2021 at 8:12 Sally CJ 40.1k2 gold badges28 silver badges49 bronze badges asked Jan 5, 2021 at 6:24 Shafayat AlamShafayat Alam 1496 bronze badges 8
  • So after saving the post, does the console show any errors? And what happens when you comment out those useEffect()? – Sally CJ Commented Jan 5, 2021 at 8:15
  • no errors, just prints console.log(props.className) as undefined. Commenting out useEffects has no effect on the issue. – Shafayat Alam Commented Jan 5, 2021 at 8:28
  • Maybe it's another block of your own, or in a plugin or the active theme - try deactivating plugins. But if you can post a link to the full code (build & source versions), perhaps I (or someone else) can help you test the block. – Sally CJ Commented Jan 5, 2021 at 8:45
  • 1 Seems like the additional classes are being modified prior to WordPress/Gutenberg saving the post, and I'd probably try disabling the internal components (e.g. CSSEditor) and then see if there's any of them that's causing the issue. I.e. Try your block with the bare setup (basic code) and add the internal components one at a time. – Sally CJ Commented Jan 5, 2021 at 10:23
  • 1 Looks like the outmost <Fragment> was the culprit. But I still can't figure out why! Replacing it with <div> fixed it. – Shafayat Alam Commented Jan 5, 2021 at 14:14
 |  Show 3 more comments

2 Answers 2

Reset to default 1

After about an hour of trial and error, I found that the outmost <Fragment> was the culprit. But I still can't figure out why! Replacing it with <div> fixed it.

So the code looks like this now:

    edit: (props) => {
        const {attributes, setAttributes} = props;
        const headingBgOverlay = Util.getBgOverlay(attributes, 'heading');
        const bodyBgOverlay = Util.getBgOverlay(attributes, 'body');

        useEffect(() => {
            setAttributes({blockId: Util.guidGenerator()});
        }, []);

        useEffect(() => {
            console.log(props)
            console.log(props.className)
            console.log(attributes.className)
            setAttributes({headingBgOverlay});
            setAttributes({bodyBgOverlay});
        }, [attributes]);
        return (
                <div>
                    <style>
                        {listIconCss(attributes)}
                    </style>
                    <div className={"atbs atbs-pricing-table " + props.className}
                         id={'atbs-pricing-table-' + attributes.blockId}>
                        <div className="plan"
                             style={{...planCss(attributes)}}>
                            <div className="head" style={{...titleCss(attributes)}}>
                                <RichText style={{...titleTypographyCss(attributes)}} tagName="h2" className={'m-0'}
                                          value={attributes.title}
                                          onChange={(title) => setAttributes({title})}
                                          placeholder={__('Plan name', 'attire-blocks')}/>
                            </div>
                            <div className='atbs_pricing_table_body'>
                                <RichText
                                    style={{...descrCss(attributes)}}
                                    className={'description'} tagName="p" value={attributes.description}
                                    onChange={(description) => setAttributes({description})}
                                    placeholder={__('Description...', 'attire-blocks')}/>
                                <div className="price" style={{...priceCss(attributes)}}>
                                    <RichText style={{fontSize: (attributes.priceFontSize / 2) + 'px'}}
                                              className={'symbol'}
                                              tagName="span" value={attributes.symbol}
                                              onChange={(symbol) => setAttributes({symbol})}
                                              placeholder={__('$')}/>
                                    <RichText className={'amount'}
                                              tagName="span" value={attributes.price}
                                              onChange={(price) => setAttributes({price})}
                                              placeholder={__('99.99')}/>

                                    {attributes.recurring && <RichText
                                        style={{fontSize: `${attributes.descrFontSize}${attributes.descrFontSizeUnit}`}}
                                        tagName="span" value={attributes.recurringTime}
                                        className="recurring"
                                        onChange={(value) => setAttributes({recurringTime: value})}
                                        placeholder={__('/month', 'attire-blocks')}/>}

                                </div>
                                {attributes.showFeatures && <RichText
                                    style={{...listCss(attributes)}}
                                    multiline="li"
                                    tagName="ul"
                                    className="features"
                                    onChange={(nextValues) => setAttributes({features: nextValues})}
                                    value={attributes.features}
                                    placeholder={__('Write list…', 'attire-blocks')}
                                />}

                                <InnerBlocks allowedBlocks={['attire-blocks/buttons']}
                                             template={[['attire-blocks/buttons', {
                                                 buttonAlignment: 'center'
                                             }]]}
                                             templateLock="all"/>
                            </div>
                        </div>
                    </div>
                </div>
        );
    },
    save: ({attributes, className}) => {
        //const {attributes} = props;
        return (
            <div>
                <style>
                    {listIconCss(attributes)}
                </style>
                <div className={"atbs atbs-pricing-table " + className}
                     id={'atbs-pricing-table-' + attributes.blockId}>
                    <div className="plan"
                         style={{...planCss(attributes)}}>
                        {attributes.title &&
                        <div className="head" style={{...titleCss(attributes)}}>
                            <RichText.Content style={{...titleTypographyCss(attributes)}} tagName="h2" className={'m-0'}
                                              value={attributes.title}/>
                        </div>}
                        <div className='atbs_pricing_table_body'>
                            {attributes.description &&
                            <RichText.Content
                                style={{...descrCss(attributes)}}
                                className={'description'} tagName="p" value={attributes.description}/>}
                            <div className="price" style={{...priceCss(attributes)}}>
                                <RichText.Content style={{fontSize: (attributes.priceFontSize / 2) + 'px'}}
                                                  className={'symbol'} tagName="span" value={attributes.symbol}/>
                                <RichText.Content
                                    style={{
                                        color: attributes.bodyTextColor,
                                        fontSize: (attributes.priceFontSize) + 'px'
                                    }}
                                    className={'amount'}
                                    tagName="span" value={attributes.price}/>
                                {attributes.recurring && <RichText.Content
                                    style={{fontSize: `${attributes.descrFontSize}${attributes.descrFontSizeUnit}`}}
                                    className="recurring"
                                    tagName="span" value={attributes.recurringTime}/>}
                            </div>
                        </div>
                        {attributes.showFeatures && <RichText.Content
                            style={{...listCss(attributes)}}
                            className={'features'}
                            tagName="ul" value={attributes.features}/>}
                        <InnerBlocks.Content/>
                    </div>
                </div>
            </div>
        );
    }
});

Looks like the outmost <Fragment> was the culprit. But I still can't figure out why! Replacing it with <div> fixed it.

If you're on WordPress 5.6.0, you don't need to replace the <Fragment> with <div>. :)

And that's because WordPress 5.6.0 actually came with block API version 2 which introduced a new hook named useBlockProps that should be used in a block's edit() and save() functions — you can read more on the link I provided, but basically, with useBlockProps, you'd be able to use Fragment as the outmost wrapper.

Working example based on the one here:

import { registerBlockType } from '@wordpress/blocks';
import { useBlockProps, RichText } from '@wordpress/block-editor';
import { Fragment } from '@wordpress/element';

registerBlockType( 'my-plugin/foo-block', {
    // Required; use the block API version 2
    apiVersion: 2,

    title: 'Foo Block',
    category: 'design',

    attributes: {
        content: {
            type: 'array',
            source: 'children',
            selector: 'p',
        },
    },

    // In edit(), use useBlockProps()
    edit: ( props ) => {
        const { attributes: { content }, setAttributes, className } = props;
        const blockProps = useBlockProps();

        const onChangeContent = ( newContent ) => {
            setAttributes( { content: newContent } );
        };

        return (
            <Fragment>
                <div className={ blockProps.className }>
                    <RichText
                        { ...blockProps }
                        tagName="p"
                        onChange={ onChangeContent }
                        value={ content }
                    />
                    <p>{ 'Back-end: ' + blockProps.className }</p>
                </div>
            </Fragment>
        );
    },

    // In save(), use useBlockProps.save()
    save: ( props ) => {
        const blockProps = useBlockProps.save();

        return (
            <Fragment>
                <div className={ blockProps.className }>
                    <RichText.Content
                        { ...blockProps }
                        tagName="p"
                        value={ props.attributes.content }
                    />
                    <p>{ 'Front-end: ' + blockProps.className }</p>
                </div>
            </Fragment>
        );
    },
} );

So as you can see above, to get the additional CSS class(es) ( and other/auto-generated CSS class(es) ), I used blockProps.className and not props.className which gave us undefined.

本文标签: plugin developmentAdditional classes undefined after saving post in Gutenberg