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

Contact form: add additional fields such as telephone #207

Open
bobbingwide opened this issue Aug 27, 2022 · 25 comments
Open

Contact form: add additional fields such as telephone #207

bobbingwide opened this issue Aug 27, 2022 · 25 comments
Assignees

Comments

@bobbingwide
Copy link
Owner

bobbingwide commented Aug 27, 2022

The Divi contact form, and many other contact forms, support multiple fields such as Telephone number.
I don't need a complex solution but it would be nice to include telephone as an additional field for the oik contact form block / shortcode.

Requirements

  • Add Telephone field as an optional field
  • Include the value submitted in emails

Proposed solution

  • Add a fields parameter which accepts the fields to be displayed.
  • Default value: name,email,subject,text
  • Allow the fields to be in any order
  • Support a field name of telephone ( oiku_telephone )
  • Include all the chosen fields in the email that's sent.
  • Improve the oik/contact-form block accordingly
@bobbingwide bobbingwide self-assigned this Sep 1, 2022
@bobbingwide
Copy link
Owner Author

bobbingwide commented Sep 1, 2022

A slightly more advanced solution would be to allow the contact form shortcode to include embedded content, with nested shortcodes that define the fields to be included on the form.

[bw_contact_form]
[bw_contact_field name=_telephone label="Telephone" type=telephone required=y]
[/bw_contact_form]

This is similar to the solution offered by Jetpack's Grunion contact form.
It's different from Contact Form 7, in which the content is loaded from a Contact form CPT and doesn't use shortcodes, although they look like them.

The [bw_contact_field shortcode] could be similar to the [bw_field] shortcode. It may use the same functions.

It should also be possible to implement the bw_contact_field shortcode as a block.

@bobbingwide
Copy link
Owner Author

Notes about other forms plugins

wpforms-lite stores the forms in a CPT called wpforms in JSON format
ninja-forms are stored in custom tables prefixed nf3 ( eg where WordPress prefix is wp_: wp_nf3_forms and wp_nf3_form_meta )
nf3_form_meta columns include label, key & type eg values: Name, name, textbox.

@bobbingwide
Copy link
Owner Author

Note: oik-user has some disabled logic that's similar to oik's contact form.

@bobbingwide
Copy link
Owner Author

bobbingwide commented Sep 5, 2022

At present the oik/contact-form block block isn't producing any field values for the fields in the form.

@bobbingwide
Copy link
Owner Author

bobbingwide commented Sep 6, 2022

At present the oik/contact-form block block isn't producing any field values for the fields in the form.

This was because the [bw_contact_field] shortcode wasn't registered when using the block. When re-implementing the Contact form block with embedded Contact field blocks it may make sense to rework the logic generates and expands [bw_contact_field] shortcodes into direct calls to the implementing logic.

The downside of this is that the code will become less extensible since there'll be fewer action hooks invoked.

@bobbingwide
Copy link
Owner Author

bobbingwide commented Sep 6, 2022

Rather than having a fields attribute on the [bw_contact_form] shortcode I've implemented the solution to use the embedded [bw_contact_field] shortcode.

  • The default fields are: name,email,subject, and message ( not text ).
  • At present Message is a required field and is added to the form if not already specified.

Since the logic uses bw_form_field() to display the fields in the form, the [bw_contact_field] shortcode supports the following field types. The field type can be determined from the field name, which is determined from the field's Label.

Field type Field name Notes
text name, subject and any other field not specifically catered for
email email
telephone telephone
textarea message, text

The syntax for the bw_contact_field shortcode allows positional parameters

Position Attribute Default
0 label field
1 type Determined from the name.
2 name Determined from the label.
n/a value null
n/a placeholder null
n/a required y if the label contains an asterisk ( '*' )

Examples

[bw_contact_field "Name *"]

produces a required text field labelled Name *

[bw_contact_field Telephone]

produces a tel field labelled Telephone

Note: bw_form_field doesn't yet support <input type="tel"

@bobbingwide
Copy link
Owner Author

Having achieved a reasonable level of success with the shortcode solution I now want to implement the oik/contact-form as a block that supports embedded blocks of the type oik/contact-field.

  • The oik/contact-field will only be insertable into the oik/contact-form.
  • It may support several variations such as Name, Email, Subject and Message
  • When the Contact Form block doesn't contain nested blocks then it will behave the same as the [bw_contact_form].

@bobbingwide
Copy link
Owner Author

bobbingwide commented Sep 6, 2022

The challenge here would be to find out how to implement InnerBlocks and ServerSideRendering at the same time.

It appears other people have already tried this, quite a while ago.
In WordPress/gutenberg#10478 Fabienkaegy wrote

