One of the most common issues with updating a theme or plugin with Gutenberg blocks is that making changes to the block code will break all existing posts using that block. Luckily WordPress offers a solution; a way to deprecate blocks. In this post we’ll look at how to do this.

If you’ve worked with blocks development before you’re probably familiar with this block error when you’ve added a block and then later changed the save function.

This happens because WordPress compares the saved block in the database with the current code in the save function in your block, and they don’t match. WordPress is not able to patch up the difference. In most cases you can click the three dots on the block and choose “Attempt Block Recovery”. If the changes made to the save function were small (e.g. a class change), WordPress is able to restore the block. Worst-case scenario you’d need to click “Convert to HTML” and you’ll lose your block’s edit functionality. Obviously we can’t expect the users of our block code to manually find all posts using this block and perform these steps for each one.

So before we make updates to the save function, we’ll add some code to tell WordPress how to handle old content that have been saved with the old save function.

Let’s get into the code!

It’s actually pretty simple. In short what we need to do is; add a deprecated property to the registerBlockType() function call. This property expects an array. That means you can deprecate a block multiple times, by providing multiple entries in the array. Each depreciation is defined as an object holding the complete attributes property and the (old) save function.

In other words, you define a deprecated property as an array and then you copy your block’s attributes and save function into it. You will need to include attributes even though you’re not changing anything in them in the update. You do not need to include the edit function in depreciation.

deprecated: [
	{
		attributes: { ... },
		save: ( props ) => { ... }
	}
]

Let’s go about this in a more practical example.

Assume our block code looks something like this. The edit function is excluded as we don’t need to deal with it in depreciation.

const { __ } = wp.i18n;
const { registerBlockType } = wp.blocks;
const { RichText } = wp.blockEditor;

import edit from './edit';

registerBlockType( 'awp/deprecated-block-example', {
	title: __( 'Example of deprecating a block' ),
	icon: 'format-aside',
	category: 'widgets',
	attributes: {
		alignment: {
			type: 'string',
			default: 'center'
		},
		exampleString: {
			type: 'string'
		},
	},
	edit,
	save: ( props ) => { 
		const { exampleString } = props;
		return(
			<div className="deprecated-block-example">
				<RichText.Content value={ exampleString } />
			</div>
		);
	}
});

Then let’s assume that we want to make changes to both attributes and save and avoid breaking existing blocks. We add the deprecated property, and copy the whole attributes and save as an array element into it. Then we are free to make any changes to attributes or/and save function.

const { __ } = wp.i18n;
const { registerBlockType } = wp.blocks;
const { RichText } = wp.blockEditor;

import edit from './edit';

registerBlockType( 'awp/deprecated-block-example', {
	title: __( 'Example of deprecating a block' ),
	icon: 'format-aside',
	category: 'widgets',
	attributes: {
		alignment: {
			type: 'string',
			default: 'center'
		},
		exampleString: {
			type: 'string'
		},
		newThing: {
			type: 'string'
		},
	},
	edit,
	save: ( props ) => { 
		const { exampleString, newThing } = props;
		return(
			<div className="deprecated-block-example">
				<RichText.Content value={ exampleString } />
				<div className="new-content">
					<RichText.Content value={ newThing } />
				</div>
			</div>
		);
	},
	deprecated: [
		{
			attributes: {
				alignment: {
					type: 'string',
					default: 'center'
				},
				exampleString: {
					type: 'string'
				},
			},
			save: ( props ) => { 
				const { exampleString } = props;
				return(
					<div className="deprecated-block-example">
						<RichText.Content value={ exampleString } />
					</div>
				);
			},
		}
	]
});

With this code compiled, you can go find an existing post using the old block code, and you should get no broken code!

WordPress will figure out that the block is using our deprecated code, and loads the content using the deprecated save code. Once you make changes in the block and updates the post, the block will be saved using the new save function.

More advanced depreciation and further reading

The above code example is the most basic form for depreciation. WordPress does support more functionality, such as including migrate, supports and even assigning constants (think version numbers) to your deprecated code. Take a look at WordPress’ documentation about block depreciation.