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

Very high barrier of entry for developers #5739

Closed
dennyf opened this issue Mar 22, 2018 · 16 comments
Closed

Very high barrier of entry for developers #5739

dennyf opened this issue Mar 22, 2018 · 16 comments
Labels
[Feature] Block API API that allows to express the block paradigm. [Feature] Extensibility The ability to extend blocks or the editing experience

Comments

@dennyf
Copy link

dennyf commented Mar 22, 2018

Issue Overview

For the past few days I've been reading (almost nonexistent) documentation and blog articles, so I can try to build a custom block. I must say that I cannot wrap my head around how it is possible that the developer interface is so complicated.

I have experience with WordPress development, PHP and JavaScript and even some basic experience with React and still found the process of registering a custom (very simple) block quite challenging.

How is it possible that registering a simple element, like a button that only has text, link and color attributes to require 200+ lines of code:
https://github.com/WordPress/gutenberg/blob/299f1b89d703333d60a6a9495e5da0a74d196f53/blocks/library/button/index.js

And it is expected from the plugin developers, many of whom are maily PHP devlopers and not advanced JS developers (not to speak about React), to just jump on board and spend months of work to learn this complicated API, so they can build a few simple elements for their plugins. This is just not right.

Expected Behavior

Gutenberg devs, please take a look at some of the most popular builder plugins such as Visual Composer and Elementor to see how simple their API is, in the same time providing even more advanced functionality than Gutenberg has.

Gutenberg should provide a simple PHP or JavaScript interface to register custom blocks, something in the form of (this is just an illustrative example):

