-
Notifications
You must be signed in to change notification settings - Fork 797
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
Contact Form: Add Gutenberg based form builder blocks #9452
Conversation
At this point it just represents the parent form -- it doesn't handle any fields yet. That will largely depend on how WordPress/gutenberg#3745 progresses.
Adds a set of Gutenberg "Form" blocks for use with the contact form module. Blocks: * Form - The main block, consists of an InnerBlock for the <form> element and a set template consisting of a default set of inner blocks preconfigured as a contact form * Text - General <input type=text>/<textarea> field with configurable label, rows * Button - A <button type=submit> with configurable button text Blocking Release: * InnerBlock templating requires WordPress/gutenberg#5452. * WordPress/gutenberg#5452 needs to override isPrivate settings to prevent form blocks being seen in the inserter when out of form context. * WordPress/gutenberg#5452 is whitelist only meaning we cant add extra blocks in between form elements - not really a huge issue for this but likely an issue for other use cases. Todo - Integration with grunion-contact-form: * Captcha support should be relatively easy to achieve with a serverside rendered block * A server side filter / hook could replace the form action Todo - Handle duplicate field names gracefully * Currently uses a variation on the label / field name to set id / for settings on label / inputs. * Currently uses same variation for <input name=""> attributes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall, I really like the approach you're taking here by using InnerBlocks
. Nice work.
I left a few mostly minor comments. Note that many of them (e.g. missing key
props, missing localisation) apply to all four JSX files added in this PR.
I'd like to see the contact form functionality itself implemented, e.g. one should be able to send an email by submitting the form on the frontend. Once that works we'll be in a good position to refine this PR into something shippable.
const inputName = (str) => str.toLowerCase().replace(/[^a-z0-9]/, ''); | ||
|
||
// Define the form block | ||
let FormButton = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should communicate that we don't intend for this variable's value to change by declaring it const
.
|
||
save: ( { attributes, className } ) => { | ||
return <div className={ className }> | ||
<Button isPrimary={ true } type={ "submit" }> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can shorten this to:
<Button isPrimary type="submit">
https://reactjs.org/docs/jsx-in-depth.html#string-literals
https://reactjs.org/docs/jsx-in-depth.html#props-default-to-true
} | ||
|
||
return [ | ||
<TextControl |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We'll need to specify a key
prop on the <TextControl>
since it is contained within a list.
Better yet, we could just omit the list altogether:
return (
<TextControl
...
/>
);
}, | ||
edit: ( { attributes, setAttributes, className, isSelected } ) => { | ||
if ( ! isSelected ) { | ||
return <div className={ className }> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JSX is easier to read, I think, when opening and closing tags align. We can do this by wrapping multiline JSX with parentheses.
if ( ! isSelected ) {
return (
<div className={ className }>
...
</div>
);
}
@@ -0,0 +1 @@ | |||
.wp-block-jetpack-form-button {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are these files necessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, development artifacts to remove.
/>, | ||
|
||
// Display on Focus | ||
!! isSelected && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can remove this check. WordPress/gutenberg#5029 made <InspectorControls>
check for isSelected
automatically.
// The id needs to be unique for for="" but also needs to be saved for block validation | ||
const id = 'jetpack-form-text-input-' + inputName( attributes.label ); | ||
|
||
return <BaseControl label={ attributes.label } id={ id }> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think using <BaseControl>
in save()
is a good idea. If, down the track, we modify the markup within BaseControl
, Gutenberg will be unable to parse existing jetpack/form-text
blocks.
I recommend instead that we manually render the necessary <label>
markup here.
|
||
edit: ( { attributes, setAttributes, className, isSelected } ) => { | ||
if ( ! isSelected ) { | ||
return FormText.save( { attributes: attributes, className: className } ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Clever! I think it would be clearer, though, if we split this out into its own component that both save()
and edit()
use.
function FormTextInput( { attributes, className } ) {
return ...;
}
const FormText = {
save( { attributes, className } ) {
return <FormTextInput attributes={ attributes } className={ className } />;
},
edit( { attributes, setAttributes, className, isSelected } ) {
if ( ! isSelected ) {
return <FormTextInput attributes={ attributes } className={ className } />;
}
},
...
};
} | ||
|
||
return [ | ||
<TextControl |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is missing a key
prop. Alternatively, we could use Fragment
(exposed as wp.element.Fragment
) instead of a list.
|
||
if ( "form" == $name ) { | ||
$namespace = "jetpack/form"; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's some mixed indentation going on here.
I think this needs a rebase before I can test it. There was a bug introduced to Jetpack that bricks the admin screen for me. |
JETPACK__VERSION | ||
); | ||
|
||
register_block_type( $type, array( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
$type
is undefined here.
To check this PR (which comes from a fork of the Jetpack repo) when working on a local clone of the Automattic/Jetpack repo:
Make sure Gutenberg is installed and Jetpack is connected. |
@lsl could you create a version of this branch but on this same repo instead of being a branch on a fork ? |
Context: #9452 @oskosk Requested this unfinished branch to be pushed up to Automattic/jetpack for use in the Jetpck Beta Tester Plugin. -- Adds a set of Gutenberg "Form" blocks for use with the contact form module. Blocks: * Form - The main block, consists of an InnerBlock for the <form> element and a set template consisting of a default set of inner blocks preconfigured as a contact form * Text - General <input type=text>/<textarea> field with configurable label, rows * Button - A <button type=submit> with configurable button text Blocking Release: * Fix issues identified in original PR #9452 * InnerBlock templating requires WordPress/gutenberg#5452. * WordPress/gutenberg#5452 needs to override isPrivate settings to prevent form blocks being seen in the inserter when out of form context. * WordPress/gutenberg#5452 is whitelist only meaning we cant add extra blocks in between form elements - not really a huge issue for this but likely an issue for other use cases. Todo - Integration with grunion-contact-form: * Captcha support should be relatively easy to achieve with a serverside rendered block * A server side filter / hook could replace the form action Todo - Handle duplicate field names gracefully * Currently uses a variation on the label / field name to set id / for settings on label / inputs. * Currently uses same variation for <input name=""> attributes
Thank you @lsl ! |
Status: In Progress
Adding a Gutenberg form builder to Jetpack for use in the contact form module.
There are a couple of issues blocking any kind of usable solution being completed, outlined further below.
Changes proposed in this Pull Request:
Testing instructions:
Proposed changelog entry for your changes:
Further info:
Blocks:
<form>
element and a set template consisting of a default set of inner blocks
preconfigured as a contact form
<input type=text>/<textarea>
field with configurablelabel, rows
<button type=submit>
with configurable button textBlocking Release:
Todo - Integration with grunion-contact-form:
rendered block
Todo - Handle duplicate field names gracefully:
id / for settings on label / inputs.
<input name="">
attributesHow it looks: