-
Notifications
You must be signed in to change notification settings - Fork 797
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Contact Form: Add a Gutenberg based form builder
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
- Loading branch information
Showing
13 changed files
with
466 additions
and
120 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
# Contact Form - Gutenberg Blocks | ||
|
||
Contact form Gutenberg Blocks are implemented in JSX and currently depends on using Gutenberg's [5452](https://github.com/WordPress/gutenberg/pull/5452). | ||
|
||
Current form is more of a v0.1 library we can expand on to incorporate the original contact form logic. | ||
|
||
Development: | ||
|
||
* Run `gulp build` initially to create the blocks .js files after that you can run `gulp gutenpack` and `gulp gutenpack:watch` to continue development. | ||
* Set `define('SCRIPT_DEBUG', true)` and `Jetpack_Constants::set_constant('SCRIPT_DEBUG', true)` somewhere to use your local blocks built with gutenpack. | ||
|
||
Blocks Available: | ||
|
||
* 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 | ||
|
||
Current state: | ||
|
||
* InnerBlock templating requires [5452](https://github.com/WordPress/gutenberg/pull/5452) | ||
* Needs a solution to filtering blocks in the inserter so we can prevent showing form blocks in non form context. Talks of this in [5452](https://github.com/WordPress/gutenberg/pull/5452). | ||
* allowedBlocks solution in [5452](https://github.com/WordPress/gutenberg/pull/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 | ||
* 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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
const { | ||
registerBlockType, | ||
InspectorControls, | ||
InnerBlocks, | ||
} = wp.blocks; | ||
|
||
const { createElement } = wp.element; | ||
const { ToggleControl, TextControl, ButtonGroup, Button, RadioControl } = wp.components; | ||
|
||
const { __ } = wp.i18n; | ||
|
||
const inputName = (str) => str.toLowerCase().replace(/[^a-z0-9]/, ''); | ||
|
||
// Define the form block | ||
let FormButton = { | ||
title : __( 'Form - Submit' ), | ||
icon : 'button', | ||
category : 'common', | ||
description: __( 'A submit button' ), | ||
keywords: [ | ||
__( 'send' ), | ||
__( 'submit' ), | ||
__( 'contact' ), | ||
], | ||
useOnce: true, | ||
// isPrivate: true, | ||
attributes: { | ||
label: { | ||
type: 'string', | ||
default: 'Submit', | ||
} | ||
}, | ||
|
||
save: ( { attributes, className } ) => { | ||
return <div className={ className }> | ||
<Button isPrimary={ true } type={ "submit" }> | ||
{ attributes.label } | ||
</Button> | ||
</div> | ||
}, | ||
edit: ( { attributes, setAttributes, className, isSelected } ) => { | ||
if ( ! isSelected ) { | ||
return <div className={ className }> | ||
<Button isPrimary={ true } type={ "submit" }> | ||
{ attributes.label } | ||
</Button> | ||
</div> | ||
} | ||
|
||
return [ | ||
<TextControl | ||
label={ __( 'Button Text' ) } | ||
placeholder={ __( 'Submit' ) } | ||
value={ attributes.label } | ||
onChange={ value => setAttributes( { 'label': value } ) } | ||
/> | ||
]; | ||
}, | ||
}; | ||
|
||
// Register the form block under jetpack/form | ||
registerBlockType( 'jetpack/form-button', FormButton ); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
.wp-block-jetpack-form-button {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
const { | ||
registerBlockType, | ||
InspectorControls, | ||
InnerBlocks, | ||
} = wp.blocks; | ||
|
||
const { createElement } = wp.element; | ||
const { CheckboxControl, TextControl } = wp.components; | ||
|
||
const { __ } = wp.i18n; | ||
|
||
// Define the form block | ||
let Form = { | ||
title: __( 'Form' ), | ||
icon: 'feedback', | ||
category: 'common', | ||
description: __( 'Contact Form Settings' ), | ||
keywords: [ | ||
__( 'form' ), | ||
__( 'contact' ), | ||
], | ||
useOnce: true, | ||
attributes: { | ||
subject: { | ||
type: 'string', | ||
default: 'Feedback', | ||
}, | ||
|
||
to: { | ||
type: 'string', | ||
default: '' | ||
} | ||
}, | ||
|
||
save: ( { attributes, className } ) => { | ||
return <div className={ className }> | ||
<form> | ||
<InnerBlocks.Content /> | ||
</form> | ||
</div> | ||
}, | ||
|
||
edit: ( { attributes, setAttributes, className, isSelected } ) => { | ||
return [ | ||
// Display the inner blocks | ||
<InnerBlocks | ||
template={[ | ||
[ 'jetpack/form-text', { | ||
'label': __( 'Name' ), | ||
'placeholder': __( 'Full Name' ), | ||
'required': true, | ||
} ], | ||
[ 'jetpack/form-text', { | ||
'label': __( 'Email' ), | ||
'placeholder': __( 'example@example.com' ), | ||
'required': true, | ||
} ], | ||
[ 'jetpack/form-textarea', { | ||
'label': __( 'Message' ), | ||
'placeholder': __( 'Enter message' ), | ||
'required': true, | ||
} ], | ||
[ 'jetpack/form-button', { 'label': __( 'Send' ) } ] | ||
]} | ||
allowedBlocks={ [ | ||
'jetpack/form-text', | ||
'jetpack/form-textarea', | ||
'jetpack/form-button' | ||
] } | ||
/>, | ||
|
||
// Display on Focus | ||
!! isSelected && | ||
<InspectorControls key="inspector"> | ||
<TextControl | ||
label={ __( 'Email Subject' ) } | ||
help={ __( 'What would you like the subject line of the email to be?' ) } | ||
placeholder={ __( '[Site Feedback]' ) } | ||
value={ attributes.subject } | ||
onChange={ value => setAttributes( { 'subject': value } ) } | ||
/> | ||
<TextControl | ||
label={ __( 'Email Address' ) } | ||
help={ __( 'Which email address should we send the submissions to?' ) } | ||
value={ attributes.to } | ||
placeholder={ __( 'admin@example.com' ) } | ||
onChange={ value => setAttributes( { 'to': value } ) } | ||
/> | ||
</InspectorControls> | ||
]; | ||
}, | ||
}; | ||
|
||
// Register the form block under jetpack/form | ||
registerBlockType( 'jetpack/form', Form ); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
.wp-block-jetpack-form {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
const { | ||
registerBlockType, | ||
InspectorControls, | ||
InnerBlocks, | ||
} = wp.blocks; | ||
|
||
const { createElement } = wp.element; | ||
const { ToggleControl, TextControl, BaseControl } = wp.components; | ||
|
||
const { __ } = wp.i18n; | ||
|
||
const inputName = ( str ) => str.toLowerCase().replace(/[^a-z0-9]/, ''); | ||
|
||
// Define the form block | ||
let FormText = { | ||
title : __( 'Form - Text' ), | ||
icon : 'editor-textcolor', | ||
category : 'common', | ||
description: __( 'Text field' ), | ||
keywords: [ | ||
__( 'text' ), | ||
__( 'name' ), | ||
__( 'email' ), | ||
], | ||
// isPrivate: true, | ||
attributes: { | ||
// Set label to display above the input | ||
label: { | ||
type: 'string', | ||
default: 'Custom Text', | ||
}, | ||
|
||
// Inspector: set placeholder value for the input | ||
placeholder: { | ||
type: 'string', | ||
default: '', | ||
}, | ||
|
||
// Inspector: determine if input is required or optional | ||
isRequired : { | ||
type : 'boolean', | ||
default : true, | ||
}, | ||
}, | ||
|
||
save: ( { attributes, className } ) => { | ||
// todo: replace with uuid4 + saved as attribute? | ||
// 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 }> | ||
<input className={ `${className} components-text-control__input` } | ||
type="text" | ||
id={ id } | ||
name={ inputName( attributes.label ) } | ||
placeholder={ attributes.placeholder } | ||
|
||
/> | ||
</BaseControl> | ||
}, | ||
|
||
edit: ( { attributes, setAttributes, className, isSelected } ) => { | ||
if ( ! isSelected ) { | ||
return FormText.save( { attributes: attributes, className: className } ) | ||
} | ||
|
||
return [ | ||
<TextControl | ||
label={ attributes.label } | ||
value={ attributes.label } | ||
placeholder={ __( 'e.g. Name' ) } | ||
onChange= { value => setAttributes ( { 'label': value } ) } | ||
required={ true } | ||
/>, | ||
<InspectorControls key="inspector"> | ||
<TextControl | ||
label={ __( 'Placeholder Text' ) } | ||
help={ __( 'Text shown when field is empty.' ) } | ||
placeholder={ __( 'Placeholder' ) } | ||
value={ attributes.placeholder } | ||
onChange={ value => setAttributes( { 'placeholder': value } ) } | ||
/> | ||
<ToggleControl | ||
label={ __( 'Is required?' ) } | ||
help={ ( checked ) => checked ? __( 'Field must be filled out.' ) : __( 'Field is optional.' ) } | ||
checked={ !! attributes.isRequired } | ||
onChange={ value => setAttributes( { 'isRequired': value } ) } | ||
/> | ||
</InspectorControls> | ||
]; | ||
}, | ||
}; | ||
|
||
// Register the form block under jetpack/form | ||
registerBlockType( 'jetpack/form-text', FormText ); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
.wp-block-jetpack-form-text {} |
Oops, something went wrong.