gutenberg
gutenberg copied to clipboard
Tracking issue: Connecting block attributes and custom fields
Part of:
- https://github.com/WordPress/gutenberg/issues/41236
- https://github.com/WordPress/gutenberg/issues/51373
- https://github.com/WordPress/gutenberg/issues/54536
This issue is meant to discuss how to connect block attributes with custom/meta fields. It includes a list of tasks needed for this, and we will share updates about the progress here.
While working on this implementation, we realized that the internal API we were using could be useful for other projects like Partially Synced patterns. Therefore, we decided to create another issue to keep track of the Block Bindings API, which will be used to connect block attributes and custom fields.
- Block Bindings API: Internal API to connect block attributes and different sources. Not only used for custom fields but for other projects like Partially Synced patterns.
- Custom Fields: Using the Block Bindings API, support for the "meta_fields" source to connect block attributes and custom fields.
The idea is to create a new source for the Block Bindings API that gets the data from meta fields.
This will allow users to show data stored in custom fields in existing blocks like headings or paragraphs.
Progress
This is a list of things to consider/questions related to the Block Bindings API that will be updated as we go along:
WordPress 6.5 planning
A couple of things that are important:
- This project depends on the Block Bindings API: link.
-
We will start supporting just a few core blocks attributes that can be increased in a later phase. We can start with:
- Paragraph content.
- Heading content.
- Image URL.
- Button link and content.
Fixes/updates for Gutenberg 17.6 RC (Tuesday 30th)
- [x] Decide the final name of the public class and methods included in this pull request.
- [x] Migrate all the changes suggested in this wordpress-develop pull request to Gutenberg, including the naming decision. #58383
- [x] Decide the final shape of the bindings object used in the blocks and make the necessary changes: #58337
- [x] Backports to WordPress.
- [x] Add more tests for the bindings, especially in the editor.
- [x] Add validation in the
WP_Block_Bindings_Registry
class like others likeWP_Block_Type_Registry
are doing: link.
Fixes/updates for WordPress 6.5 beta 1 (February 13th)
- [x] Review the accessibility of the editor with the accessibility team, including the suggestions made: link.
- https://github.com/WordPress/gutenberg/pull/58687#pullrequestreview-1867359839
- [x] Migrate to Gutenberg the changes made in this core pull request: link. PR: #58683
- [x] Fix a bug with
strcasecmp
reported here. - [x] Decide if we should add a
WP_Block_Binding_Source
class and handle validation there: link. PR: #6042 / Core changeset: 57562 - [x] Refactoring the processing of block bindings into two steps: link. This would solve this issue with the empty images in pattern overrides. PR: #6059
- [x] Add initial documentation. Core changeset: 57560
- [x] Remove unused
setAttributes
. PR: #58806 - [x] Lock editing by default when the source used in the bindings is not registered in the client and adapt pattern overrides. PR: #58787
Fixes/updates during beta phase
- [x] Fix the way context is added as discussed here. Core / Gutenberg PR
- [x] Remove unnecessary
queryId
in context: link. Solved as part of Core / Gutenberg PR - [x] Create a guide about using block bindings. Discussion: 219. Guide part 1.
- [x] Fix metadata attribute not being preserved after block transforms: link. PR: #59179
- [x] Fix query loop not working as expected in the editor when blocks are bound. PR #59283
- [ ] Dev note covering how extenders can use the block bindings.
- [ ] Don't show protected meta fields. PR #59326
- [ ] Review the
use-bindings-attributes
hook and improve its implementation. As part of that, we should address link. PR with the refactoring: #58895 - [ ] Improve the accessibility of the block bindings:
- https://github.com/WordPress/gutenberg/issues/58674
- https://github.com/WordPress/gutenberg/issues/58673
- [ ] Review the current UX and make further improvements: link.
- https://github.com/WordPress/gutenberg/pull/59185
- [ ] Add hook to check when we should lock controls when bindings exist: link.
- [ ] Use
RichText
identifier to check if we should make it non-editable: link. - [ ] Should we have metaValue and setMetaValue instead of useSource: [ metaValue, setMetaValue ]: link?
- [ ] Remove the filter when a source is unregistered as discussed here.
Out of the scope for 6.5
I'd like to include as many things as possible in 6.5, but trying to be realistic, I believe this list will probably not make it:
- [ ] Create new sources: Site data, post data, taxonomy data.
- [ ] Add the possibility of editing the value of the meta fields directly from the UI.
- [ ] Add a UI to allow users to add bindings through the Editor.
- [ ] Explore how to abstract the locking of controls: link.
Other issues to keep in mind:
- [ ] Add support for more core blocks we consider important.
- [ ] Explore the possibility of creating a filter to modify the value of the meta field returned. Ex: Change the date format with PHP.
- [ ] Explore the possibility of concatenating custom fields somehow. Ex:
site_url
+field_id
. - [ ] Explore the possibility of creating "before/after" setting until an Inline Binding functionality is implemented.
- [ ] Design the UI/UX to connect block attributes and custom fields: link.
- [ ] Change the UI to use the upcoming DataViews: link.
- [ ] Probably using DataViews, add the possibility of creating new custom fields.
- [ ] Replace core blocks like Post Author to use variations using these bindings.
Initial experimental MVP
We can start with a simple experimental version, that can be activated through Gutenberg → Experiments, to kick off the project. We can aim to just:
- Connect the paragraph content and the image URL through an object in the block attributes. Just by having the following block attribute, it should display the value of the custom field in the frontend:
<!-- wp:paragraph
{
"connections": {
"attributes": {
"content": {
"source": "meta_fields",
"value": "my_custom_field"
}
}
}
}
-->
Keep in mind that this is just an example, and we have to discuss how the API should look. Additionally, it might require adding support for these connections in the block itself.
- Have a really basic UI to add those connections and select the custom field we want to connect.
For this first experimental MVP, I would leave out of the scope:
-
Don’t support reading/writing of the custom field values from the editor: We wouldn’t be able to read the value of the custom field or update its value from the editor. We could use a placeholder in the editor (in the frontend it should show properly). Making it work in the editor is trickier, and we might hit some blockers that can be solved in next iterations.
-
Don’t show a list of available custom fields: For the same reason, I propose using a text input and keeping the user responsible that it matches an existing custom field in this initial phase.
By the way, the meta
attributes source was only deprecated in WP 5.4, and core still maintains backward compatibility.
I wasn't actively involved in the project then, so I don't remember the reason for the deprecation. We should probably dig up old PRs and check.
I wasn't actively involved in the project then, so I don't remember the reason for the deprecation. We should probably dig up old PRs and check.
Thanks a lot for sharing! 🙂 I've been taking a look at the old PRs and it seems the deprecation was added in this pull request: link. I've been reading the different conversations and, as stated in the Dev Notes, it seems it was deprecated in favor of the EntityProvider
. Which is supposed to "provide a more flexible and powerful way for building blocks that source data from different properties of WordPress entities and data." But I wasn't involved in the project either, and I couldn't find too much information, so I might be missing something.
Anyways, I believe the case here is slightly different than the meta
attributes source. In this case, we want that block attributes that are not usually connected to meta fields, can do it if the user wants. If we take the paragraph content as an example, it uses source: html
. In most cases, users will want to use the paragraph block as it is used right now but, if wanted, this would offer the possibility to connect it to a meta field (Post Excerpt for example) through a UI in the editor.
Apart from that, blocks using the old meta
source would keep working as well. It's just that those attributes wouldn't have the UI to connect to a different meta field. If we consider this a need, we could explore how to support that too in the future.
I've opened the PR to allow connecting the url
attribute of the Image block to Custom Fields:
- https://github.com/WordPress/gutenberg/pull/53488
By the way, the meta attributes source was only deprecated in WP 5.4, and core still maintains backward compatibility.
@mcsf should be the best person to contact, in case you need to know the details. Here is the initial implementation https://github.com/WordPress/gutenberg/pull/2740.
It's been a long time and my memory is fuzzy, but I believe the original meta source was deprecated due to a combination of:
- Gutenberg betting on and consolidating its data needs around Entities as introduced in 2019
- suboptimal performance and/or ergonomics of the meta source compared to normal attributes
- general lack of interest for post meta as an attribute source (newcomers were likely to not use them, whereas heavy users of meta were likely to not use the block editor) weighed against the cost of maintaining that specific source, which IIRC was a bit shoehorned into parts of the block API
I think the main problem of the meta source compared to this new proposal is that it requires folks to actually write a new block by explicitly marking a given attribute as a "meta" attribute. While this new proposal allows setting the source as an attribute of existing blocks (no need to write new blocks).
@SantosGuillamot, @Poliuk I have added a tracking issue for partial syncing, which is going to have some overlap with this work.
I wanted to share an update on the work done till now:
Done
The first implementation to connect the paragraph content with custom fields has been merged. It is a really basic MVP that will let us build the rest on top of it. Bear in mind that it's just an MVP to test the technical part, it will change, especially the Editor UX. This is a quick demo of how this initial version works:
I created a custom field "custom_text" with a value "Custom Text Value"
https://github.com/WordPress/gutenberg/assets/34552881/81d7c542-4dc4-4ae4-92cd-418428ddb276
Apart from that, there is an ongoing PR to be able to connect the Image block URL as well: link.
Additionally, @glendaviesnz has started experimenting with the possibility of using this mechanism for the Partially synced patterns, and he created a tracking issue for that work: link. According to the first impressions, it seems it could work.
Next steps
The potential immediate next steps could be:
- Finish the work to add support for the Image URL attribute.
-
Add support for the Image title attribute. I believe this one could be special because the title is usually stored in a meta field that is an object. Adding a new image usually creates two meta fields:
_wp_attached_file
and_wp_attachment_metadata
. The first one contains the image url, but the second one is an object that contains some attributes like the title. For this reason, I believe we can use it to explore how to retrieve/modify the data from a meta field that is an object. -
Investigate how to read/write the custom fields in the editor. Even if we don’t have a proper UX for it yet, there is a technical challenge to research/decide what to do with the
show_in_rest
limitation. We need to explore different ways of overcoming this limitation. Maybe we can change the API so, if you are an editor, it shows you all the fields. Or not retrieving that data from the REST API and doing it in PHP somehow. I didn’t think too much about it, that's what the research would be about. - We could work on a fallback mechanism in case that value doesn’t exist. This could be especially interesting for templates and patterns.
- Keep investigating how this mechanism could be used for WP Pattern.
To reflect the general nature of the feature that goes beyond just custom fields, @SantosGuillamot and I propose to call it "Block Bindings".
- Calling the project "Custom Fields" when the custom fields are only one of the use cases does not make much sense.
- There is prior art for the term
binding
used in a similar technical sense (e.g. data binding in frontend UI frameworks) - It rolls off the tongue nicely 😄
The name should not be taken as final, but more as a codename that gives us a way to refer to the combined effort in a consistent way.
Majorly agree with thinking beyond custom fields here, binding could be useful for other use cases too
After thinking about it and working on the first implementation of custom fields, I believe we can differentiate between Block Bindings API and Custom Fields:
- Block Bindings API: Internal API to connect block attributes and different sources. Not only used for custom fields but for other projects like Partially Synced patterns.
- Custom Fields: Using the Block Bindings API, support for the "meta_fields" source to connect block attributes and custom fields.
Having this distinction should help clarify each project's scope and how they are related. Let us know if it is clear enough.
I've updated the opening comment to reflect that and moved part of the discussion to the Block Bindings API issue.
Initial version for WordPress 6.5
We want to include an initial version of the binding between Custom fields and Blocks in WordPress 6.5. We have already experimented with the implementation as explained before, and we feel confident enough to start working on a version meant to be included in WordPress 6.5.
Goal
As a reminder, this feature aims to create a simple way of connecting block attributes and Custom fields/metadata. Imagine something like this:
Bear in mind that the UI still needs to be discussed, this is just for explanation purposes
https://github.com/WordPress/gutenberg/assets/34552881/9cb4808c-4928-40b8-a7cd-db75fd0f04db
These bindings are especially helpful when the value of the metadata changes depending on the context. For example, in a Query Loop or inside a template. Imagine a user wants to create a Query Loop of movies like this one:
Right now, they would need to create custom blocks for the release date, the runtime, the trailer button, or any other info related to the movie.
With this initial version, users could bind blocks with custom fields, whose values can easily be changed for each movie, simplifying the process a lot. They would just use a Query Loop with core blocks connected to custom fields:
Proposal for 6.5 release
The whole Custom Fields & Blocks project could be pretty big as it covers many things. I believe we can start small and implement new functionalities progressively. This way, we add value to the users and receive feedback as soon as possible.
I'm sharing the phases that I consider realistic for 6.5. But as I mentioned, we can approach them one by one and get as far as possible. If we only reach phase 2, that would already be much better than what we have now and can be improved in later releases.
I'm including some orientative things/questions that we should consider for each phase, although we will edit this issue once we progress and discover what other things we need to do, and some might be postponed to later phases.
Progress and updates relative to these tasks will be shared in the opening post.
1. Be able to connect block attributes and custom fields without a UI
The idea is that users can add the binding through a new "bindings" block attribute. A couple of things that are important at this point:
- This project depends on the Block Bindings API: link.
-
We will start supporting just a few core blocks attributes that can be increased in a later phase. We can start with:
- Paragraph content.
- Heading content.
- Image URL.
- Button link and content.
With that in mind, this is the list of things to consider:
- [ ] Implement the
metadata
source used by the Block Bindings API.- Which metadata should it cover? Site data, post data, taxonomy data, custom fields, user data...
- [ ] Mechanism for block attributes to opt-in for these bindings.
- [ ] Add tests.
2. Include a basic UI to create these bindings where we can read the metadata value
We can start with a basic dropdown as the one shown in the video without the possibility of editing its value.
- [ ] Mechanism to get the available metadata fields in the Editor.
- Should we use the REST API? Any other methods we should consider?
- If we use the REST API, should we reconsider changing the default value of
show_in_rest
for new fields?
- [ ] Implement basic UI to select the existing metadata.
- Should we use the same UI for all block attributes or each one should have a different one.
- [ ] Add tests.
3. Add the possibility to edit the value of the meta field directly through the Editor
- [ ] Explore how to handle user permissions. A user might be able to read the meta value but not write it, for example.
- [ ] Implement UX to let users know they are editing a meta field instead of the block's content.
- [ ] Add tests.
4. Add support for more core blocks we consider important
Once we feel confident enough about the solution, we can focus on adding support to more core blocks.
With these phases, there is already a lot of work for 6.5. For the next releases, we can keep working on this, work on the remaining tasks, and explore the possibility of addressing new ones like:
- Explore the possibility of adding new functionalities:
- Concatenate custom fields somehow. Ex:
site_url
+field_id
. - Create "before/after" setting until an Inline Binding functionality is implemented.
- Create a filter to modify the value of the meta field returned. Ex: Change the date format with PHP.
- Concatenate custom fields somehow. Ex:
- Change the UI to use the upcoming DataViews: link.
- Probably using DataViews, add the possibility of creating new custom fields.
- Replace core blocks like Post Author to use variations using these bindings.
Anyway, we can analyze this deeply once 6.5 is out, and we have a better picture. Or even reconsider including some of them in 6.5 if we feel they are important enough.
I've updated the opening post to reflect this
@SantosGuillamot This looks good! How do you think existing meta will work with this? Will there be some way to mark a meta field as one which should be shown in the list of bindable fields?
ACF currently uses the legacy metabox support for page-wide meta, but if we can add a "progressive enhancement" way for meta to be updated live as users change fields, we could do that so their changes from ACF are visible on bound attributes immediately - this would require a JS api for trigging meta value update events which is subscribed to by each block which uses one.
1. Be able to connect block attributes and custom fields without a UI
Mechanism for block attributes to opt-in for these bindings.
Assuming this will be a way for other blocks and third party blocks to allow an attribute of theirs to be selected from the "link" button from a meta field?
2. Include a basic UI to create these bindings where we can read the metadata value
Mechanism to get the available metadata fields in the Editor.
The REST makes sense here I think, but there should be a way for third party plugins (like ACF) to add fields to it. For legacy data and field location reasons, ACF doesn't use register_field
- so we'd have to add support for this by hooking in our fields as available here.
Should there be a way to specify which fields are available to which blocks? For example you'd only want compatible image fields to be possible to set as the source of an image.
Sorry for the half-spam here. This same ability is provided by Toolset over its Dynamic Sources.
I was the team leader for Toolset when this was developed back in 2020-2021, if anyone here is interested I could name a couple of devs who could provide precious feedback on implementation ideas and edges found during that phase.
@lgladdy Thanks a lot for those questions! I'll try to address them one by one but I wanted to note first that we still have to discuss and decide most of the things 🙂
How do you think existing meta will work with this? Will there be some way to mark a meta field as one which should be shown in the list of bindable fields?
On the PHP side, we considered accessing the value of the meta fields using the get_metadata function or get_post_meta. Are ACF accessible through that function?
On the editor side, one idea was to use the REST API to get the list of available fields for a given context. I assume that any field exposed there should be available in the list of bindable fields.
Apart from that, if plugins need something more custom, we were thinking of creating a mechanism to add different sources in the Block Bindings API. For example, we could explore the possibility of having an "ACF" source if we feel that a better approach.
Anyways, it's something we have to explore deeper, and we have to understand better how plugins like ACF work.
this would require a JS api for trigging meta value update events which is subscribed to by each block which uses one.
This could make sense 🙂 Adding it to the list of things to consider.
Mechanism for block attributes to opt-in for these bindings.
Assuming this will be a way for other blocks and third party blocks to allow an attribute of theirs to be selected from the "link" button from a meta field?
The end goal is that any block can decide which attributes can be connected. But for this first version, we will limit it to just a few core blocks where everything is under control. Making the bindings work in any block is a bit trickier and should be done cautiously. There is more info about this in the block bindings API issue.
but there should be a way for third party plugins (like ACF) to add fields to it. For legacy data and field location reasons, ACF doesn't use register_field - so we'd have to add support for this by hooking in our fields as available here.
Totally agree here. We have to ensure that whatever we provide works as smooth as possible with plugins like ACF.
Should there be a way to specify which fields are available to which blocks? For example you'd only want compatible image fields to be possible to set as the source of an image.
We should definitely explore that possibility and analyze how to handle types and that validation. In my opinion, that could be done in a later phase. In the meantime, we can use the own block as the "validator". For example, if I connect an image to a field that is not a URL, the block will fail and return an error. I created a quick video to show what I mean:
https://github.com/WordPress/gutenberg/assets/34552881/6b4ef9c7-46ee-4438-b5a2-ed33dca7927f
Sorry for the half-spam here. This same ability is provided by Toolset over its Dynamic Sources.
I was the team leader for Toolset when this was developed back in 2020-2021, if anyone here is interested I could name a couple of devs who could provide precious feedback on implementation ideas and edges found during that phase.
@decodekult That looks great! All the feedback we receive, regarding the UX, things to consider, or the development, is more than welcome 🙂
Thanks for the reply @SantosGuillamot! This is all logical.
I'm more than happy to help work on the code here too, and will try to make sure ACF is good to go at launch too. I'm passionate about making meta work better in the block editor, so anything I can do to help here I will!
On the PHP side, we considered accessing the value of the meta fields using the get_metadata function or get_post_meta. Are ACF accessible through that function?
On the editor side, one idea was to use the REST API to get the list of available fields for a given context. I assume that any field exposed there should be available in the list of bindable fields.
Specifically with your question on ACF here, yeh - get_post_meta
will give you ACF's raw database value, so we'd want to add a layer on top here (maybe by a final return filter on the PHP side?) to intercept and translate accordingly (that's things like return formats for data/time strings etc)
Apart from that, if plugins need something more custom, we were thinking of creating a mechanism to add different sources in https://github.com/WordPress/gutenberg/issues/54536#:~:text=2.-,Get%20the%20value%20from%20the%20source%20defined%20in%20the%20binding.,-Depending%20on%20the. For example, we could explore the possibility of having an "ACF" source if we feel that a better approach.
This would be cool, not just for ACF but the other meta plugins. If plugins could register themselves as a source for meta, and can handle the meta available to that location somehow.
Glad to hear that and thank you for your feedback!
maybe by a final return filter on the PHP side?
One of the points I mentioned in the opening post was "Explore the possibility of creating a filter to modify the value of the meta field returned.", which I believe is what you mean here. I include it in the "Future releases" section, but if we are in good track and we feel it is important enough we can coordinate and try to include it 🙂
This would be cool, not just for ACF but the other meta plugins.
Great to know, it's something we must consider since the beginning.
What if core "post meta (aka custom fields)" and "ACF integration" will be coded so that both are consumer of the same API used to expose ~~custom fields~~ dynamic data to blocks?
Treating WP as a consumer-of the API could be a way to have this API looks agnostic, facilitating third party integration.
Core WP produce a new API that is used to expose ~~custom fields~~ dynamic data in block toolbar based on context. Core WP produce also an adapter that consume the API to expose "post_meta" , "post_title" and so on...
ACF, and any other plugin, then need to produce an adapter for its own plugin.
In this way, core WP can produce a contract and be also the first consumer of the API, so that problem that would eventually arise for a third-party consumer will be soon tackled.
@SantosGuillamot, thank you for posting the detailed update with accompanying visuals that help to tell the whole story. While we have enough to do the more advanced prototyping in the Gutenberg plugin behind the feature flag for experiments, it will be initially limited to everything available in WordPress core internally. Obviously, it's a trade-off, but that would help us iterate fast and land a UI that could get shipped in WordPress 6.5 if it provides enough user value. In the case of post meta, it's all simple today as it's covered with the existing REST API endpoint that is integrated with @wordpress/core-data
through @wordpress/api-fetch
so to modify the value on the client you need very little code, example pseudo-code:
import { useEntityProp } from '@wordpress/core-data';
const [ meta, updateMeta ] = useEntityProp( 'postType', 'post', 'meta', 123 );
updateMeta( {
...meta,
my_key: 'foo',
} )
In parallel, we should continue the discussion started and concentrate our efforts on building a compelling API that allows us to integrate any data source. From the technical perspective, it would be convenient to tap into the existing concept of entities inside @wordpress/core-data
that is integrated very deeply with the block editor. The first step would be identifying the unique requirements for this integration. @lgladdy mentioned the ability to run a custom filter for the value on the server before rendering the value. The supporting question would be how we can apply the same transformation in the editor in case we would like to show the preview, or is it fine to proceed with the raw value?
@sc0ttkclark, how does all that fit into the vision for the Fields API project? @tresorama , could this API be mostly based on PHP and the adapter would be the REST API endpoint that works on the client the same way how post meta in the example above?
The biggest advantage of using @wordpress/core-data
is that it integrates automatically with the editor, offering a way to persist the changes on the server in a way where users have full control over it when about to save changes in the editor:
For the full context, this is the code that initalizes the configuration for all post types so it's possible to use their REST API endpoints with useEntityProp
or useEntityRecord
interfaces:
https://github.com/WordPress/gutenberg/blob/52e9eb2950647c2439d4365fcae867dc01ea0b15/packages/core-data/src/entities.js#L278-L333
The supporting question would be how we can apply the same transformation in the editor in case we would like to show the preview, or is it fine to proceed with the raw value?
Hey @gziolo - specifically for ACF here, I think it's fair to assume anyone wanting to consume ACF meta in the block editor would expect values to be transformed by their requested return formats, so having a specific filter where we can modify the results going into the block editor via the REST API would be good (this may already exist, but I'm not sure if there is available context is specific to rendering in the block editor)
We do already support returning all ACF meta in the REST API in an acf
key, so we could potentially do something on page load in JavaScript to pre-fill all of our formatted meta into the core-data cache as meta?
Also, it's worth mentioning, ACF users could potentially have substantial amounts of fields in meta for a page that will appear via get_post_meta
, so some way to handle that without showing every possible option feels important here in v1 to avoid that list of connectable meta fields being hundreds of entries long.
In this way, core WP can produce a contract and be the first consumer of the API, so that problem that would eventually arise for a third i party consumer will be soon tackled.
@tresorama shared the perfect words for what I wanted to express. Same with these from @gziolo
concentrate our efforts on building a compelling API that allows us to integrate any data source
One concern I have with these mockups is that they are already a bit tight on their fit to a specific use-case, which is meta fields for a single attribute on a block. From the get-go I see the need to address blocks having multiple bound attributes - something already exposed by @michalczaplinski's exploration in #53488 because it really doesn't make sense to replace an image's URL without providing the ability to supply a proper alt
description or title
.
Further, as we build the UI for the use-case of meta fields we may miss that different data sources will have different UI needs. I think that somewhere you already mentioned, @SantosGuillamot, the need to store various attributes for a given binding, and possibly a validator. These can be surfaced in a general way or in an over-specific way to meta fields.
One approach I can imagine here is to focus not on building meta fields, but building a registration mechanism to supply sources, and then also build an implementation for meta fields that registers. This should hopefully surface some additional constraints like validation and passing arguments and providing fallback values and updating the editor. If we can't accomplish what we need through our interface, then we have to adjust the interface.
As with Bits, there's likely going to need to be separate registration: one on the server and one inside the editor.
register_block_binding_source( 'core/custom-field', … );
register_block_binding_source( 'core/query-value', … );
These registrations need to provide a replacement value when called, given their respective arguments, and might provide information for an API call, might provide a name and label for display in the editor. They could list or enqueue any respective code that needs to run in the editor.
So in the mockups with the custom field meta key, that would be something built through this generic interface. In my head there's almost perfect harmony in the UI needs for that side panel area as there are for when adding a link inside a paragraph or for the block controls above it. We could create a new area that lists all active block bindings for a block, and for each binding add its registered controls, if there are any.
Maybe to toss around some concrete ideas, based on the explorations already shared, we might see something like this…
wp_register_script(
'wp_block_binding__core/query-value',
__DIR__ . '/editor.js',
$deps
);
register_block_binding_source(
arary(
'name' => 'core/query-value',
'label' => __( 'Query Value' ),
'description' => __( 'Use a property from the current post or item in a query loop.' ),
'provider' => 'wp_query_value_binding_provider',
'editor_script' => 'wp_block_binding__core/query-value'
)
);
import { registerBlockBinding } from '@wordpress/block-bindings';
registerBlockBinding( {
name: 'core/query-value',
controls: QueryValueControls,
getAvailableBindings: ({block, context, attrs}) => context.isPost ? [ … ] : [ … ],
bindingPreview: ({block, context, attrs}) => …,
getFallbackValue: …
} );
I love the direction of this, it looks fantastic! This is what I believe many plugins enabling embedding of Dynamic Content within a block could benefit from too.
GenerateBlocks and Stackable Blocks both allow connecting fields. I've built integrations that extend them to offer even more comprehensive and flexible options for embedding things based on the additional context that Pods itself knows about those configurations too. I believe we'd benefit from that filter that @lgladdy mentioned towards improving the content that is embedded (not just the raw meta value).
I also agree that we need some ability to limit what fields are available to be used/shown here.
Another item not mentioned but that would be helpful here would also be to define the "label" shown instead of just the meta_key
name. Could be as simple as adjusting register_meta()
to support a label too, or just filtering the list of meta keys for that object type.
@gziolo Regarding the Fields API, I see any effort we do from that side would most likely be towards enabling things like this and improving the APIs used to register the field configurations via PHP/JS. Everything I see here isn't stepping on the toes of that project as it stands and would definitely benefit from the things we're doing there too.
Thanks a lot everyone for the great feedback! ❤️
The way I've been thinking about it lately is that we might need two different extension mechanisms:
- Mechanism to extend the "metadata" source.
- Mechanism to register new sources.
It seems to me that they are slightly different use cases, and it could make sense to differentiate them.
1 . Mechanism to extend the "metadata" source.
This would be just a way to add new items to the list of fields we show in the interface. This way, there would be just one unique UI tailored for "metadata". Other plugins dealing with metadata, and even core solutions like site data or post meta, would just hook into this list and add new items. We would end up with a complete list including custom fields, post meta, site meta, ACF...
As part of this mechanism to extend the "metadata" source, each plugin could maybe add more validation for their fields.
2 . Mechanism to create new sources.
This mechanism to create new sources would be part of the Block Bindings API and not part of the Custom Fields implementation.
This one looks more complex to me because each source might be completely different. For example, a new "pattern" source will potentially be used for partially synced patterns.
The way I see it, if we are able to provide the first mechanism and serve the needs of external plugins dealing with metadata, the use cases for custom sources would be much lower, and they will probably require a pretty custom solution.
For that reason, I would say that we should focus first on making sure the Block Bindings API understands new sources BUT don't provide a mechanism to extend the UI. Each of them would need to come up with their own way of adding the proper attributes to blocks as we are doing for "metadata" or they are doing for the "pattern" one. For example, they could add a new element to the blocks toolbar if they feel that's the best way for their use case. Or create a totally different interface.
This is all assuming the first mechanism is enough for metadata.
Regarding the UI of custom fields shown in my comment, I would like to emphasize a couple of things:
- It was just an experiment to help me explain the purpose of the project. The UI still needs to be discussed.
- We will probably need to iterate the UI. We can start with a basic UI and extend that later.
cc: @michalczaplinski
Can you expand more about the reasoning because for me, I think the first one is just a special case of the second one.
I believe I was trying to distinguish them more from a user/extender perspective than from the technical implementation.
Imagine I have a plugin that creates new custom fields. I would probably just want to ensure that the fields created with my plugin appear in the list of the "metadata" source. I would probably want to reuse their UI and just add new items, not registering a new source with a similar UI just for my use case. That's what I was referring to in the first mechanism.
Another use case would be that, as a developer, I need to connect block attributes to a totally different source with a different UI. For example, that's the case for partially synced patterns, where they are connecting block attributes to the content defined in the pattern. Or imagine I want to connect, for any reason, block attributes to a shortcode or a custom PHP snippet. It wouldn't make sense to reuse the logic created for metadata and it would make sense to create a new source.
In my head, it made sense to distinguish them because the use cases for the second mechanism seem less common to me, and they will probably require more custom solutions.
Anyway, I am still trying to connect everything and I am not convinced how it should work. Just sharing to get more thoughts 🙂
Imagine I have a plugin that creates new custom fields. I would probably just want to ensure that the fields created with my plugin appear in the list of the "metadata" source. I would probably want to reuse their UI and just add new items, not registering a new source with a similar UI just for my use case. That's what I was referring to in the first mechanism.
To be honest for me, it's not very clear whether they should be in the same UI. Also, I believe the UI bit is not important at all for this project (at least initially). It's going to be a challenge for the user to understand what the UI is doing (connecting to sources). So I think for the start, the project is more aimed towards developers creating block variations, new block bindings (though even this could be private to start with as we implement the first ones).
In that sense, I don't think adding a "shortcut API" is the best path to start personally.
I'm guessing the question comes down to:
- Do we want "post fields", "site fields", "template fields" maybe (I can't think of anything else) to be part of the same "block binding source" or do we want each of this to be a separate "block binding source". I feel it's not important to answer this today, because I think all of these sources are "core provided sources". I'd love to understand more what "other fields source" plugins should add here?
Just sharing a pseudo-code POC.
I wanted to begin from an extender perspective, the "who" want to add a dynamic data source to the core API. Example of extender can be:
- ACF custom fields
- Wordpress post meta fields
- Wordpress site properties (site url, site name, ...)
- Wordpress current post properties (post title, post author,...)
I wanted to iterate more on this before posting but maybe can be already beneficial even in this draft state...
NOTE: I haven't touched any Guteberg related code in months, so maybe I'm missing something "obvious" about how to use the API. Especially in the Data Fetching part, if I remember correctly there was a method to retrieve from the redux store outside of React, bypassing the limitations of React Hooks. If anyone has any suggestions to point me in the right direction that would be great
https://gist.github.com/tresorama/bf512a84b6a32faafadd1600664118d1?permalink_comment_id=4763241#gistcomment-4763241
For example, a new "pattern" source will potentially be used for https://github.com/WordPress/gutenberg/issues/53705.
It seems like partially-synced patterns and block bindings are divergent enough that designing this system to support it is an invitation for scope creep and I worry that it could broaden the requirements in a way that is unworkable.
I'd rather we focus on this primary use-case and the necessary API it needs for developers to hook into it:
Replace the content in a rendered block that corresponds to an attribute defined in its
block.json
file with new content generated during the render.
Custom fields and anything else of the same kind of data could be provided together, and I don't see why Core's custom field provider couldn't itself be extendable, but other sources requiring more setup (e.g. a stock ticker or a foto feed) would provide their own registration.
It seems like partially-synced patterns and block bindings are divergent enough that designing this system to support it is an invitation for scope creep and I worry that it could broaden the requirements in a way that is unworkable.
I agree they are very divergent in terms of the data sources. As someone working on partial syncing, I think it's absolutely fine to start developing the binding API with custom fields and other post data as the primary target. I personally find it very hard to assess what opportunities there are for partial syncing using the bindings API without something more concrete. Having a more concrete API can also help with the development of partial syncing. At the moment the work being done is without guidelines or constraints, so it has naturally diverged. Imposing some constraints wouldn't be a bad thing.
Even with the divergence, I think there's still some overlap. The rewriting of block HTML server side is a system both custom fields and partial syncing can leverage, so it's worth considering some integration points.
Maybe to toss around some concrete ideas, based on the explorations already shared, we might see something like this…
My main suggestion is to delay exposing any UI parts of the API. UI is always in flux, if API users are able to directly pass react components in it makes it much more challenging to change later on.