There is no way to pass the InnerBlocks html string to the block renderer Rest endpoint. Which is something that I believe would be very useful.

I suppose I'll have to look at how Jetpack's Contact form blocks work. I assume that there's no Server Side Rendering.

@bobbingwide
Copy link
Owner Author

bobbingwide commented Sep 7, 2022

I suppose I'll have to look at how Jetpack's Contact form blocks work.

Rather than use Server Side Rendering I'm going to emulate the form in the block editor.

I'm making some progress. The blocks are much faster than when using Server Side Rendering.

image

Notes:

  • It's OK in the editor, but I need to determine how to render the inner blocks for the front end.
  • I haven't yet implemented the different field types: Text, Email and Textarea
  • or field length
  • or required toggle.
  • And the method Jetpack uses for editing the Label is quite nice as well.

Actually, in the Editor the <table> tag is outwith a <div>. Not sure what to do about that.

@bobbingwide
Copy link
Owner Author

bobbingwide commented Sep 10, 2022

Actually, in the Editor the <table> tag is outwith a <div>. Not sure what to do about that.

In order to display the Contact form nicely in the block editor I had to replace the table formatting method with grid styling.

For the front end this meant changing the form field logic that calls bw_tablerow() to use a new function bw_gridrow().
It also entailed changing the logic to produce the outer table to a div that'll have the CSS grid styling.

The default contact form is now expected to be a <div class="bw_grid">.
It falls back to a <table/> when the bobbforms shared library version is lower than 3.4.0

The PHPUnit tests for the contact form will now default to the grid format.

Because this change produces different HTML from before the oik version should be changed to v4.9.0
I don't think it's necessary to make it v5.0.0

@bobbingwide
Copy link
Owner Author

Now that I've developed the form to be styled as a grid I can try to introduce a checkbox field that gets a user to confirm they understand how the data they submit might be used.

bobbingwide added a commit that referenced this issue Sep 11, 2022
bobbingwide added a commit that referenced this issue Sep 11, 2022
bobbingwide added a commit that referenced this issue Sep 11, 2022
@bobbingwide
Copy link
Owner Author

bobbingwide commented Sep 11, 2022

I've added the checkbox and written logic to ensure required fields are completed. It's now possible to remove the requirement for the Message field. It can either be present but not required or not even present.
This means you can give it a different label, such as Text.
The slight downside of this is that it won't be passed to Akismet for spam checking.

@bobbingwide
Copy link
Owner Author

The slight downside of this is that it won't be passed to Akismet for spam checking.

This could be resolved by adding some logic to retrieve any textarea field as the message to be passed to Akismet.

@bobbingwide
Copy link
Owner Author

Additional requirements

  • Contact form - Allow definition of email recipient - consider copying logic from oik-user
  • Contact form - check why oiku_email is revealed to the front end
  • Contact field - Need to be able to show the syntax for the [bw_contact_field] shortcode
  • Contact field - consider swapping input field and label for checkbox.

@bobbingwide
Copy link
Owner Author

Contact field - consider swapping input field and label for checkbox.

.bw_contact_form .bw_grid {
    display: grid;
    gap: 10px;
    grid-template-columns: 1fr 3fr;
}

The above styling for the bw_grid class, attached to the div inside the form,is automatically enqueued for the oik/contact-form block but not for the [bw_contact_form] shortcode.

@bobbingwide
Copy link
Owner Author

Contact form - check why oiku_email is revealed to the front end

This was done a long time ago prior to oik v2.3.
I believe the code can be adjusted so that the hidden field isn't required.

@bobbingwide
Copy link
Owner Author

Contact field - Need to be able to show the syntax for the [bw_contact_field] shortcode

I've implemented support for Help and Syntax and generated the shortcode in oik-plugins. There was a problem with the example due to a missing function. Fixed by loading shortcodes/oik-contact-form.php at the start of bw_contact_field()

@bobbingwide
Copy link
Owner Author

bobbingwide commented Sep 13, 2022

Contact form - Allow definition of email recipient - consider copying logic from oik-user

image

I've started adding some logic to set the default values for the email and contact attributes.
Challenges are:

  • setting the defaults has to be done during block registration.
  • when the user blanks out an attribute it should be unset - reverting to the default

Blanking attributes

When the user blanks out an attribute it should be unset - reverting to the default
eg

<!-- wp:oik/contact-form -->

rather than empty strings.

<!-- wp:oik/contact-form {"contact":"","email":""} -->

This can be achieved by the following code.

/**
  * Reset fields to defaults if they're blanked out by the user.
  */
