Gatsby – WordPress: contact form

Gatsby – WordPress: contact form

This article covers one of the method how to create a contact form in Gatsby.js, getting the data from WordPress database through GraphQl.

You well need some skills of coding in JS, React, PHP, and some knowledge of WordPress functions.

The libraries which will be used here are:

  • React Apollo
  • Formik
  • Formik Semantic UI React
  • Yup

Let’s start from installing all above mentioned libraries.

In the terminal open the root folder of Gatsby instance and then

npm i react-apollo formik formik-semantic-ui-react yup

To get our form working we will have to program it in Gatsby and WordPress, as well. Let’s start from Gatsby part.

In root/src folder create new subfolder. Why don’t we name it “mutations”. Then we create new file. Too keep a logic in our naming convention, we name it ContactFormMutation.js.


import { gql } from '@apollo/client';

const CONTACT = gql`
    mutation CONTACT ($clientMutationId: String!, $name: String!, $phone: String!, $company: String!,  $email: String! $message: String!) {
        createContact(
            input: {
                clientMutationId: $clientMutationId,
                name: $name,
                phone: $phone,
                company: $company,
                email: $email,
                message: $message,
            }
        ) {
            success
            data
        }
    }
`;

export default CONTACT;

Now we can create contact form component. Too keep a logic in a file structure, let’s create a new folder “ContactForm” in root/components folder. Then, we need to create a new file there: ContactForm.js.

We will take advantage of React state, Yup validation, and Formik functionality.


import React from 'react';
import PropTypes from 'prop-types';
import { Mutation } from 'react-apollo';
import {
    Form, Input, SubmitButton, TextArea,
} from 'formik-semantic-ui-react';
import { Formik } from 'formik';
import * as Yup from 'yup';
import CONTACT from '../../mutations/ContactFormMutation';

const initialValues = {
    email: 'a@a.com',
};

const validationSchema = Yup.object({
    name: Yup.string().required(),
    email: Yup.string().email('Incorrect email address').required('Required'),
    phone: Yup.string().matches(new RegExp('[0-9]{7}'), 'Incorrect phone number').required('Required),
});

class ContactForm extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            formStatus: 'unsubmitted',
            email: '',
            name: '',
            company: '',
            phone: '',
            message: '',
            errorList: [],
        };
        this.handleInputChange = this.handleInputChange.bind(this);
    }

    handleInputChange(event) {
        const { target } = event;
        let value = '';
        let name = '';
        value = target.value;
        name = target.name;
        this.setState({
            [name]: value,
        });
    }

    form() {
        const formState = this.state;
        const emailState = formState.email;
        const nameState = formState.name;
        const phoneState = formState.phone;
        const messageState = formState.message;
        const companyState = formState.company;
        return (
            <div className="contact__form-container">
                <Mutation
                    mutation={CONTACT}
                    onCompleted={(response) => {
                        if (response.createContact.success === true) {
                            this.setState({ formStatus: 'submitted' });
                        } else {
                            this.setState({ formStatus: 'error' });
                            const errors = JSON.parse(response.createContact.data);
                            this.setState({ errorList: errors });
                        }
                    }}
                    onError={() => {
                        this.setState({ formStatus: 'error' });
                    }}
                >
                    {(addContact) => (
                        <Formik
                            initialValues={initialValues}
                            enableReinitialize
                            validationSchema={validationSchema}
                            onSubmit={(async_, { setSubmitting }) => {
                                setTimeout(() => {
                                    this.setState({ formStatus: 'loading' });
                                    addContact({
                                        variables: {
                                            clientMutationId: 'createContact',
                                            email: emailState,
                                            name: nameState,
                                            phone: phoneState,
                                            company: companyState,
                                            message: messageState,
                                        },
                                    });
                                    setSubmitting(false);
                                }, 1000);
                            }}
                        >
                            {({ isValid, dirty }) => (
                                <Form size={formSize}>
                                    <div className="row">
                                        <div className="col">
                                            <Input
                                                id="name"
                                                name="name"
                                                placeholder="Name"
                                                focus
                                                errorPrompt
                                                value={nameState}
                                                onChange={this.handleInputChange}
                                            />
                                        </div>
                                        <div className="col">
                                            <Input
                                                id="email"
                                                name="email"
                                                placeholder="Email"
                                                focus
                                                errorPrompt
                                                value={emailState}
                                                onChange={this.handleInputChange}
                                            />
                                        </div>
                                    </div>
                                    <div className="row">
                                        <div className="col">
                                            <Input
                                                id="phone"
                                                name="phone"
                                                placeholder="Phone"
                                                focus
                                                errorPrompt
                                                value={phoneState}
                                                onChange={this.handleInputChange}
                                            />
                                        </div>
                                        <div className="col">
                                            <Input
                                                id="Company"
                                                name="company"
                                                placeholder="Company"
                                                focus
                                                errorPrompt
                                                value={companyState}
                                                onChange={this.handleInputChange}
                                            />
                                        </div>
                                    </div>
                                    <div className="row">
                                        <div className="col">
                                            <TextArea
                                                id="message"
                                                name="message"
                                                placeholder="Message"
                                                focus={true.toString()}
                                                errorPrompt
                                                style={{ minHeight: 60 }}
                                                value={messageState}
                                                onChange={this.handleInputChange}
                                            />
                                        </div>
                                    </div>
                                    <div className="row">
                                        <div className="col" />
                                        <div className="col">
                                            <SubmitButton
                                                className="wc-button-submit"
                                                name="submit"
                                                type="submit"
                                                disabled={!(isValid && dirty)}
                                            >
                                                <span>Indienen</span>
                                            </SubmitButton>
                                        </div>
                                    </div>
                                </Form>
                            )}
                        </Formik>
                    )}
                </Mutation>
            </div>
        );
    }

    render() {
        const formState = this.state;
        const { errorList } = this.state;
        switch (formState.formStatus) {
        case 'submitted':
            return (
                <div className="form-alert alert-success">
                    Thank you for your Message.
                    <p>We will reply ASAP.</p>
                </div>
            );
        case 'loading':
            return <div className="form-alert alert-info">Please wait</div>;
        case 'error':
            return (
                <div className="form-alert alert-error">
                    An error has occurred.
                    {
                        errorList.map((error, index) => <p key={index}>{error}</p>)
                    }
                </div>
            );
        default:
            return this.form();
        }
    }
}
export default ContactForm;

