Solvedgutenberg Dynamic reusable blocks: technical details
✔️Accepted Answer
I might be missing a piece of this puzzle so apologies for wading into this late! The above REST spec and some associated features seem to make the assumption that the registered blocks are available server-side, but as I understand it, it's recommend to write / register custom blocks in JavaScript: https://wordpress.org/gutenberg/handbook/blocks/writing-your-first-block-type/
This is a "limitation" that struck me when reading the handbook - by having all block registration done client side, it becomes impossible to provide server-side functionality and abstractions, such as a /block-types
REST API endpoint. Having them available server side allows us to do some more security wise validation, which would presumably be more important when blocks can be used outside of the post_content (which is safe, as already has all the reliability of existing sanitization).
It would also open up the possibility of other block interfaces backed by a REST API, such as mobile apps. Again, if this has been discussed elsewhere, a link would be great. By having block registration as part of the Gutenberg app client side, the blocks and general Gutenberg concept will never be able to escape the confines of the WP Admin. While I don't think it will be possible to make blocks totally portable (UI / front end logic is always going to be more powerful expressed as JavaScript components), having registration happen at the server level (and only the server level) will ensure they are more portable.
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:
block
post type.block
post would store in itspost_content
one 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_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
./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/text
type./gutenberg/v1/blocks/358b59ee-bab3-4d6f-8445-e8c6971a5601
- Single core/text block.block
resource would look like:core/block
block 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/block
block initializes, it looks up the from the REST API via the UUID supplied in theref
attribute, and then it creates a block component for thetype
returned for thatblock
resource.core/block
's attributes get written not into the containing post's content, but rather get written intoedits
for that externalblock
resource.post
resource, but also any edits to theblock
resources that were modified.core/block
block would be registered in PHP, and itsrender_callback
would look up theblock
post by its UUIDref
, and embed the content from thatblock
post.transformation
that would result in a new REST APIblock
resource 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 soleref
attribute.Thoughts?