Search code examples
reactjswordpresswordpress-gutenberggutenberg-blocks

"Attemp Block recovery" message after reloading block editor


I created a custom gutenberg block that contain two images. The blocks works fine until y reload the editor page or I close it and come back and my block has this message: "This block contains unexpected or invalid content." When I click on "Resolve" it marks the closing tag in the img tags.enter image description here

export default function save({ attributes}) {
  
      const blockProps = useBlockProps.save();
      return (
  
      <div  { ...blockProps }>
          
      <div className='col-text col'>
          <div className='name-icon'>
          <figure className='icon'>
          <a href={attributes.customUrl}>
          <img
                  className="icon-app"
                  src={ attributes.mediaURL }
                  alt="icono app"
              />
              </a>
          </figure>
          <h4>{attributes.softwareName}</h4>
          </div>
          <p>{attributes.softwareDescription}</p>
      </div>
      <figure className='col col-image'>
          <a href={attributes.customUrl}>
              <img src={ bannerImg } alt='imagen banner descarga' style='width: 100%;'></img>
          </a>
      </figure>
      
      </div>
  
      );
  
}

export default function Edit({attributes, setAttributes}) {
    

    return (
        <div className='banner-bsc' { ...useBlockProps() }>
        <div className='col-text col'>
            <div className='col-icon'>
        <MediaUpload
                    onSelect={
                        ( media ) => setAttributes( { mediaURL: media.url,
                                                        mediaID: media.id, })
                      }
                    allowedTypes="image"
                    value={ attributes.mediaID }
                    render={ ( { open } ) => (
                        <Button
                            className={
                                attributes.mediaID ? 'image-button' : 'button button-large'
                            }
                            onClick={ open }
                        >
                            { ! attributes.mediaID ? (
                                __( 'Sube el icono de la app', 'bsc-blocks' )
                            ) : (
                                <img
                                    className='icon-app'
                                    src={ attributes.mediaURL }
                                    alt={ __(
                                        'Sube el icono de la app',
                                    ) }
                                />
                            ) }
                        </Button>
                    ) }
                />
                </div>
        <RichText
                tagName="h4"
                placeholder={ __(
                    'CYPE Architecture'
                ) }
                value={ attributes.softwareName }
                onChange={( val ) => setAttributes( { softwareName: val }) }
                className="nombre-programa"
            />
            <RichText
                tagName="p"
                placeholder={ __(
                    '3D architectural modelling program, specifically designed for multidisciplinary collaboration.'
                ) }
                value={ attributes.softwareDescription }
                onChange={( val ) => setAttributes( { softwareDescription: val }) }
                className="descripcion-programa"
            />
        
            
        </div>
        <figure className='col col-image'>
        <TextControl
            label="Url banner"
            value={ attributes.customUrl }
            onChange={ ( val ) => setAttributes( {customUrl: val} ) }
        />
            <img src={ bannerImg } />
        </figure>
        </div>
    );
}
{
    "$schema": "https://schemas.wp.org/trunk/block.json",
    "apiVersion": 2,
    "name": "create-block/banner-descarga",
    "version": "0.1.0",
    "title": "Banner descarga",
    "category": "bimservercenter-categories",
    "icon": "smiley",
    "description": "Example block scaffolded with Create Block tool.",
    "supports": {
        "html": false
    },
    "textdomain": "banner-descarga",
    "editorScript": "file:./index.js",
    "editorStyle": "file:./index.css",
    "style": "file:./style-index.css", 
    "attributes": {
        "softwareName": {
            "type": "string",
            "source": "text",
            "selector": "div",
            "default": "CYPE Architecture"
        },
        "softwareDescription": {
            "type": "string",
            "source": "text",
            "selector": "div",
            "default": "3D architectural modelling program, specifically designed for multidisciplinary collaboration."
        }, 
        "customUrl" : {
            "type": "string",
            "source": "attribute",
            "selector": "a",
            "attribute": "href",
            "default": "https://store.bimserver.center/en/"

        },
        "mediaID": {
            "type": "number"
        },
        "mediaURL": {
            "type": "string",
            "source": "attribute",
            "selector": "img",
            "attribute": "src"
        }
        
    }
}



Solution

  • In your block.json, the attributes softwareName and softwareDescription both have "source": "text" and "selector": "div" which matches the text content of the outermost <div>...</div>. Any change to any attribute value from Edit() then invalidates the block as the content of <div>...</div> has changed.

    There is also a mismatch in your save() function as the attribute selectors don't match the generated content, ref:

    export default function save({ attributes}) {
        ...
          <div className='col-text col'>
              <div className='name-icon'>
              ...
              <h4>{attributes.softwareName}</h4> // softwareName selector should be "h4"
              </div>
              <p>{attributes.softwareDescription}</p> // softwareDescription selector should be "p"
          </div>
        ...
        ); 
    }
    

    There are multiple selector matches for <div> and more than one match for selectors <a> and <img>.

    To resolve this, each attribute selector should be specific and unique. In your Edit() function, you have already assigned unique classnames to the RichText components; so you can use these as the attribute selectors.

    Eg. for softwareName:

    Edit()

    <RichText
        tagName="h4"
        ...
        className="nombre-programa"
    />
    

    save()

    <h4 className="nombre-programa">{attributes.softwareName}</h4>
    

    block.json

    "softwareName": {
        "type": "string",
        "source": "text",
        "selector": ".nombre-programa",
        "default": "CYPE Architecture"
    },
    

    Once you have updated your attributes and save() function, the generated output from save() should map to the attributes and the block save correctly.