0

I’ve created a custom WordPress block and would like to ensure that every time a block is newly generated or copied, it is assigned a unique ID. I’ve tried many approaches and have finally come up with the following solution:

= attributes.js =

uniqueId: { type: String, default: '', }, 

= Excerpt from edit.js =

const generateUniqueClass = () => { return `custom-${Math.random().toString(36).substr(2, 9)}`; }; useEffect(() => { const { uniqueClass } = attributes; if (!uniqueClass) { const newUniqueClass = generateUniqueClass(); setAttributes({ uniqueClass: newUniqueClass }); } else { const blocks = select('core/block-editor').getBlocks(); const isDuplicate = blocks.some( (block) => block.attributes.uniqueClass === uniqueClass && block.clientId !== clientId, ); if (isDuplicate) { const newUniqueClass = generateUniqueClass(); setAttributes({ uniqueClass: newUniqueClass }); } } }, [attributes.uniqueClass, clientId]); 

Unfortunately, this solution doesn’t reliably work when I copy a block. Sometimes it works, sometimes it doesn’t—it’s currently like playing the lottery.

During my research, I also came across this hook:

// Apply filter addFilter( 'blocks.getSaveContent.extraProps', 'my-plugin/add-custom-class-on-copy', addCustomClassOnCopy ); 

Even here, I can’t get it to work.

Does anyone know of a better solution for my requirements?

In summary: When creating a WordPress block, a unique ID should be assigned and stored in an attribute called uniqueId. This ID should not change anymore. However, if a block is copied (and already has a unique ID), a new unique ID should be generated. Duplicate unique IDs must be avoided.

5
  • this can't be done reliably, but it usually indicates that you're making a major mistake that requires this to be implemented, the mistake is usually that you want your block to be a first class piece of data in the same way that a post or term is so that you can use that ID in other places to reference it, which is not how blocks are meant to work. You wouldn't do this with a paragraph or a shortcode and it's the same with a block. Normally the solution is to make the block refer to an external source of truth such as a custom post type ID etc.
    – Tom J Nowell
    CommentedJan 7 at 13:51
  • Note that all the javascript magic in the world will be undone the moment a post revision is created or the user duplicates the block. Creating a block pattern and inserting it multiple times, as well as dragging and dropping the blocks between tab windows would also bypass this. The block ID is there to let the editor tell the difference between different blocks e.g. 2 paragraph blocks with the same attributes need something more than their order to tell them apart, they aren't unique, they aren't GUIDs or identifiers, and you shouldn't use them as such
    – Tom J Nowell
    CommentedJan 7 at 13:52
  • @TomJNowell I use this method to target the blocks via custom CSS. I would like to have the option to avoid assigning this class manually. I understand that this goes against the logic of the blocks. However, it is important for me to ensure that the string is not regenerated when the page is refreshed. Do you perhaps have a suggestion for a possible solution?CommentedJan 7 at 14:28
  • 1
    that's what the ID is meant to be used for, but the best you can do is in the edit screen scan through every block and check if there's a duplicate, but this won't guarantee uniqueness outside of the block editor context, blocks in other posts and templates that show on the page will never know about them, and as you discovered it has its caveats. This is why I mentioned using an external source of truth.
    – Tom J Nowell
    CommentedJan 7 at 14:39
  • 1
    Maybe this will help: stackoverflow.com/questions/65582451/…
    – admcfajn
    CommentedJan 8 at 4:29

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.