Skip to content

Instantly share code, notes, and snippets.

@0verscore
Last active May 27, 2023 15:40
Show Gist options
  • Save 0verscore/393982c179eeb061f5945bc95cc6d9a0 to your computer and use it in GitHub Desktop.
Save 0verscore/393982c179eeb061f5945bc95cc6d9a0 to your computer and use it in GitHub Desktop.
WP / Gutenberg - Change Block Attributes before they got saved in serialized html comments

Description

I am currently working on a 3rd party style system, that basically works on the new gutenberg style engine.

A cornerstone of this system is that I need to filter the block attributes for the HTML comment attribute rendering process. I have searched in the /packages/blocks/src/api/serializer.js for an applyFilters hook that I can use, but to no avail.

The basis for my style management is a datastore called "my/store". It provides additional operations for handling style attributes and a backup system, which you will read about below. Its stored objects are clientId-based, so don't wonder why there are clientIds in the store method.

Solution

I first filter the save block process as usually.

addFilter( 'blocks.registerBlockType', 'my/blockSave', block => {
	return {
		...block,

		save( props ) {
			return (
				<>
					<BlockSave block={ block } props={ props } />
				</>
			);
		}
	}
});

Inside the BlockSave component, I need the clientId to address the block attributes backup and the newly generated attributes in "my/store". To ensure that this temporary clientId is not stored in the BlockSave, I delete the property before we return the BlockSave result.

At that moment I found out that I can manipulate the attribute state of the block directly via the block save method, which even affects the display of the HTML comments. However, I don't want the saved attributes to apply to the currently open editor, because after saving, the attributes that applied before saving should still apply.

const BlockSave = ({ block, props }) => {
	const clientId = props.attributes.tempId;

	dispatch( 'my/store' ).backupBlock( clientId, props.attributes );
	dispatch( 'my/store' ).saveBlock( clientId );

	const attributes = select( 'my/store' ).getBlockAttributes( clientId );

	props.attributes = attributes;
	delete props.attributes.tempId;

	return (
		<>
			{ block.save( props ) }
		</>
	);
}

So afterwards I needed a process that restores the previously valid attributes. Therefore I developed a subscriber that is only executed when we have backups stored, i.e. 1x after execution of the BlockSaves.

const RestoreListener = subscribe( () => {
	const backups = select( 'my/store' ).getBackups();

	if ( ! Object.keys( backups ).length ) {
		return;
	}

	dispatch( 'my/store' ).resetBackups();
	dispatch( 'core/block-editor' ).updateBlockAttributes( Object.keys( backups ), backups );
});

Environment info

  • WordPress 6.2
  • Gutenberg 15.8.1

Environment Plugins or Themes

There are no other Plugins or Themes active or installed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment