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

Feature suggestion: Form & input blocks #44186

Closed
aristath opened this issue Sep 15, 2022 · 24 comments · Fixed by #44214
Closed

Feature suggestion: Form & input blocks #44186

aristath opened this issue Sep 15, 2022 · 24 comments · Fixed by #44214
Labels
New Block Suggestion for a new block [Type] Discussion For issues that are high-level and not yet ready to implement.

Comments

@aristath
Copy link
Member

aristath commented Sep 15, 2022

What problem does this address?

Most sites need forms in one form or the other.
We already have the comment form, but that covers a very specific and limited scenario - leaving comments on a post.
This still leaves contact/feedback etc forms, and is one of the things that a huge number of sites needs.
Yes, there are plugins out there that do forms, but this is such a fundamental feature that we should have the building blocks for a form as part of Core.

What is your proposed solution?

I suggest creating 2 new blocks:

  1. A "Form" block. This will be the wrapper element for forms, adding the <form> element and allowing users to nest blocks inside it. It should have an area for inner blocks, and a submit button at the bottom
  2. An "Input" block. This block will only be visible/available when the parent block is a form block. In its most basic and initial implementation, it should have 2 attributes: type and label.

A simplified example of the generated HTML should look like this:

<form>
    <p>This is a paragraph block with <a href="https://example.com">a link etc</a>.</p>
    <label>
        This is the label for a field
        <input type="text">
    </label>
    <input type="submit" value="Submit">
</form>

The default action for the form should be to simply send an email to the site-admin.
We can have a PHP filter on the block's render callback to change the action - which will allow us to reuse the form for everything else we need (comment form, login block etc), as well as allow 3rd-party blocks & plugins to build forms in a unified and consistent way, and do what they need to do with the form's actions.

This will also help us abstract and improve existing blocks:

  • Comment form
  • Login form

Related: #21443, #30754

@aristath aristath added the [Type] Discussion For issues that are high-level and not yet ready to implement. label Sep 15, 2022
@Humanify-nl
Copy link

Humanify-nl commented Sep 15, 2022

Hi @aristath,

So much yes!

It is about time. Plug-ins should extend/improve forms, not supply them.

See here for some feedback I got from @talldan on the question if 'forms are going to be in core eventually". Maybe it helps to support this.

@mtias mtias added the New Block Suggestion for a new block label Sep 15, 2022
@mtias
Copy link
Member

mtias commented Sep 15, 2022

Related #34198

@courtneyr-dev
Copy link
Contributor

At the very basic level, a contact form would be ideal.

@noisysocks
Copy link
Member

noisysocks commented Sep 16, 2022

Absolutely! This is a big missing piece for me when I try to rebuild a real world website using the site editor. Most business websites (e.g. for a restaurant, a hotel, a tradesperson) require some call to action which is usually an enquiry form.

Right now there are half a dozen plugins which implement a Form block in different ways. This isn't great because:

  1. It creates inconsistent experiences. A site admin has to re-learn how to do forms every time they join a new WordPress site.
  2. It denies WordPress a significant platform opportunity. For example right now a developer that wanted to create an anti-spam plugin would right now have to support half a dozen different Form blocks.

Also, and apologies if this gets ranty and subjective, but I think most existing third party Form blocks do it wrong 😀.

The Input blocks and Submit blocks should be allowed to appear anywhere within the Form block, not just as an immediate child. For example you should be able to have your Input blocks nested within layout blocks such as Row. That lets users build forms that aren't a arranged as a traditional vertical stack. For example it's very common in real world websites that you would want a horizontal call to action form on the home page.

Screen Shot 2022-09-16 at 13 26 17

Lastly, most existing third party Form blocks simply email what the user submits to an email address provided by the site admin. Sometimes the user input ends up in a custom post type that appears in WP Admin somewhere. This is all very nice but it falls short of what I think is a huge opportunity which is to integrate with Web APIs. For example imagine being able to select an Airtable document, Google Sheets spreadsheet, or ITTT / Zapier workflow as the destination for where form submissions go. Suddenly a small restaurant or hotel could build a pretty intricate booking system without needing to pay for a programmer.

Core doesn't need to have everything (Calendar inputs, Zapier integrations, etc.) out of the box. Just the building blocks which allow platform multipliers to do their thing and for a rich form ecosystem to pop up.

@aristath
Copy link
Member Author

For example you should be able to have your Input blocks nested within layout blocks such as Row. That lets users build forms that aren't a arranged as a traditional vertical stack. For example it's very common in real world websites that you would want a horizontal call to action form on the home page.

I agree. That's why in the proposal above, the form block is a simple wrapper allowing to add innerBlocks. You could add rows, columns, basically any block - and therefore build the form you require.
The input block can (but is not required to) be nested inside the columns or any other layout block added.

In theory it's a simple concept, and I have started working on a proof of concept for these.

@aristath
Copy link
Member Author

I started experimenting a bit with this idea this morning.
I have a rough proof of concept on #44214 along with a short screencast of building a basic doctor's appointment form.
The POC in the draft PR is extremely basic and bad, but it demonstrates that it's possible to build this feature, it can be simple to use, and extremely valuable.

@Luehrsen
Copy link
Contributor

Luehrsen commented Sep 16, 2022

An "Input" block. This block will only be visible/available when the parent block is a form block. In its most basic and initial implementation, it should have 2 attributes: type and label.

For a later stage of the input blocks I would really like to see a similar approach like the embed block. For example surface a "textarea" block, that gracefully falls back on the input block. I think that makes the creation experience a bit more accessible for non technical users.

But all in all: Really amazing stuff! The thought of a unified forms system and a pluggable action-pipeline is a really great idea.

@aristath
Copy link
Member Author

aristath commented Sep 16, 2022

For a later stage of the input blocks I would really like to see a similar approach like the embed block. For example surface a "textarea" block, that gracefully falls back on the input block. I think that makes the creation experience a bit more accessible for non technical users.

Yes, that would make things easier 👍
These input blocks are only available inside the form block anyway, so they would not "pollute" the overall user-experience outside the context of a form block

@alexstandiford
Copy link

alexstandiford commented Sep 16, 2022

This is a really cool idea.

A couple considerations jump to mind:

  1. What about fieldsets? I wonder if those should be included, too. Might be something to add in a later revision instead of on V1
  2. What are your thoughts on how these forms can be extended? To ask another way, how could I tell WordPress to do something with the form submission? I'd imagine it would need to be able to run using PHP by default.

@aristath
Copy link
Member Author

Fieldsets could probably be explored at some point, but I don't think they'd belong in v1

As for doing stuff with the form, we could have a PHP filter in the render callback of the form, and we'd be able to handle submissions etc that way (already mentioned in the OP) 👍

@alexstandiford
Copy link

As for doing stuff with the form, we could have a PHP filter in the render callback of the form, and we'd be able to handle submissions etc that way (already mentioned in the OP) 👍

My bad 🤦‍♂️.

How would we identify the form for the hook? It's possible to have multiple forms on a single page, right? It's also possible to (intend to) have the same form across multiple pieces of content. In those cases, leaning on the post ID isn't enough.

@aristath
Copy link
Member Author

How would we identify the form for the hook?

I don't know yet... There would have to be some identifier for the forms, I didn't get that far in my proof of concept 😅
I'm sure we can find a solution though, there's plenty of things we can do!

@Humanify-nl
Copy link

How would we identify the form for the hook? It's possible to have multiple forms on a single page, right? It's also possible to (intend to) have the same form across multiple pieces of content. In those cases, leaning on the post ID isn't enough.

I think a unique ID for each form would be needed, and additionally:

Most form plugins ask user for a unique name (and slug), I suppose this could be added in the block (such as template-part name modal)

@alexstandiford
Copy link

I don't know yet... There would have to be some identifier for the forms, I didn't get that far in my proof of concept

No problem 😄. Just thinking through the challenges.

I can see the necessity of a form ID, but where would that be stored?

@aristath
Copy link
Member Author

I can see the necessity of a form ID, but where would that be stored?

Probably as an attribute in the form (wrapper) block 😉

