-
Notifications
You must be signed in to change notification settings - Fork 133
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
RFC: React Components to Gutenberg Blocks #1522
Comments
To make sure I'm understanding this correctly, if only a blockJson is provided, and not the edit/save functionality, then the component/block will be displayed in the admin, but all editing will occur in the sidebar? Otherwise, I think I'm missing the connection between providing the schema/props for the block and the visual editor for editing conntent/props in place. Also, I'm curious how nested blocks might be supported. |
Hey @jmusal Thanks for the feedback. I still have to fill in a section in the RFC but I can answer some of your queries:
Yes we need the
You don't have to provide an edit or save functions since they will autogenerated for you by the
Yes. You will have to provide hints using the component config section (I will have to provide details in the
For now you can just use regular React By default the generated edit and save functions will use the standard |
Where will these React Components coming from / should this packaged be used?
Personally, I think a better immediate target for keeping things DRY and reducing friction (especially considering the noted limitation in the Putting aside the significant comparative benefits , handling react-to-gutenberg first almost guarantees a breaking change for both the library and all the people who adopt it. It's a lot easier to extrapolate the DX in reverse. |
Hey @justlevine Thanks for the comments. Let's get into them:
We assume that you have already made React components that you created and you want to try in Gutenberg. That's without any prior knowledge of how to create them using the edit or save functions.
That would be another lists considerations that @josephfusco can help you with. He is working on a POC to better handle syncing the components between WP plugin/theme and our frontend app. Maybe he can provide more clarification here. This RFC deals specifically with what you need to use to take a React component and present it in the Gutenberg Editor without having to provide your own edit and save functions which greatly simplifies its scope.
That would be nice but not sure how feasible it is without introducing extra baggage or a lot of problematic scenarios. For example take any random Gutenberg block component from the core block-library and you will find almost immediately that it is definitely not portable outside the Gutenberg Editor context. The promise of this RFC once implemented is that you can use the same React Component in both the Headless site and the Gutenberg Editor side without having to maintain a duplicate implementation for the Gutenberg Editor. It will be somehow a hybrid approach.
Not necessarily. You can have your React Component developed on a package that you can import them into your blocks plugin so that Gutenberg can use them as well. The key thing is that the React Component will have to be unaware of any Gutenberg Editor related stuff so they won't be ported into you headless site. The breaking change may happen if you commit certain React Components in the database and then change their markup. Since the Gutenberg will warn you if the implementation part will change when you try to load the component from the database. However if you have your React Components under a version control system you can use semver to keep track of their changes. Another possibility is to provider a custom deprecated function so that you can deal with any changes. IMO this would allow you to try-before-you-buy since the React Component will not depend on the Gutenberg side. You plug it in. You check if you are satisfied. You provide extra hints to refine this better and if you are happy you keep using it. If you are not you just simply take the React Component elsewhere. |
A less productive comment, but I can't express how excited I am for this. If you need any help, I'd be happy to try to help out however I can. |
Thanks @theodesp 😊
...
To clarify by "coming from", I mean where are the code for the components supposed to live/get registered. While a POC is nice for working out implementation kinks, I'm just trying to understand what this library is intended to achieve, and how it will allow you to not 'maintain a duplicate implementation'. If the goal is simply/strictly about extending WPs block registration API for non-WP users then that's one thing, but that's is a solution to a very different problem statement than what's outlined here. Ultimately I'm trying to understand how this RFC is meant to address the frictions of using blocks in HeadlessWP (that you mentioned or otherwise )🙏 (Skipping the rest for brevity, the intention of my suggested alternative was to sketch out the ideal ecosystem pattern that the ecosystem is striving to - WordPress as a source-of-truth - and how that directly relates the problem statement in comparison to what's proposed here. A separate RFC and eventual POC would be the place to work out implementation details/ engineering hurdles just like what's happening now on this one) |
It's up to the developer to decide where to put the components. What's important for WordPress is to have the call to register_block_type that points to the folder that contains a valid
One big problem with Headless WordPress adoption is that a lot of agencies want to use Gutenberg blocks and share the same component in both places without having to maintain two implementations. A lot of those agencies already have some React Components that they would like to use them in Gutenberg. However they always have to start from scratch and waste tons of development time with porting it into Gutenberg. With this RFC we provide a conventional and somewhat opinionated way to do that without having to change a lot while giving them an opportunity to plug their components directly to Gutenberg. For example: Take a component like: https://grubersjoe.github.io/react-activity-calendar This component will render a github activity calendar when passed the list of dates and some other configuration. With this proposal you will be able to provide editor controls to fill in the required properties that this component needs and it will render as it inside the editor when using the presentational view. You don't have to provide an edit or save function since this would be automatically generated for you by the helper function. You only have to provide a simple block.json with the attributes you want to have and a component to render the activity calendar. Some thing like: export function MyActivityCalendar({attributes, className, children ...rest}) {
const {data, theme} = attributes;
return <ActivityCalendar className={className} data={data} theme={theme} {...rest}>{children}</ActivityCalendar>
}
// Declare metadata here
MyActivityCalendar.config = {
name: 'MyActivityCalendar',
...
}; This same component will be used in both the Headless site and the Editor site, thus reusing the component implementation part. (NOTE: In some cases you have to be careful how you define the |
Which means either the duplicated code still needs to be maintained separately in both places, or the component needs to be imported as a dependency from a package (such as in your example, the unique feature here if I understood it is that the component wrapper is simplified). If that's the case, I suggest updating the RFC (scoped along the the lines of "This library will allow Block Developers to easily import and register React components as Guternberg Blocks, without the unnecessary boilerplate".) There's no deduplication or impact on headless WP here, the benefit is avoiding parts of the block registration API. Alternatively, this RFC is introducing a new mechanism to allow React component that only exists on the server/frontend to be imported/used somewhere else without moving it to an npm dep. That's what I've been trying to get clarification on, but I guess I'll wait for Joe's POC 👍 |
Pinging @josephfusco here to provide more context. |
@justlevine Hoping I can shed some light on this! The goal would be for the code to live under version control within the NextJS app. I'm proposing the following CLI commands to help facilitate this:
|
@josephfusco that truly is ecosystem pushing! Mad props mate! @theodesp Idk if its worth the effort to transcribe all this into the RFC while the proof-of-concept is still in flux. The tl;dr that I do think is worth adding to make the RFC clearer (and directly address the intro/motivation) is along the lines of:
|
I'll let @josephfusco handle that part since he is working on that feature. |
-> Working example demonstrating how block files would be moved to WordPress. |
The Blockset file sync POC is now a fully working example with Next.js "blocks" showing up to the publisher within a few seconds of running Feel free to leave any relevant feedback you have directly in that PR. |
The block support package contains an example. |
Is this mapping of |
Yeah we don't have a definite nice way to handle object types since they could be anything so we opted for having a field that stores value as a string. Maybe there is a way to make it better. |
We're closing the current RFC as we have implemented the basic functionality. If you have further suggestions for improvements, encounter related issues, or have code changes you'd like to propose, we encourage you to either open a new issue or submit a pull request. |
Intro
This document provides a detailed proposal for converting existing React components into Gutenberg blocks. Gutenberg blocks are the fundamental building blocks used in the new WordPress editor, also known as Gutenberg. The goal of this RFC is to streamline the process of integrating React components into WordPress using Gutenberg, which will enhance the development process and make it more efficient and pleasant for the developer.
Motivation
WordPress powers a significant portion of the web, and React is a popular library for building user interfaces. Converting React components into Gutenberg blocks will enable developers to utilize the power of React in WordPress development. This approach will also make it easier to keep the code DRY (Don't Repeat Yourself) and maintain a consistent UI across different parts of a WordPress site.
For example, in many cases a developer has created many React Component that would like to use in the Gutenberg Editor. Currently there is no standard way to do this. As a matter of fact, most development of Gutenberg Blocks happen first and then are converted to React and not vice verca. This creates a lot of friction and slowing adoption of Headless WordPress initiative.
Detailed Design
The proposed solution involves creating a wrapper component that would serve as a bridge between React and Gutenberg. This wrapper component would be responsible for rendering the React component inside a Gutenberg block.
Here is an example of what the code might look like:
In this example,
MyFirstBlock
is a React component that we want to convert into a Gutenberg block.There is a new package that exposes a helper for facilitating this conversion.
registerFaustBlock
takes the following arguments:User Experience
The
registerFaustBlock
function will autogenerate custom edit and save functions that the Gutenberg Editor requires to register a Block.Upon Component Registration, the Gutenberg Editor by default and using the blocks block.json will create editor fields that the user will be able to fill in.
Here is a screenshot of the above React Component that contains 3 fields. A textarea and two color pickers:
By default, it will create relevant fields in the Form Editing View. In this mode, users will be able to fill in the component information using the generated control fields.
However, the developer has the option to provide hints to the registration function to assign certain fields on the sidebar as
InspectorControls
. Here is the same block with the two color controls located in the sidebar:Users would be able to switch between the form editing view to the presentational view using a preview button:
Block Fields Configuration
This section is dedicated to provide a more detailed view of the available options to configure the default UX when using
registerFaustBlock
helper and to customise the block in the Editor according to your needs.block.json fields
The
registerFaustBlock
helper will parse the respective block attributes and associate them with Editor Fields. The corresponding table represents the mapping logic between the block attributes and the associated fields:text
number
number
Note: The array type won't be supported initially.
Labels
Each form field will consist of a Label and the associated control type. By default, the attribute name will be used as a label. Users would be able to override the default label by using the
label
property in theeditorFields
configuration object. (See below).Ordering
Each form field will be rendered by their order they were defined in the
block.json
attributes list. Users would be able to override the default ordering by using theorder
property in theeditorFields
configuration object. (See below).Providing hints with the
editorFields
configuration.Since by default, when using the
block.json
supports only a limited types of fields, users would be able to provide more hints and configuration metadata to configure both the type of the control fields and their location. For example as mentioned in the demo component above, users can declare that some of the fields should be located in the sidebar and using a more appropriate control type like a ColorPicker. This will enhance the default editing experience.To provide hints when registering a React Component with
registerFaustBlock
, create a new property callededitorFields
and attach this to the React Component:Here the component config section contains the new
editorFields
property that provides hints to the helper when building the final fields configuration. The associated field names should match the one with the block.json attributes. Each field will be merged together to form the final field configuration.For example the first field
message
will have the final configuration:This will create a
TextAreaControl
field with a default value of""
, a label"My Message"
and located in the Form Editor side.Similarly the rest of the fields:
bg_color
andtext_color
will render aColorPicker
component and be located in the InpsectorControls area (block sidebar).Available Controls
The
registerFaustBlock
helper with use conventional methods to merge block.jsonattributes
andeditorFields
to create the final configuration for constructing the respective Editor Fields and InspectorControls.The following control types will be available:
text
number
Invalid combinations
We may chose to ignore certain invalid combinations of control types and attribute types. For example using
type: "boolean"
andcontrol:"color"
.In such cases it will fallback to regular
TextControl
with a warning.Drawbacks
One potential drawback is that, depending on the complexity of the React component, the conversion process may not be straightforward. Some React components may rely on context or hooks that don't have a direct equivalent in Gutenberg. In such cases, you have the option to provide your own Custom Edit or Save functions when using the
registerFaustBlock
helper function.Another caveat is that since we are registering the components as static blocks, then any use of
useEffect
,useState
hooks are not allowed inside the component. See related SO answer.However we could alleviate this fact by leveraging the Interactivity API in future iterations of this proposal.
In the meantime we will propose effective workarounds and limitations when using the components that would be compatible out of the box with our solution.
How to Contribute
Interested in hearing your thoughts on this and any possible enhancement's that you want to see materialised. Do the conventions make sense?
The text was updated successfully, but these errors were encountered: