-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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
Try supporting post meta in block attributes #2740
Merged
Merged
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
dce9ac5
First stab at meta support in block attributes
mcsf 20aa841
Let block author specify meta shape (`single` or not)
mcsf 94d94e5
Defining Book as a third-party block
mcsf 30f7dc0
Bail meta support if not enough data
mcsf e0f3a89
Serialization: Ignore meta attributes
mcsf 4b2ac5e
Book block: Don't even render statically
mcsf 8b10a40
Docs: Update & rename Attributes doc
mcsf 37c7292
Remove hypothetical Book block
mcsf 35f5d1c
getBlock, setAttributes: fix & refactor handling of meta
mcsf d7ffb68
Docs: Mention register_meta type default
mcsf 402806b
getBlock: memoize w/ createSelector
mcsf d6f9296
Docs: Meta: Considerations: Type casting
mcsf File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
# Attributes | ||
|
||
## Common Sources | ||
|
||
Attribute sources are used to define the strategy by which block attribute values are extracted from saved post content. They provide a mechanism to map from the saved markup to a JavaScript representation of a block. | ||
|
||
Each source accepts an optional selector as the first argument. If a selector is specified, the source behavior will be run against the corresponding element(s) contained within the block. Otherwise it will be run against the block's root node. | ||
|
||
Under the hood, attribute sources are a superset of functionality provided by [hpq](https://github.com/aduth/hpq), a small library used to parse and query HTML markup into an object shape. In an object of attributes sources, you can name the keys as you see fit. The resulting object will assign as a value to each key the result of its attribute source. | ||
|
||
### `attr` | ||
|
||
Use `attr` to extract the value of an attribute from markup. | ||
|
||
_Example_: Extract the `src` attribute from an image found in the block's markup. | ||
|
||
```js | ||
{ | ||
url: { | ||
source: attr( 'img', 'src' ) | ||
} | ||
} | ||
// { "url": "https://lorempixel.com/1200/800/" } | ||
``` | ||
|
||
### `children` | ||
|
||
Use `children` to extract child nodes of the matched element, returned as an array of virtual elements. This is most commonly used in combination with the `Editable` component. | ||
|
||
_Example_: Extract child nodes from a paragraph of rich text. | ||
|
||
```js | ||
{ | ||
content: { | ||
source: children( 'p' ) | ||
} | ||
} | ||
// { | ||
// "content": [ | ||
// "Vestibulum eu ", | ||
// { "type": "strong", "children": "tortor" }, | ||
// " vel urna." | ||
// ] | ||
// } | ||
``` | ||
|
||
### `query` | ||
|
||
Use `query` to extract an array of values from markup. Entries of the array are determined by the selector argument, where each matched element within the block will have an entry structured corresponding to the second argument, an object of attribute sources. | ||
|
||
_Example_: Extract `src` and `alt` from each image element in the block's markup. | ||
|
||
```js | ||
{ | ||
images: { | ||
source: query( 'img', { | ||
url: attr( 'src' ) | ||
alt: attr( 'alt' ) | ||
} ) | ||
} | ||
} | ||
// { | ||
// "images": [ | ||
// { "url": "https://lorempixel.com/1200/800/", "alt": "large image" }, | ||
// { "url": "https://lorempixel.com/50/50/", "alt": "small image" } | ||
// ] | ||
// } | ||
``` | ||
|
||
## Meta | ||
|
||
Attributes may be obtained from a post's meta rather than from the block's representation in saved post content. For this, an attribute is required to specify its corresponding meta key under the `meta` key: | ||
|
||
```js | ||
attributes: { | ||
author: { | ||
type: 'string', | ||
meta: 'author' | ||
}, | ||
}, | ||
``` | ||
|
||
From here, meta attributes can be read and written by a block using the same interface as any attribute: | ||
|
||
{% codetabs %} | ||
{% ES5 %} | ||
```js | ||
edit: function( props ) { | ||
function onChange( event ) { | ||
props.setAttributes( { author: event.target.value } ); | ||
} | ||
|
||
return el( 'input', { | ||
value: props.attributes.author, | ||
onChange: onChange, | ||
} ); | ||
}, | ||
``` | ||
{% ESNext %} | ||
```js | ||
edit( { attributes, setAttributes } ) { | ||
function onChange( event ) { | ||
setAttributes( { author: event.target.value } ); | ||
} | ||
|
||
return <input value={ attributes.author } onChange={ onChange } />; | ||
}, | ||
``` | ||
{% end %} | ||
|
||
### Considerations | ||
|
||
By default, a meta field will be excluded from a post object's meta. This can be circumvented by explicitly making the field visible: | ||
|
||
```php | ||
function gutenberg_my_block_init() { | ||
register_meta( 'post', 'author', array( | ||
'show_in_rest' => true, | ||
) ); | ||
} | ||
add_action( 'init', 'gutenberg_my_block_init' ); | ||
``` | ||
|
||
Furthermore, be aware that WordPress defaults to: | ||
|
||
- not treating a meta datum as being unique, instead returning an array of values; | ||
- treating that datum as a string. | ||
|
||
If either behavior is not desired, the same `register_meta` call can be complemented with the `single` and/or `type` parameters as follows: | ||
|
||
```php | ||
function gutenberg_my_block_init() { | ||
register_meta( 'post', 'author_count', array( | ||
'show_in_rest' => true, | ||
'single' => true, | ||
'type' => 'integer', | ||
) ); | ||
} | ||
add_action( 'init', 'gutenberg_my_block_init' ); | ||
``` | ||
|
||
Lastly, make sure that you respect the data's type when setting attributes, as the framework does not automatically perform type casting of meta. Incorrect typing in block attributes will result in a post remaining dirty even after saving (_cf._ `isEditedPostDirty`, `hasEditedAttributes`). For instance, if `authorCount` is an integer, remember that event handlers may pass a different kind of data, thus the value should be cast explicitly: | ||
|
||
```js | ||
function onChange( event ) { | ||
props.setAttributes( { authorCount: Number( event.target.value ) } ); | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pento this would be nice to address in general :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, that's annoying.
@rmccue: I don't recall the history for why postmeta is only included in a response when it has the
show_in_rest
flag set. (As opposed to at least returning the visible postmeta when the user is appropriately authenticated.)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Meta fields aren't guaranteed to be "safe" by default. "Safe" is a few things, namely safe for JSON serialisation (which is lossy compared to PHP), and safe for capabilities (not all meta is always available).
The current behaviour exists for those reasons. When we initially didn't require
show_in_rest
, people noted that this would expose hidden fields created by plugin or users (turns out, a bunch of people use the "Custom Fields" metabox for random internal notes). Solving these problems in a consistent and safe way turned out to be essentially impossible.show_in_rest
is an indicator that plugin developers are accepting the limitations of the API for their meta fields.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These hidden fields would be shown if you do
get_post_meta()
calls, no? It feels like the API should adhere to the expectations of doing such authenticated calls.