@Luehrsen
Copy link
Contributor

Luehrsen commented Sep 16, 2022

A thought that just came to mind: Maybe we can turn the action-dependency on its head. Not the filter chooses its form, the form chooses its filter.

Imagine some sort of selection, dropdown, or similar, that describes the purpose of the form. The default is the "mail to admin" action. There is some sort of register, where core & plugins can add new actions. (Something like newsletter signup, or submit comment.)

These registered actions could then define a set of rules or requirements and mapping, that the form has to meet. (e.g. the newsletter needs exactly one email field.)

Edit: I see this action-registry concept as a chance for plugins like Gravity Forms to hook into the system, without abandoning its core functionality.

Edit 2: With a system like this, form-dependent vendors could (at least) provide three things:

  1. Actions that take form data and do something with it. (Think Newsletter signup or similar.)
  2. Complex form fields, that go beyond HTML standard. (e.g. Chosen Select, Calendars, etc.)
  3. Patterns to quickly create standard forms. (Again: Newsletter signups.)

The potential here is so amazing and vast: Typeform, Surveymonkey, everything is on the table...

@alexstandiford
Copy link

alexstandiford commented Sep 17, 2022

A thought that just came to mind: Maybe we can turn the action-dependency on its head. Not the filter chooses its form, the form chooses its filter.

Yes, I think this could work (great idea!). Something like a simple register_form_action function that includes a name, a slug, and a callback. The name, and slug can be used by the block editor for a select field, or something like that. Or, if the editor interface has something fancier, that information could be added to the registration.

I could see benefit in potentially taking this further than a select field, and maybe even making it possible to embed some JS to make it so that anyone can add configurations related to their action in the editor. Perhaps these settings would display when a form action is selected.

We'd probably want to make registering things like this run inside an action, so that the registration only happens when necessary. That action could be wrapped up in a function, get_form_actions, that would get the registered forms.

@draganescu
Copy link
Contributor

I want to express my support for this endeavour. Having forms is one of the most basic needs, even for brochure sites, and having to install a plugin for a basic contact form is not great in light of the 80% rule of how Core absorbs features :) To second @noisysocks I too think:

  • we need layout blocks for form building
  • we should allow forms to submit to various endpoints

I'd also build a core version of an auto generating CPT based on forms that are just for data collection, but that may be plugin territory if the form block's API is properly extensible.

@alexstandiford
Copy link

but that may be plugin territory if the form block's API is properly extensible.

I think this should be considered plugin territory. Building a post type for this would require that we also add an interface to view the data, and also require that we ensure the method in which the data is stored satisfies GDPR concerns. I think it adds a lot of complexity that, at least for version 1, should be skipped for now.

I'd suggest that WordPress comes with an email notification action, that automatically sends an email to the person who submitted the form and a list of pre-determined email addresses.

This would cover the majority of use-cases for a form, and is still complex enough that the change would require a fair amount of consideration to make it work well. All of these considerations can be added to make the base interface for the forms API extendable.

Also, WordPress directly supports this kind of action using wp_mail, and many plugins and hosts extend that functionality to make it more robust.

Just that feature causes me to ask many questions:

  • What does the email form action interface look like?
  • What happens if content in the settings needs to reference a field in the email? How can we reference those in the form submission content?
  • How can we register these form actions both in PHP and JavaScript?
  • How can someone register a custom form field? For example - maybe someone wants to make an upload file field.
  • What are the default styles for a form? What CSS classes can be embedded from the form data to help theme developers style effectively?
  • What about multiple columns in form layouts? Can the form block support things like the columns block or group block to help facilitate these things?
  • Can we make the form submit-able via PHP and optionally REST?

@jonathanbossenger
Copy link
Contributor

I'd like to add my voice to the "wholeheartedly agree" camp, but with one small caveat

The default action for the form should be to simply send an email to the site admin.

I'm sure we've all experienced having emails from a WordPress install being marked as spam. There's nothing I dread more than a client emailing to ask "is my contact form working, I've stopped receiving emails".

