Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Propose block APIs for backwards compatibility #413

Closed
wants to merge 2 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions blocks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ Registers a new block provided a unique slug and an object defining its behavior
- `icon: string | WPElement | Function` - Slug of the [Dashicon](https://developer.wordpress.org/resource/dashicons/#awards) to be shown in the control's button, or an element (or function returning an element) if you choose to render your own SVG.
- `attributes: Object | Function` - An object of [matchers](http://github.com/aduth/hpq) or a function which, when passed the raw content of the block, returns block attributes as an object. When defined as an object of matchers, the attributes object is generated with values corresponding to the shape of the matcher object keys.
- `category: string` - Slug of the block's category. The category is used to organize the blocks in the block inserter.
- `compatibility: Object[]` - An array of compatibility initializers. See ["Backwards Compatibility" section](#backwards-compatibility) for more information.
- `edit( { attributes: Object, setAttributes: Function } ): WPElement` - Returns an element describing the markup of a block to be shown in the editor. A block can update its own state in response to events using the `setAttributes` function, passing an object of properties to be applied as a partial update.
- `save( { attributes: Object } ): WPElement | String` - Returns an element describing the markup of a block to be saved in the published content. This function is called before save and when switching to an editor's HTML view.
- `controls: string[]` - Slugs for controls to be made available to block. See also: [`wp.blocks.registerControl`](#wpblocksregistercontrol-slug-string-settings-object-)
Expand All @@ -154,6 +155,44 @@ Returns settings associated with a registered block.

Returns settings associated with a registered control.

## Backwards Compatibility

When defining a block, you can choose to associate its compatibility with content shapes that had existed prior to the introduction of blocks. A block's `compatibility` property can include one or more objects which describe how the block can be initialized in cases where the editor cannot find another applicable handler.

For example, consider a paragraph of text. A post's content may contain paragraphs, either explicitly with a paragraph `<p>` tag or inferred by newlines courtesy of the default [`wpautop` behavior](https://developer.wordpress.org/reference/functions/wpautop/). Prior to block parsing, content is normalized to apply `wpautop`, so thankfully we need only deal with the paragraph elements.

We want to define a text block to enable controls specific to text (alignment, etc.), but we also want to apply this treatment to paragraph tags which were not saved with block demarcations.

To do so, we'll declare compatibility with the paragraph tag when registering the block:

```js
registerBlock( 'core/text', {
attributes: {
content: html( 'p' )
},

compatibility: [
{
tagName: 'p'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if the html contains a p but its content can not fit inside the text block. (For example if the p has a style attribute, or if the p contains complex HTML, shortcodes etc...). I think these compatibility matchers should be stricter.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we care what comes inside of the p tag as long as the text editing tool (tiny) can handle the markup?

Copy link
Member

@nylen nylen Apr 12, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, I think that not only should the compatibility matchers be as strict as possible, but also the parsing itself. This should be the default option; we may also need a more flexible option like the initialize function proposed here, but I think we need to provide a standard way to handle the cases we expect to occur commonly.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it that text compatibility is a poor example here, and instead unparseable text should simply fall back to the freeform block type? In which case, we should clarify the role of the freeform block vs. the text block.

Later in the documentation is consideration for when a block compatibility initializer needs to bail on an unsupportable type.

I agree it's less clear on how to handle compatibility matched elements which contain descendant matchable blocks. Might tie into discussion of support for nested blocks?

}
]
} );
```

For each compatibility object, we have a few ways to identify content:

- `tagName`: Identify elements of a particular tag
- `shortcode`: Identify shortcodes of a particular shortcode name
- `blockType`: Enable conversion of an instance of another block type to this type

Not shown in this example, but you can also define an `initialize` function which accepts the parsed content as an argument and is expected to return attributes of a block instance corresponding with the matched content. If omitted as is the case here, the block's default `attributes` property takes effect (in this case matching the HTML of the paragraph tag).

```
initialize( node: HTMLElement|WPShortcode|WPBlockNode ): ?Object
```

If the `initialize` function returns `null` or `undefined`, it's assumed that the block does not support the content. This is especially useful in cases where your block may be compatible with elements of a particular tag name, but only when specific conditions apply.

## Components

Because many blocks share the same complex behaviors, the following components are made available to simplify implementations of your block's `edit` function.
Expand Down