Description
Previously: #2529, #104
Related: #886
Related Slack conversation: https://wordpress.slack.com/archives/C5UNMSU4R/p1505677036000104 (cc @jasonbahl)
When initially developing the API for implementing a block (#104), there were some competing objectives:
- The editor representation of a block must occur in the client to preserve an ideal user experience
- A block should ideally be easy to implement for quick prototyping (Simple API for defining a block #27, e.g. defining block in a browser console)
- General information about a block should be context unaware (title, attributes definition, category, etc need not specifically be defined in a client, server, or an other external static file)
Where we have fallen short is in:
- The third of these objectives; As a need has arisen for server-side attribute validation (Block API: Support and bootstrap server-registered block attribute schemas #2529), we have further fragmented the definition of a block (its attributes may be defined on the server or in the client).
- It is not possible for the server to have reliable awareness of all blocks which would be registered in the editor.
Proposal:
To improve consistency, we should move block attributes (and other general information) to a server block registration. This would likely behave exactly as it does in #2529, including client-side attributes bootstrapping and validation, but would be applied consistently across all blocks. Therefore, every block would have a companion PHP file associated with it, which in addition to current supports defines:
- Title
- Icon
- Category
- Attributes
The trade-off here is that it is not as simple to implement a block in a single location. We could potentially leave client-defined attributes support as-is, but this could also entice developers to avoid the server registration and reintroduce all the inconsistencies/drawbacks therein.
Some previous discussion had considered the idea of a third JSON "manifest" file, similar to a package.json
or composer.json
, describing the static general information about a block. While this would be a simple format for what is essentially overview data, is problematic because (a) it is yet another file that a developer could need to become familiar with, (b) it is difficult to bring into the client without a build step understanding JSON imports, and (c) localization of strings would need to implement some amount of "magic" (hard-coding to properties expected to be localized).
It's worth pointing out that a plugin author already needs some amount of server-specific logic for each of their blocks, specifically that of enqueueing the JavaScript files responsible for registering the blocks in the client. By requiring block registration in the server, there may be some added benefit in handling scripts and styles.
- A block could define its companion scripts and styles as properties of the block type (e.g.
script_handle
,style_handle
). - Or: These files could be "discovered" adjacent the block registering file by naming conventions (e.g. find
style.css
,edit.css
,block.js
adjacentmyblock/index.php
). This could encourage developers to define their blocks in a standalone folder/file structure for easier separation overview.
A remaining challenge in moving all block attributes definitions to the server is support for attribute sources. With advent of additional source types (meta, options), we will likely need to expand this concept to cover more than just DOM-based attribute sourcing. Therefore, I would propose creating an alternative structure for representing what currently exists as the assignment of source functions:
Before:
{
url: {
source: attr( 'img', 'src' )
}
}
After:
[
'url' => [
'source' => [
'type' => 'attribute',
'selector' => 'img',
'name' => 'src',
],
],
]
The intent here is not necessarily that the server would become responsible for parsing attributes from the markup of a block (although there is nothing that precludes it from doing so), but rather to be able to represent the structure in a static format, which could then be bootstrapped into the client to recreate the current behavior.
As an example for how this extends into the concept of additional sources:
'author' => [
'type' => 'string',
'source' => [
'type' => 'meta',
'name' => 'author', // Inferred from attribute name if not specifically defined?
],
],
'siteTitle' => [
'type' => 'string',
'source' => [
'type' => 'option',
'name' => 'name',
],
]
Open questions:
- While there is justification for defining block attributions in the server for the purpose of improving consistency, there is still a lack of general understanding of specific use cases for server-specific awareness of blocks, aside from a "nice to have" reasonings. Lack of these use cases is not intended as an argument for a server definition not to exist, but it would help guide specific implementation decisions.
cc @westonruter