I'm sure many of us have dealt with either configuring a WordPress site to send emails via SMTP or setting up SPF, DKIM, and DMARC to ensure email deliverability, but for someone new to building sites with WordPress, this might not be obvious at first.

While many of the WordPress-managed hosts do have ways to tackle this, at the end of the day, sending an email via wp_mail still doesn't log anything anywhere.

I'd like to suggest therefore that this feature should also include some way of logging the emails sent so that the site admin can at least see the list of any emails sent.

@alexstandiford
Copy link

alexstandiford commented Sep 22, 2022

I'd like to suggest therefore that this feature should also include some way of logging the emails sent so that the site admin can at least see the list of any emails sent.

I think this is a good intentioned suggestion, but I fear it creates a fair bit of complexity (see my note about GDPR and storing the form data in my previous comment)

It also raises a curious precedent - is it WordPress' responsibility to ensure that an e-mail is sent successfully? I don't think it logs messages that fail to send in other contexts. I'm not sure this should be handled differently.

I don't disagree that there's value in the suggestion - in fact I think it would be awesome if WP was able to detect and somehow capture emails that don't send, I just don't think it makes sense for it to be built for this feature specifically, and instead should probably be captured higher up the stack.

@sc0ttkclark
Copy link

I'd love to see this!

@bhubbard
Copy link

I agree having blocks for forms is very much needed. I think sending an email as a default might be ok for a first example, but many sites want to handle form submissions differently. Examples:

  • Send an email to submitter
  • Send an email to site owner (or other wp users)
  • Trigger a webhook
  • Trigger a call to a third party API
  • Save it somewhere in the database
  • Create a Blog Post
  • Redirect to another page/url
  • Refresh the block and show new "thank you" content
  • Maybe pick and choose several of the options above
  • etc

Maybe the form data can just go into a custom table that acts like a simple "message queue" (Think Pub/Sub), and "events" can be configured for forms. From there each submission could be processed (maybe even re-processed) as needed. Maybe processing the queue can be a job for Action/Scheduler?

https://actionscheduler.org/

@aristath
Copy link
Member Author

aristath commented Aug 1, 2023

There is a PR in #44214, and it allows all of the above. Some of them are possible out of the box, and others will require writing some additional code - or using a 3rd-party plugin.
The implementation in Core should allow for common scenarios without getting too overwhelming. It should also provide a framework for plugins. Core should provide the things that simple forms require, and plugins can then add additional input-field types, as well as more possibilities for processing the form submissions via the provides hooks.

Send an email to submitter

This one is not implemented out of the box, but the implementation is bookable so 3rd-party plugins can easily implement it.

Send an email to site owner (or other wp users)

Implemented (set the method to email, and you'll be able to define an email address where the mail will be sent - or an array of comma-separated addresses. If left empty, defaults to the site admin.

Trigger a webhook

Trigger a call to a third party API

Setting the method to POST or GET, you can define a URL for the form's action. This allows a lot of freedom, and you can use 3rd-party APIs directly - or write some code to hook into the form submissions and add any headers etc that the webhooks may require.

Save it somewhere in the database

Create a Blog Post

Can easily be done via a plugin that will be implementing/extending the forms. A couple of months ago I wrote a proof-of-concept that saves the form submissions as a CPT. You can check that out here: https://gist.github.com/aristath/7f5ed7185a35e58c8ea65d1154b3d86d

Redirect to another page/url

Refresh the block and show new "thank you" content

These are all doable by hooking in the form actions & filters

Maybe the form data can just go into a custom table that acts like a simple "message queue" (Think Pub/Sub), and "events" can be configured for forms. From there each submission could be processed (maybe even re-processed) as needed. Maybe processing the queue can be a job for Action/Scheduler?

That would be beyond the basic forms scenarios, so I guess we could consider it plugin territory as well.

It's important to keep the Core implementation as simple as possible, otherwise we risk making unusable to all but the most advanced users. There's a lot of room for plugins to do whatever we need/want to do... 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
New Block Suggestion for a new block [Type] Discussion For issues that are high-level and not yet ready to implement.
Projects
None yet
Development

Successfully merging a pull request may close this issue.