Search code examples
wordpresswordpress-gutenberggutenberg-blocks

How do I properly deprecate Gutenberg block


I have a custom Gutenberg block (https://pastebin.com/bV2k5Ekc) in which I display text, link and an image. I want to change it so so instead of saving the image URL as a background image of the container, to use an img tag. Unfortunately - I can't manage to create the deprecation correctly - I fail at assigning the attributes parameters in the deprecation:

From this:

    const {
      attributes: {
        mediaURL,
        boxTitle,
        boxDescription,
        linkText,
        linkHref,
        linkTitle
      },
      className,
    } = props;

    let boxClass = 'cta-box';
    let contentDescription = '';

    if (boxDescription.length) {
      boxClass += ' cta-box-description';
      contentDescription = (
        <p>
          {boxDescription}
        </p>
      )
    }

    return (
      <div className={`cta-block-box ${className}`}>
        <a
          className="cta-box-link"
          href={linkHref}
          style={{ backgroundImage: "url(" + mediaURL + ")" }}
          rel="noopener noreferrer"
        >
          <div className={boxClass}>
            <h3>
              {boxTitle}
            </h3>
            {contentDescription}
            <span className="arrow">{linkText ? linkText : linkTitle}</span>
          </div>
        </a>
      </div>
    );
  },

To this (I only change what's in the return statement):

return (
      <div className={`cta-block-box ${className}`}>
        <a
          className="cta-box-link"
          rel="noopener noreferrer"
        >
          <img className="cta-box-image" src={linkHref} alt=""/>
          <div className={boxClass}>
            <h3>
              {boxTitle}
            </h3>
            {contentDescription}
            <span className="arrow">{linkText ? linkText : linkTitle}</span>
          </div>
        </a>
      </div>
    );

Which of course broke the Gutenberg element. So I added a deprecate to the blog, as much as I could following the official Wordpress documentation:

deprecated: [
    {
      attributes: {...this.attributes},
      save: (props) => {
        const {
          attributes: {
            mediaURL,
            boxTitle,
            boxDescription,
            linkText,
            linkHref,
            linkTitle
          },
          className,
        } = props;
        console.log('dep');
        console.log(props);

        let boxClass = 'cta-box';
        let contentDescription = '';

        if (boxDescription.length) {
          boxClass += ' cta-box-description';
          contentDescription = (
            <p>
              {boxDescription}
            </p>
          )
        }

        return (
          <div className={`cta-block-box ${className}`}>
            <a
              className="cta-box-link"
              style={{ backgroundImage: "url(" + mediaURL + ")" }}
              rel="noopener noreferrer"
            >
              <div className={boxClass}>
                <h3>
                  {boxTitle}
                </h3>
                {contentDescription}
                <span className="arrow">{linkText ? linkText : linkTitle}</span>
              </div>
            </a>
          </div>
        );
      },
    }
  ],

After this the editor page crashes, and I get error message in console, that attributes is not defined (displaying incorrect row in the script file). This is the "after" script contents (https://pastebin.com/dVdLMx7N).

react-dom.min.js?ver=16.13.1:125 ReferenceError: attributes is not defined
    at save (cta-box2.js?f66a:242)
    at Wt (blocks.min.js?ver=9ed25ffa009c799f99a4340915b6dc6a:3)
    at Qt (blocks.min.js?ver=9ed25ffa009c799f99a4340915b6dc6a:3)
    at block-editor.min.js?ver=4378547cec8f5157a02ead3dfc5c65b2:12
    at hooks.min.js?ver=50e23bed88bcb9e6e14023e9961698c1:2
    at $r (blocks.min.js?ver=9ed25ffa009c799f99a4340915b6dc6a:3)
    at blocks.min.js?ver=9ed25ffa009c799f99a4340915b6dc6a:3
    at Ur (blocks.min.js?ver=9ed25ffa009c799f99a4340915b6dc6a:3)
    at blocks.min.js?ver=9ed25ffa009c799f99a4340915b6dc6a:3
    at Array.reduce (<anonymous>)

Any help would be greatly appreciated! I suspect I'm missing some small detail, but so far I've failed to locate it. And was not able to find relevant enough information on the web.

Thanks in advance!


Solution

  • There are two issues in your "after" script:

    1. The attributes do not match (and the this is actually the window object): attributes: {...this.attributes} (see line 212).

      So what you used with the attributes property on line 24, should also be used with the same property on line 212. (because you only changed the output, so the block attributes remain the same)

    2. The save output/markup also do not match — in the "before" script, you've got href={linkHref}, but in the deprecated property of the "after" script, the save output did not have that href. (see this diff)

    So make sure the attributes and save output match the ones in the old/"before" script, and the following is how your code would look like, but note that I only included the main parts that need to be fixed:

    // Define the attributes and use it with the root "attributes" property and
    // the one in the "deprecated" property.
    const blockAttributes = {
      mediaID: {
        type: 'number'
      },
      mediaURL: {
        type: 'string'
      },
      boxTitle: {
        type: 'string',
        default: ''
      },
      // ... the rest of the attributes here.
    };
    
    registerBlockType('hswp/test-box', {
      title: __('Test Box', 'modula'),
      // ... your code.
      attributes: blockAttributes,
      // ... your code.
      deprecated: [
        {
          attributes: blockAttributes,
          save: (props) => {
            // ... your code.
    
            return (
              <div className={`cta-block-box ${className}`}>
                <a
                  className="cta-box-link"
                  href={linkHref}
                  style={{ backgroundImage: "url(" + mediaURL + ")" }}
                  rel="noopener noreferrer"
                >
                  ... your code.
                </a>
              </div>
            );
          },
        }
      ],
    });
    

    Additionally, note that the PlainText component doesn't (as of writing) have a property named tagName.