Pitch - JSON Approach For the Fields API #109
Replies: 5 comments 13 replies
-
I really like this pitch. I wonder if some of the properties can be decoupled to define a flatter JSON?
|
Beta Was this translation helpful? Give feedback.
-
On Locations and Field GroupsThis approach to field definition is very bottom-up, which is to say that the field is an entity that can be rendered in any number of places. While I think that approach has merit, I believe most existing field plugins approach field definition from the top down: location-specific groups of fields are defined, into which controls are added. I think we need to make a determination on which approach is most suitable for all the various ways we expect this to be used. One point in favor of a "field group" approach is the potential for in-group conditional rendering. While it would be very impractical for any individual field to conditionally render based on another field that may or may not be present at a location, defining groups of fields together allows for co-location of conditional logic* between fields. Another point of concern I have is defining datastores per field. I think it's likely that the datastore would be highly coupled to the location a field or group of fields is rendered. For instance, rendering fields on the edit screen for a particular post type likely means the datastore is post meta--and let's not forget that we may need some special conditions for certain locations, like *This is a bit of a tangent, but considering conditional logic has me realizing that pure PHP rendering of field markup will likely not be enough, and we might benefit from jumping straight into a system based on React for field rendering, since we know the admin is going that direction anyways. |
Beta Was this translation helpful? Give feedback.
-
I agree with all of you: Having a JSON representation of the fields will be key for being able to leverage the Fields API in both the PHP side of the house as well as the Block & Site Editor. I have a couple of thoughts that might be worth some discussion: Forms are more than just the fieldsWhile this is a Fields API, whatever we build needs to keep in mind that it will power forms and forms need more than just fields. We need an API that supports the injection of non field-related elements so that we can reduce the overhead of generating forms. PHP first, JSON secondHand-built JSON can introduce confusion for developers and unpredictability with initializing a field set because, well, humans are humans and it is easy to misread/add a typo/etc. Building out a JSON file requires knowledge (or a reference) of the structure and meticulous attention to ensure a properly formatted result. A PHP-first API would allow:
GiveWP's approach feels fairly approachable from the Fields API kick-off call earlier this year. Here's a potential example using some of the naming conventions proposed above: use WpOrg\Fields\Location;
use WpOrg\Fields\Section;
use WpOrg\Fields\Text;
use WpOrg\Fields\Email;
$location = new Location( 'some-form' );
$location->append(
Section::make( 'the-section-id' )
->append(
Text::make( 'first_name' )
->label( __( 'First Name', 'whatever-textdomain' ) )
->rules( 'required', 'max:255' ),
Text::make( 'last_name' )
->label( __( 'Last Name', 'whatever-textdomain' ) )
->rules( 'required', 'max:255' ),
Email::make( 'email' )
->label( __( 'E-mail', 'whatever-textdomain' ) )
->rules( 'required', 'email' ),
)
); From a PHP API, the fields would be serializable. $json = $location->jsonSerialize(); [
{
"name": "the-section-id",
"nodeType": "group",
"type": "section",
"nodes": [
{
"name": "first_name",
"nodeType": "field",
"type": "text",
"label": "First Name",
"defaultValue": "",
"helpText": "",
"placeholder": "",
"readOnly": false,
"validationRules": {
"required": true,
"max": 255
}
},
{
"name": "last_name",
"nodeType": "field",
"type": "text",
"label": "Last Name",
"defaultValue": "",
"helpText": "",
"placeholder": "",
"readOnly": false,
"validationRules": {
"required": true,
"max": 255
}
},
{
"name": "email",
"nodeType": "field",
"type": "email",
"label": "E-mail",
"defaultValue": "",
"helpText": "",
"placeholder": "",
"readOnly": false,
"validationRules": {
"required": true,
"email": null
}
}
]
}
] Handling datastoresWith a OO PHP API, we could create field objects with traits (perhaps similar to Give) and explicitly indicate that specific fields should be fetched and persisted in specific locations. Visibility conditionsLikewise, with OO PHP, we can have some very flexible approaches to field visibility, leveraging values from other fields, closures, etc. $form->append(
Checkbox::make( 'sandwich' )
->label( 'Get a sandwich?' ),
->checked( false )
->value( 'yes' ),
Select::make( 'bread' )
->showIf( 'sandwich', '=', 'yes' )
->options( [
'wheat' => 'Wheat',
'white' => 'White',
'rye' => 'Rye',
] ),
Checkbox::make( 'super_deluxe' )
->label( 'Make it super awesome?' ),
->checked( false )
->value( 'yes' )
->showIf( 'is_admin' ),
Checkbox::make( 'wrapped_in_wax_paper' )
->label( 'Wrap it in wax paper?' ),
->checked( false )
->value( 'yes' )
->showIf( function() use ( $some_other_thing ) {
return is_admin() && $some_other_thing;
} )
); |
Beta Was this translation helpful? Give feedback.
-
Handling non-fields seems - by definition - out of scope of a fields API. Could you share a use case/example? |
Beta Was this translation helpful? Give feedback.
-
👋 New and catching up here, but I'm not sure about the inclusion of "location" data in the field definition 🤔 It seems to me that locations are collections of fields that are mostly useful when rendering. I don't see a use case where we'd need to check all the different locations that a particular field is registered in, rather the most obvious need would be the inverse: getting all the fields that are registered for a particular location. What's more, I think the definition of the field itself should be independent of whatever locations it's registered in in order to fully decouple field definition from rendering. |
Beta Was this translation helpful? Give feedback.
-
I started working on a very rough PoC earlier this week, and it helped me form an opinion on how I think the fields API could work. I think there's some pretty good ideas here that would allow us to implement the fields API without disrupting WordPress backcompat.
The key component of this approach is that the rendering is completely decoupled from the fields. This allows us to register fields without trying to wrangle the disparate methods in which WordPress currently outputs HTML in the process. Further, the approach allows us to inject this into existing locations without requiring significant refactors in the process.
My hope is that this discussion will help kick off discussions about the individual components that would ultimately make up the fields API. This would allow us to break this project into smaller pieces, and enable us to split up into multiple teams to work on the individual pieces. With this clarity, perhaps it could also open up opportunity for buy-in from other teams, such as the people working on the new admin UI, or Gutenberg itself.
Most of this content came from discussions that have happened inside the core-fields channel in Make WordPress. If you're interested in contributing more, I encourage you to join there since we've been talking about this topic quite a bit lately.
Goals
The primary goal of the Fields API is to make it possible to register, and display fields anywhere in WordPress, through JSON files. These JSON files should be able to sufficiently describe fields, and allow these fields to be displayed throughout WordPress without writing any PHP or JavaScript.
It should be able to be used throughout the existing WordPress interfaces, as well as be something that can be used in future interfaces. Further, it should be relatively easy to introduce the fields API anywhere, and should not require significant refactoring to add.
The JSON
The goal of JSON file is to make it possible to completely describe any set of fields within WordPress. This should allow you to:
The JSON below is absolutely not complete. This is just a starter point to start thinking through how it can be used.
Now there's a lot going on in this JSON, so let's break it down into pieces.
Datastore
The datastore portion of the JSON determines where the field saves the data. There can be any number of datastore types, and they would need to somehow be registered in PHP, probably using some kind of abstract class or interface that has a set of specific methods that enable the crud operations against the datastore.
Perhaps something like this:
Where
Some_Datastore_Handler
is a class that gets instantiated with the JSON data, and that information is used to help inform how to save the data.Validations
The datastore could also support an array of "validations", which can also be registered, and have their own handlers to validate. You'll see these validation types show up in other places, as well, and are intended to serve as a way to make a pre-made conditional usable inside the JSON. In this case, if the person does not have the role of administrator and the input value is not a valid email, validation would fail and the content would not be saved.
Perhaps something like this:
Or maybe a functional-based approach:
Ultimately, this should be able to do all basic CRUD options for any given field, and make the validations necessary before saving to ensure that it should save.
Locations
Locations could be an array of places in-which the field would be rendered throughout WordPress.
Controls
Each location would be associated with a control. Just like validations and datastores, these controls could be registered, and then associated with a class interface that is instantiated with the JSON data. This data is then used to parse, and provide the information about the control, which enables whatever is being used to render the content to actually do the rendering.
Perhaps something like this:
Note that in this concept a control does not actually render the content. It is intended to instead describe the field to whatever is doing the rendering. The control type would use the input data from the JSON to provide the actual information for the control.
The control above includes
hide_if
anddisable_if
validations, which could work with the same validation types as discussed above. This allows us to signify if a field should be conditionally hidden, or if a field should be disabled.Rendering These Locations
Fields for a location could be registered, and then rendered inline by either calling a PHP function, or a React component:
Behind the scenes, these functions would need to:
In either case, we would probably need to somehow map field control types to different markup strategies. In React, this could be a component. In PHP, we would probably need to create something to handle this since there isn't a standard way to do that right now.
In the case of the block editor, we could ensure the fields render quickly by adding them as preloading middleware for the field data, but that's just a suggestion 😄.
Working With Fields
I think it's important that the fields API allows us to work with these fields both in PHP and with the REST API. I believe this is what will enable the system to work well inside the block editor, modern admin interfaces, future iterations of the WordPress app 🤞, while also enabling us to create backcompat layers with existing systems, should we choose to do any refactoring (although this probably isn't going to be necessary.
While this is definitely not complete, some things that I think we would need include:
It could be really useful to have a registry query function that could be consistent with how other query objects work. something like:
Which would yield an array of
Field
objects that are in thepermalink_settings
location.Beta Was this translation helpful? Give feedback.
All reactions