I'm splitting this out from #1516 (Turning a static block into a dynamic reusable block) since that issue is long and primarily focused on the UI aspects. Here's what I've been thinking of in terms of how such reusable blocks would work at a technical level:
- There would be a new
block post type.
- The
block post would store in its post_content one serialized block. Potentially we could store the block's attributes individually in postmeta instead, and just the contents of the block in post_content. That would improve the ability to do queries on the blocks. If a block type is registered with PHP, it could have serialize/deserialize logic that would dictate whether the attributes get stored in postmeta instead of in content.
- A block would be identified by a UUID which would get saved in
post_name. Using a UUID instead of auto-incremented post ID would eliminate the requirement that a block post be created up-front to reserve its ID. The auto-incremented post ID would be for internal use only and not exposed in the API.
- A
block_type taxonomy would exist and each block would be associated with one and only one term that would store the block type as the term's slug. The sanitization logic for such terms could be overridden to allow slashes in the slug, e.g. core/text.
- The block post type would be exposed in the REST API with endpoints such as:
/gutenberg/v1/block-types - Collection of registered block types.
/gutenberg/v1/blocks - Collection of all blocks.
/gutenberg/v1/blocks?type=text/core - Collection of blocks of the core/text type.
/gutenberg/v1/blocks/358b59ee-bab3-4d6f-8445-e8c6971a5601 - Single core/text block.
- A
block resource would look like:
{
"id": "358b59ee-bab3-4d6f-8445-e8c6971a5601",
"type": "core/text",
"attributes": {
"dropCap": true,
"align": "center"
},
"content": "<p style=\"text-align:center\" class=\"has-drop-cap\">Hello World!</p>"
}
- External blocks would be embedded in a post via a
core/block block type which has a single attribute that contains the UUID (REST API resource id) for the external block, for example: <!-- wp:core/block { "ref": "358b59ee-bab3-4d6f-8445-e8c6971a5601" } /-->
- When a
core/block block initializes, it looks up the from the REST API via the UUID supplied in the ref attribute, and then it creates a block component for the type returned for that block resource.
- Modifications to such an external
core/block's attributes get written not into the containing post's content, but rather get written into edits for that external block resource.
- Saving the editor updates not only the main
post resource, but also any edits to the block resources that were modified.
- The
core/block block would be registered in PHP, and its render_callback would look up the block post by its UUID ref, and embed the content from that block post.
- When a non-reusable block (attached block) is converted into a reusable (detached) block it would go through a
transformation that would result in a new REST API block resource being drafted among the edits, including a newly-generated UUID and all of the attributes from the block would be moved into this detached block resource, with the transformed block in content then getting the generated UUID as its sole ref attribute.
- Likewise, a reusable/detached could be re-attached to the content by reversing the transformation in the previous step.
Thoughts?
I'm splitting this out from #1516 (Turning a static block into a dynamic reusable block) since that issue is long and primarily focused on the UI aspects. Here's what I've been thinking of in terms of how such reusable blocks would work at a technical level:
blockpost type.blockpost would store in itspost_contentone serialized block. Potentially we could store the block's attributes individually in postmeta instead, and just the contents of the block inpost_content. That would improve the ability to do queries on the blocks. If a block type is registered with PHP, it could have serialize/deserialize logic that would dictate whether the attributes get stored in postmeta instead of in content.post_name. Using a UUID instead of auto-incremented post ID would eliminate the requirement that a block post be created up-front to reserve its ID. The auto-incremented post ID would be for internal use only and not exposed in the API.block_typetaxonomy would exist and each block would be associated with one and only one term that would store the block type as the term's slug. The sanitization logic for such terms could be overridden to allow slashes in the slug, e.g.core/text./gutenberg/v1/block-types- Collection of registered block types./gutenberg/v1/blocks- Collection of all blocks./gutenberg/v1/blocks?type=text/core- Collection of blocks of thecore/texttype./gutenberg/v1/blocks/358b59ee-bab3-4d6f-8445-e8c6971a5601- Single core/text block.blockresource would look like:{ "id": "358b59ee-bab3-4d6f-8445-e8c6971a5601", "type": "core/text", "attributes": { "dropCap": true, "align": "center" }, "content": "<p style=\"text-align:center\" class=\"has-drop-cap\">Hello World!</p>" }core/blockblock type which has a single attribute that contains the UUID (REST API resourceid) for the external block, for example:<!-- wp:core/block { "ref": "358b59ee-bab3-4d6f-8445-e8c6971a5601" } /-->core/blockblock initializes, it looks up the from the REST API via the UUID supplied in therefattribute, and then it creates a block component for thetypereturned for thatblockresource.core/block's attributes get written not into the containing post's content, but rather get written intoeditsfor that externalblockresource.postresource, but also any edits to theblockresources that were modified.core/blockblock would be registered in PHP, and itsrender_callbackwould look up theblockpost by its UUIDref, and embed the content from thatblockpost.transformationthat would result in a new REST APIblockresource being drafted among theedits, including a newly-generated UUID and all of the attributes from the block would be moved into this detached block resource, with the transformed block in content then getting the generated UUID as its solerefattribute.Thoughts?