registerBlockType( 'myplugin/button', {
    title: __( 'Button' ),
    icon: 'button', 
    category: 'common',
    attributes: {
        text: {
            type: 'richtext',
        },
        bgcolor: {
            type: 'color',
            label: __('Select color'),
            location: 'sidebar'
        }
    },
    render: function(props){
        <button className="button" style={ { backgroundColor: props.bgcolor } }>
            {props.text}
        </button>
    }
}

so that developers won't have to care about:

  • rendering the controls manually (including lots of repetitive code)
  • writing the same markup twice (in the edit and save functions)
  • writing callback functions to handle updates of each of the controls

Gutenberg should do all of this automatically in background. This functionality reminds me of the Post Meta and Options APIs which only provide a few basic functions, but the developers still had to write manually the markup of the elements, save the data, etc. This resulted in a great UI inconsistency between the plugins and many ended up using helper plugins like ACF to accomplish something simple that should have been available by default.

It doesn't have to be that complicated. If you want the plugin developers to become excited about Gutenberg, there should be a simple interface to create custom blocks. Until then, most of the people will be anxious and will fall back to other solutions to support their custom elements (such as disabling Gutenberg).

@maddisondesigns
Copy link

This is the same issue I have with the Customizer. The amount of code required to do the bare minimum is ridiculous.

@dennyf
Copy link
Author

dennyf commented Mar 22, 2018

@maddisondesigns Agreed - the customizer is another example of an API that can be a lot simpler. I had to write my own internal library, so I can register controls with a few lines of code (instead of having to write tons of repetitive code for each control). I hope we won't have to do the same with Gutenberg.

@Luehrsen
Copy link
Contributor

Luehrsen commented Mar 22, 2018

While I understand (and feel) your problem very much, I think you are comparing apples and oranges.

One of the main focuses of Gutenberg is to provide stellar UX and accessability. That is one of the reasons, why a 'simple' button has a little more that 200 lines of code. Because it is not just a button, the file lets you set colors, checks background and text color contrast, lets you toggle aligment, set links and text.

As a developer I very much like the (seeming) complexity of the current iteration. It gives us great freedom in what we want to do, while still providing a solid framework provide necessary functionality.

If you want one more layer of abstraction take a look at create-guten-block by @ahmadawais, which gets you about 60% to where you want to be. He also provides a great example of a very simple block, which is at about 70 lines of code, 26 of which are just markup for frontend and backend, and if you ignore comments and just count business logic, you can get well below 30 lines of code.

@dennyf
Copy link
Author

dennyf commented Mar 22, 2018

@Luehrsen The thing is that this is not only my problem - it will be everyone's problem once Gutenberg ships with WordPress.

And I'm not saying that the existing API should not exist - it should be available for those who want to create more custom elements.

However, most of the people will need to create just simple elements with a few attributes. For example, I will need to register 15+ elements for one of my projects - most of these elements have very simple attributes, such as "name", "color" and "link" and maybe a category selector. If I have to use the current API, I will need to write 3000+ lines of code just to do that. And in most cases will be the same repetitive code - including the general widgets, such as a color picker, a text field, an alignment toolbar, etc.

This is not productive - countless of developer hours will be wasted for no good reason. Most of the people won't have the time to write so much code, not to speak about how long it will take to learn and understand how the API works.

I've tried create-guten-block - all it does is help with setting up the build tools, but it doesn't help with the complex API. Their example is just a text block that has no editable attributes, so that's why it is short. It is however a very good example of how you need to write repetitive code in the edit and save functions.

Writing 200+ lines to register a simple button element is not okay. There should be a higher level of abstraction that allows devs to register custom elements easily, with only a few lines of code.

To sum up, registering simple common elements should be easy and intuitive. I don't argue that there shouldn't be also a more advanced API for those who want to go beyond the basics, but this should not be the default.

@pento
Copy link
Member

pento commented Mar 23, 2018

Thank you for the feedback, @dennyf!

I agree that there are definitely places where it could be easier for developers to get up and running, and to build things in an appropriately concise manner.

create-guten-block is a good example of a tool to fix the first part: ensuring you can start working on a new thing as quickly as possible. WordPress certainly needs an "official" tool for that, but there are community examples popping up in the mean time.

For creating blocks, there are certainly parts of the developer experience that could provide less verbose options. I really like your idea of being able to define the settings interface for attributes, it seems like the most common case for attributes that require user input would be for it to simply store the value that a primitive from the Components library returns.

I'm not so sure about providing a render function that replaces both the edit and save functions, though. It seems like this would only be valuable for extremely simple blocks that don't provide any editing interface inside the block, everything would have to be in the sidebar. In your example above, the props.text part of the render function would either need to be edited in the sidebar, or it would need to be somehow transformed into a RichText element depending on whether render is being called in an edit or save context.

Did you have more thoughts on how that might be achieved? Either way, I agree that some work could be put into the block API to make it simpler to start working with.

@pento pento added [Feature] Block API API that allows to express the block paradigm. [Feature] Extensibility The ability to extend blocks or the editing experience Needs Dev Ready for, and needs developer efforts labels Mar 23, 2018
@pento pento added this to the Merge Proposal milestone Mar 23, 2018
@dennyf
Copy link
Author

dennyf commented Mar 23, 2018

@pento Thank you for your reply and for giving my feedback a consideration!

I personally don't see any problems with most of the settings being available from the sidebar. I'm going to bring back the Elementor plugin example - all of the element settings are configured from the sidebar and it's a very pleasant UI to work with.
Of course, the RichText control can be an exception to be loaded inline.
Even if you take as an example the "Latest Posts" block, almost all of its settings are located in the sidebar and I think that this should work fine for the majority of elements.

As for ideas about how this can be achieved - I just created a sample working example of one way to accomplish this:
https://gist.github.com/dennyf/b970202e89297ca88ba1d6dcdfa1ad90
(it's only an illustrative example that I built quickly)

As you can see in the bottom of the file, I was able to register a custom element only by using the following code and it also includes an inline text control:

new MyCustomComponent( 'myplugin/button', {
        title: __( 'My Button' ),
        icon: 'button',
        category: 'common',
        attributes: {
            btntext: {
                type: 'plaintext',
                selector: 'button',
            },
            bgcolor: {
                type: 'color',
                label: __('Select color'),
                selector: 'button',
                attribute: 'color'
            }
        }
    },
    function(props, mode){
        let atts = props.attributes;

        return (
            <button color={atts.bgcolor} style={ { backgroundColor: atts.bgcolor } }>
                <MyTextComponent props={props} mode={mode} attrId="btntext" />
            </button>
        );
    }
);

This resolves some of the problems I mentioned above:

  • the controls are rendered automatically and their values are updated automatically
  • edit and save is combined into one function with no repetitive code

If we can avoid setting the selector manually in the attributes, that would be great too.

@mrleemon
Copy link
Contributor

Something like this but for JS would surely ease the building of blocks:

https://github.com/sc0ttkclark/wordpress-fields-api

@StephenAtty
Copy link

i do get the feeling that Gutenberg has been designed without any consideration that a lot of plug-in developers are in many ways "hobbyists". Having to learn React and write large amounts of javascript code to replace a much smaller amount of php / html and javascript could well lead to a lot of developers walking away because it's just no longer worth it... or stops being "fun", If you want people to adopt Gutenberg and make their plugins work with it I really do think that there needs to be a much simpler method of creating blocks and getting plugins to interact with them

@aduth
Copy link
Member

aduth commented Mar 26, 2018

writing the same markup twice (in the edit and save functions)

It would only be the same markup if we assume that the optimal display for a block in the editor is a preview, presumably controlled by some buttons and knobs in a drawer elsewhere on the page. While this is certainly convenient for a developer, one of the earliest design considerations was that direct manipulation makes for a much better user experience. This led to the distinction between "edit" and "save" forms of the block.

Of course, this doesn't mean code need be duplicated. The entire premise of componentization common to front-end frameworks (not just React) is the idea to abstract common behaviors into a component. It's entirely expected that should there be common behaviors between the two, they can be shared easily by use of a component.

While these components may be a new concept for many, one of the primary goals in their introduction is to be able to shield developers from its internal implementation details. For example, the RichText component which manages a TinyMCE instance has significant internal complexity, but the hope is that for the large majority of developers, it can be rendered with only a value and onChange callback.

Can this be improved? I certainly think so. Simple and even moderately complex blocks shouldn't require hundreds of lines of code. I personally have faith in the component abstraction to think that these improvements can be made progressively over time as pain points surface.

rendering the controls manually (including lots of repetitive code)
writing callback functions to handle updates of each of the controls

To both of these, I agree. That's why with iterations like those in #4069, we can collapse some of these common behaviors into a simple supports flag. With a single line of code, these supports can encapsulate whatever amount of complexity is necessary to implement and, better yet, ensures a consistent experience for the end-user, since plugins need not reinvent the wheel for their blocks.

@gziolo
Copy link
Member

gziolo commented Mar 27, 2018

To both of these, I agree. That's why with iterations like those in #4069, we can collapse some of these common behaviors into a simple supports flag. With a single line of code, these supports can encapsulate whatever amount of complexity is necessary to implement and, better yet, ensures a consistent experience for the end-user, since plugins need not reinvent the wheel for their blocks.

I wanted to add here that there are more features that are included this way. You can see the full list in here, but let me emphasize:

  • anchor - let you link directly to a specific block on a page.
  • customClassName - adds a field to define a custom className for the block’s wrapper
    As @aduth mentioned, we started exploring similar concepts you are referring to. It just needs some time to make sure we have all low-level APIs ironed out before we will start exposing this kind of simplifications for the plugin developers.

There is also an interesting initiative started by @sayedtaqui and @danielbachhuber, which is very close to what you proposed for attributes. See this plugin: Gutenberg Fields Middleware. I'm looking forward to see how it evolves in parallel to the ongoing efforts inside the Gutenberg core. We have similar goals because we need to maintain over 20 core blocks so this would be mutual benefit.

@dennyf
Copy link
Author

dennyf commented Mar 27, 2018

@aduth @gziolo

I'm glad to hear that this is something that will be explored!
The Gutenber Fields Middleware looks very similar to what I had in mind, it's a very good example of how the rendering of the control can be simplified for example to middleware.fields.image instead of writing the component and binding onchange callback functions.

I understand that there is no solution that fits all and I can definitely see some cases where separate edit and save functions will be needed and where people will need to write their controls manually. However I hope that there will be also an easy to use API, for those who want to create simple elements.

@danielbachhuber
Copy link
Member

Related #5862

@karmatosed karmatosed modified the milestones: Merge Proposal, Merge Proposal: Plugins Apr 12, 2018
@rchipka
Copy link

rchipka commented May 15, 2018

I implemented a concept for PHP block template partials, which, when combined with Advanced Custom Blocks, would allow developers to easily add fields to any block or block settings panel and then render those settings from a PHP template partial.

I think that most block development will either be a plugin-like block that's developed with the intention to be download and used by lots of people, or as a simple block of structured content that site developers or agencies will use internally.

When it comes to developing reusable blocks with custom UIs, the JS API is the way to go, but when it comes to every-day block composition, I think something quick and easy like block template partials will be the generally accepted approach.

@eddr
Copy link

eddr commented Jun 20, 2018

I want to focus on two issues raised in this discussion. I'm hopeful that there will be a good discussion. Sorry, it's long - I was told to detail the stuff.

  1. **The tutorials and descriptions: **
    Yes, I also feel that
    (a) tutorials aren't good. After a while reading it seems to me that instead of starting with explaining the simple concepts leading to GB, there are lots of words talking about how new and smart it is. It doesn't help to developers, I think.
    Example: https://wordpress.org/gutenberg/handbook/language/ - to figure out Gutenberg from this kind of explanations and tutorials require a lot of effort to understand the language of the authors and process lots of words that are not helping to understand it from developer point of view.
    Constructive (hopefully): Start with a simple, clear main points /+ illustration. People will understand. From there, each point can be detailed more. Don't just throw lots of words

Constructive: The blocks API itself is better, but seems to be incomplete(?), and even for those who are willing to learn react and the whole GB ecosystem, there should be code examples for building a real, full complex widget, like a post selection widget.

  • This is not to be offensive to the efforts and people - I find it very hard to explain new things.
    Is it just me? (I'm able to accept that it's just me, but I don't think so).

(b) There is no one place to go to. As a developer simply trying to figure out GB code, you won't get to one, central place with all the data from WP itself (not talking about 3rd party)

(c)Clearly say what new languages/software are required : When I started reading and figuring it out, reading the API docs and github page, I had no idea that react was in use and also - how and why. I've heard about it half a year before, with the copyrights fiasco, that's all. Big dev introduction to GB?
Also, many tutorials use node and a bunch of software to prepare/compile/transpile their examples, plugins, and stuff. That's confusing and the official WP docs should be the first to resolve this confusion.

Constructive: At least mention what is required, starting from React. Clearly say it is already loaded with the editor and that learning react is a requirement.

**(d) Again with new languages - why? ** GB and WP changed dramatically. It went from almost 100% server side simple editor to 100% client side, based on react philosophy. After all, react is a specific library with specific philosophy. No clear reason to go with it over other open source options or perhaps even simpler ajax library, right? maybe there is a deeper reasoning?

Again, when talking about how much GB is new and shiny and fast, explain - perhaps in a different, updated post, but explain. Give devs the detailed info.

**2. Learning curve: ** Going from almost 0% client side editing to 100%, based on react is a big issue, with many tools that appear in 3rd party tutorials (and probably WP using them too) usually working with node, not PHP. That's not a small change for many developers.
GB is supposed to reduce work? it's not clear how it has/will do so, if you'd have to be proficient in PHP AND react while GB is also hard to extend

Yes, like @dennyf said - allow PHP API to define stuff.

**3. Features vs other visual builder or meta fields plugins ** I totally agree with @dennyf.
Many basic features that repeat themselves can be pre-implemented (many already have been, ofcourse). Take as an example the ** ACF plugin ** which saves lots of hours and ramps up productivity considerably. The functionality it offers isn't special and it's a middleware between the developer and WP built-in capabilities, but it's extremely useful and intuitive and integrating such a thing into WP in general and blocks in particular in some form would be perfect.

Define for a block of type "X" to have a list of posts. ACF does it very well, just not for blocks

**4. Why react? ** I understand it's hard now to change it, but to associate WP with some FB tools is problematic in my eyes, maybe not technically in the short term or at all, but technics are not all in the open source world.

**5. Is there a reason beyond the editor? ** All this work and given the visual builders availability, one asks herself if there is any big plans beyond the editor. Are we going for all react/something WP in 2019?

@StephenAtty
Copy link

StephenAtty commented Jul 1, 2018

What we need is some easy way of getting Gutenberg to render the contents of an add_meta_box call in a GB block. Maybe even a GB specific variant of the existing add_meta_box function,

The Developers would still have to work out how to interact with the GB editor. For example my code uses tinyMCE.execCommand('mceReplaceContent', which would need to be replaced with something else - but I could easily code my plugin so it loads different JS depending on the status of the GB plugin.

I know it would still leave quite a bit of work to do but it would save a lot of developers a lot of time having to learn how to register a block and so on.

Looking at :

https://wordpress.org/gutenberg/handbook/extensibility/meta-box/

Most PHP meta boxes should continue to work in Gutenberg, but some meta boxes that include advanced functionality could break. Here are some common reasons why meta boxes might not work as expected in Gutenberg:

Plugins relying on selectors that target the post title, post content fields, and other metaboxes (of the old editor).
Plugins relying on TinyMCE’s API because there’s no longer a single TinyMCE instance to talk to in Gutenberg.
Plugins making updates to their DOM on “submit” or on “save”.

So how do I interact with the correct TinyMCE instance . If I can work that out and we had some way of getting my existing meta box (which contains some input boxes, some javascript and a couple of DB calls) to render in a block without me having to re-code it all......

@mtias mtias removed the Needs Dev Ready for, and needs developer efforts label Jul 17, 2018
@tofumatt
Copy link
Member

In terms of not rewriting edit and save code: such a solution could be achieved by writing a function once and passing it to both the edit and save props of a block, eg:

const buttonEditAndSave = ( attributes ) => {
    <button className="button" style={ { backgroundColor: attributes.bgColor } }>
        { attributes.text }
    </button>
}

registerBlockType( 'myplugin/button', {
    title: __( 'Button' ),
    icon: 'button', 
    category: 'common',
    attributes: {
        text: {
            type: 'richtext',
        },
        bgColor: {
            type: 'color',
            label: __('Select color'),
            location: 'sidebar'
        }
    },
    edit: buttonEditAndSave,
    save: buttonEditAndSave,
}

If you wanted to add an example to https://wordpress.org/gutenberg/handbook/block-api/block-edit-save/ with a shared edit/save you could.


Revisiting this issue I think there's some legitimate frustration with the APIs and documentation, though much of it has evolved since this issue was last revisited. While there's some good feedback in here, there's not much that's actionable and the issue isn't very focused anymore, so I'm going to close it because I don't see the steps to "solve" it.

But the feedback has been heard, thanks! 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] Block API API that allows to express the block paradigm. [Feature] Extensibility The ability to extend blocks or the editing experience
Projects
None yet
Development

No branches or pull requests