const { email, contact } = attributes;
if ( email=== undefined || email.trim() === '') {
   const attributeSettings = wp.data.select('core/blocks').getBlockType('oik/contact-form').attributes;
   props.setAttributes({email: attributeSettings.email.default});
}
if ( contact===undefined || contact.trim() === '' ) {
    const attributeSettings = wp.data.select('core/blocks').getBlockType('oik/contact-form').attributes;
    props.setAttributes({contact: attributeSettings.contact.default});
}

The logic should attempt to cater for the oik-user plugin, which obtains the user's email and name from the author of the current post. In the [bw_contact_form] shortcode this can be specified by the user= parameter

@bobbingwide
Copy link
Owner Author

Setting defaults

Notes about the original implementation for the [bw_contact_form] shortcode.

  • When oik-user is active the [bw_contact_form] shortcode supports a user= parameter
  • This can be used to override the default user, which is otherwise obtained from the post_author of the current post.
  • When oik-user is not active the values are obtained from oik options
  • The [bw_contact_form] shortcode supports an alt= parameter ( value =0,1,2 ) with alt=0 being the default.
  • See bw_get_option_arr() for the code and documentation.

Setting the defaults for the oik/contact-form block has to be done during block registration.

  • by hooking into the block_type_metadata filter we change the values defined in block.json
  • For the oik/contact-form block we can set default values for email and contact.
  • This only needs to be done when the block may be used in the editor.
  • Block registration occurs before the post is loaded
  • We can't use the same logic as for the shortcode since this relied on $GLOBALS['post'] being set.
  • In its place I've written oik_maybe_get_current_post_author()
  • If it returns a user ID then the user's email and display_name fields are returned
  • Otherwise, the default values are obtained from bw_options, using the original functions.

The code needs to be tested when the block is used in the Site and Template editor.

function oik_maybe_get_current_post_author() {
    $id = null;
    if ( function_exists( 'oiku_loaded')) {
        $post = bw_array_get($_REQUEST, "post", null);
        $action = bw_array_get($_REQUEST, "action", null);
        if ('edit' === $action && $post) {
            $post = get_post($post);
            bw_trace2($post);
            if ($post) {
                $id = $post->post_author;
            }
        }
    }
    return $id;
}

@bobbingwide
Copy link
Owner Author

bobbingwide commented Sep 13, 2022

Contact field - consider swapping input field and label for checkbox.

Q. Can this be implemented using block styles for the Contact field?
See #207 (comment)

A. Yes. I've implemented 3 different styles.
Now I'm wondering what other CSS and/or HTML tags I need for the front end styling to appear consistent.
image

@bobbingwide
Copy link
Owner Author

Testing with WordPress 6.2-RC2 in the Site Editor's new Style Book the contact form encounters an error.

Uncaught TypeError: Cannot read properties of null (reading 'trim')
    at edit (contact-form.js?ver=07594a43391158a7810b:1:928)
    at renderWithHooks (react-dom.js?ver=18.2.0:16315:20)
    at mountIndeterminateComponent (react-dom.js?ver=18.2.0:20084:15)
    at beginWork (react-dom.js?ver=18.2.0:21597:18)
    at HTMLUnknownElement.callCallback (react-dom.js?ver=18.2.0:4151:16)
    at Object.invokeGuardedCallbackDev (react-dom.js?ver=18.2.0:4200:18)
    at invokeGuardedCallback (react-dom.js?ver=18.2.0:4264:33)
    at beginWork$1 (react-dom.js?ver=18.2.0:27461:9)
    at performUnitOfWork (react-dom.js?ver=18.2.0:26567:14)
    at workLoopSync (react-dom.js?ver=18.2.0:26476:7)

@bobbingwide
Copy link
Owner Author

bobbingwide commented Aug 5, 2023

Currently getting strange styling of the Fields metabox in
https://s.b/oikcom/wp-admin/post.php?post=48491&action=edit

image

The problem occurs after the post is saved with the contact form and then re-edited.

The contact form is.

<!-- wp:oik/contact-form -->
<div><!-- wp:oik/contact-field {"label":"Name","required":true,"requiredIndicator":" *"} /-->

<!-- wp:oik/contact-field {"label":"Name left","required":true,"requiredIndicator":" *","className":"is-style-grid"} /-->

<!-- wp:oik/contact-field {"label":"Subject","required":false} /-->

<!-- wp:oik/contact-field {"label":"Message","type":"textarea","required":true,"requiredIndicator":" *"} /--></div>
<!-- /wp:oik/contact-form -->

@bobbingwide
Copy link
Owner Author

bobbingwide commented Aug 5, 2023

Currently getting strange styling of the Fields metabox

When the editor contains the Contact Form block the Fields metabox is not displayed as a table but as a serie of divs.
bw_is_table( true) needs to be called after the contact form's been run.

@bobbingwide
Copy link
Owner Author

The Message field is not redisplayed in the event of a form validation error.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant