0

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>
        );
    }
});
8
  • So after saving the post, does the console show any errors? And what happens when you comment out those useEffect()?
    – Sally CJ
    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. 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
    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
    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. Jan 5, 2021 at 14:14

2 Answers 2

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>
        );
    }
});
1
  • 2
    I think this has to do with some of the block editor's magic, that tries to add the correct block/variant/etc. classes to the root element. If there is no root element (ie a Fragment), it seems to fail right now. Did you consider opening an issue in GitHub?
    – kero
    Jan 5, 2021 at 16:23
1

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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