The integral save options for block attributes focus on storing the attribute data in the block save content, which then means it’s saved in post_content. That won’t be suitable if the attribute is data you want to later query in a scaleable way. Now the easiest way and sometimes the most appropriate would be to use post meta storage. This will make your block attribute queryable. However it may not be as scaleable as you’d like, so if your goal is maximum scalability then you may want to use a custom database table.
Having prefaced this with the alternatives, let’s jump into how we handle attribute storage to ta custom database table using PHP and the save_post hook.
An overview of the method:
- Create a save_post hook, it’s recommended to use save_post_[custom_post_type] if this a solution for a custom post type.
- In the save_post hook use the run parse_blocks() on the $post->post_content in order to parse the blocks into an array of blocks.
- Loop over the blocks and try to match the “blockName” of the block where you want to take the attribute from. Use multiple matches for different blocks if you need attribute data from different block types.
- After the loop is complete and you’ve gathered all the attribute data, save this to your custom database table using whatever your normal process is. This might be handled (as it is in Saber Commerce) using a data model class with a save() method provided.
One issue to raise and consider here is that if the user has removed the block you expecting, then you won’t find the block or the attribute. So expect that to be possible, if you’re not using template locking to prevent a given block type from being removed. For use cases where the goal is to provide blocks that collect important data, you’ll often be locking the template that was setup when you registered the custom post type. Meaning in other words, you’re ensuring that the block does exist, although potentially the data attribute will still be empty.
A perhaps more perplexing variable would be to find multiple instances of the block you’re collecting attribute data from. This might be by design, or again in an unlocked template it may be that the user has chosen to insert multiple blocks of this type. Again template locking can be used to avoid this is having exactly 1 instance of the given block type is important to enable you to store data. This is the case in Saber Commerce where it wouldn’t be good for the user to insert multiple SKU blocks, as the SKU block is used to collect (in an InspectorControl text field) the Product SKU.
If locking down the Gutenberg template is not possible, and you want exactly 1 instance of your data collecting block then you can solve part of the problem by turning off the “multiple” flag under the block definition. When set to false, the editor can only hold a maximum of 1 of the block type. The user could still remove the 1 instance of the block you provide however, unless you scripted a solution that prevents this (which is possible).