Now our contact form component is ready, and we can import it to page component, footer component or wherever else we need.

It’s time to deal with WordPress part.

In functions.php file we need to register our contact form mutation:


<?php function create_contact_form_mutation() { register_graphql_mutation( 'createContact', array( 'description' => 'Custom mutation creating new contact form submission',
            'inputFields'         => array(
                'email'   => array(
                    'type'        => 'String',
                    'description' => 'User email',
                ),
                'name'    => array(
                    'type'        => 'String',
                    'description' => 'User name',
                ),
                'phone'   => array(
                    'type'        => 'String',
                    'description' => 'User phone',
                ),
                'company' => array(
                    'type'        => 'String',
                    'description' => 'User company',
                ),
                'message' => array(
                    'type'        => 'String',
                    'description' => 'User message',
                ),
            ),
            'outputFields'        => array(
                'success' => array(
                    'type'        => 'Boolean',
                    'description' => 'Whether or not data was stored successfully',
                    'resolve'     => function( $payload, $args, $context, $info ) {
                        return isset( $payload['success'] ) ? $payload['success'] : null;
                    },
                ),
                'data'    => array(
                    'type'        => 'String',
                    'description' => 'Payload of submitted fields',
                    'resolve'     => function( $payload, $args, $context, $info ) {
                        return isset( $payload['data'] ) ? $payload['data'] : null;
                    },
                ),
            ),
            'mutateAndGetPayload' => function( $input, $context, $info ) {

                $sanitized_data = array();
                $errors = array();
                $success_data = array();
                $acceptable_fields = array(
                    'name',
                    'email',
                    'phone',
                    'company',
                    'message',
                );

                foreach ( $acceptable_fields as $field_key ) {
                    if ( ! empty( $input[ $field_key ] ) ) {
                        $sanitized_data[ $field_key ] = sanitize_text_field( $input[ $field_key ] );
                    } else {
                        $errors[] = $field_key . ' was not filled out.';
                    }
                }
                
                // ... Here we code what we want to do with the data we got.
                // Either we want to send an email to admin,
                // or create new custom post and save a message to database.


                $output = '';

                if ( ! empty( $errors ) ) {
                    $output = array(
                        'success' => false,
                        'data'    => wp_json_encode( $errors ),
                    );
                } else {
                    $output = array(
                        'success' => true,
                        'data'    => wp_json_encode( $success_data ),
                    );
                }

                return $output;

            },
        )
    );

}

add_action( 'graphql_register_types', 'create_contact_form_mutation' );

And this is more less it. Our contact form is ready.

Happy Coding!