Creating a WordPress Contact Form – Complete Guide

On March 18, 2024
14min read
Veljko Ristić Content Manager @ Mailtrap
This is a symbolic graphic representation of WordPress contact forms for an article that covers the topic in detail.

I’ll make you an offer you can’t refuse. 🐈

I’ll tell you how to create a WordPress contact form, covering every imaginable detail, and making sure you won’t be reading only code and industry jargon. 

So, this article is suitable for beginners and those who already have some experience and wish to get the most from a basic contact form in terms of security and user experience. 

Now, get your fingers cracking and let’s start.  

How to create a contact form in WordPress with a plugin?

The contact form plugin method is the simplest and fastest. Though there are some security limitations and plugins aren’t as flexible as coding stuff yourself. 

Here I’ll use WPForms (the WPForms Lite – free version) as it’s most reliable and straightforward. Another honourable option to consider is Ninja Forms. 

Whichever plugin you choose, it might be worth considering installing auxiliary add-ons like Jetpack for advanced spam control and security. I won’t be going into details of that here, since I cover security, validation, and sanitization the fun way – I tell you how to code it yourself. 😀

Here goes the step-by-step tut to install and use arguably the best WordPress contact form plugin. 

Step 1: Install and Activate the WPForms Plugin

Go to the sidebar WordPress admin panel. Then, navigate to Plugins > Add New, look for “WPForms“.

WPForms in WordPress dashboard

Now, click on the grey Install Now button next to the plugin called Contact Form by WPForms.

The last thing to do is activate the plugin. 

WPforms activate the plugin

Step 2: Create a New Contact Form

After activating WPForms, navigate to WPForms > All Forms in the WordPress dashboard. Then, click the Add New button to open the WPForms drag-and-drop form builder.

WPForms add a new form

In the form builder plugin, give your contact form a name, then select the contact form template. WPForms Lite comes with a few free form templates. 

For simplicity, I selected the Simple Contact Form template; it’ll automatically add the Name, Email, and Message fields. But if you’re a small business or ecommerce, the RFQ, Billing, or newsletter signup forms would also work. 

WPForms Simple Contact Form template

Step 3: Customize your form

Click on a form field to bring up a Field Options panel on the left to make changes to the field label or other form settings. You can also use your mouse to drag and drop the fields to change the order. 

WPForms customizing the contact form

Here, I’m doing a user-friendly Contact Us form without fancy fields. You can create any other type of registration form and align it with your WordPress themes if necessary. 

Pro Tip: Don’t go overboard with the fields as it’ll affect form submissions. 3 to 5 fields is usually more than enough. 

Step 4: Save your form

Once you’re done customizing your form, make sure to click the Save button.

New form save the form

Step 5: How to add a contact form to a Page

You can add it to an existing contact page or create a new page in WordPress. To create a new contact form page, go to Pages > Add New and give your page a name.

Use the WPForms block to add the form to the page.

Click the Plus add block button and search for WPForms. Select the simple form you created earlier from the drop-down menu. WPForms will load the contact form preview inside the editor. 

Adding a contact form to a page

Finally, click Publish or Update to save your form.

Step 6: Using WordPress plugin shortcodes

WPForms comes with a WordPress contact form shortcode. You can use it by visiting WPForms > All Forms and then copying the shortcode next to your form. 

Wordpress plugin form shortcodes

Open the page builder where you want to add the shortcode, click the Plus add block button, and search for “Shortcode”. 

Paste the shortcode that you copied above into the box, then click Update or Publish

Bonus tip:

Now, there’s also an option to step things up a notch and use platform like Divi.

It’s a fresh website-building experience, replacing the standard WordPress post editor with an intuitive visual editor that allows you to see changes in real time.

You don’t need to be a coding guru; even total beginners can quickly grasp its user-friendly interface.

With Divi, you can design:

Sophisticated layouts that follow your website’s unique aesthetic and functional needs.

Any type of form or page, ensuring your contact forms align seamlessly with your online presence.

What I like the most is the platform’s flexibility, and the creative freedom you get without the need to jump into the backend.

Divi natively integrates with WP Forms allowing you to add the forms you create with WP Forms onto your pages. To do so, simply enable the Divi builder, and select the WP Forms Divi module:

How to create a simple contact form in WordPress without a plugin?

Here, I’ll tell you how to create more advanced forms without any plugins. With that, you’ll have more control over the email notifications from the form itself. 

Note: This is one of WordPress tutorials that assumes you have basic coding skills. 

Step 1: Create a new HTML form inside WP Pages

You can add the form to an existing page or create a new one. 

To create a new contact form page, go to Pages > Add New and give your page a name. Afterward, click add block “Custom HTML”

Step 2: Create the HTML structure of the contact form

Create the HTML structure of your contact form. Here’s an example:

<form id="contact-form" action="/wp-admin/admin-post.php" method="post">
    <input type="hidden" name="action" value="submit_contact_form">
    <label for="name">Name:</label>
    <input type="text" name="name" id="name" required><br>
    <label for="email">Email:</label>
    <input type="email" name="email" id="email" required><br>
    <label for="message">Message:</label>
    <textarea name="message" id="message" required></textarea><br>
    <input type="submit" value="Submit">
</form>

The form contains, Name, Email, and Message fields, and a form button for submitting the form. But if you want to go super fancy you could also add some conditional logic, pull data from a CRM, add checkbox, etc.  

Note: The super fancy stuff would require quite a bit of coding and integration of third-party APIs into the PHP structure of your WordPress site. 

Intermediary step: Custom CSS styles

The default HTML style looks a bit bland. Here’s a sample CSS to beautify the form:

<style>
#contact-form {
    width: 100%;
    max-width: 500px;
    margin: 0 auto;
    padding: 20px;
    background-color: #f9f9f9;
    border: 1px solid #ddd;
    border-radius: 5px;
}

#contact-form label {
    display: block;
    margin-bottom: 5px;
    font-weight: bold;
}

#contact-form input[type="text"],
#contact-form input[type="email"],
#contact-form textarea {
    width: 90%;
    padding: 10px;
    margin-bottom: 20px;
    border: 1px solid #ddd;
    border-radius: 5px;
}

#contact-form input[type="submit"] {
    background-color: #007BFF;
    color: white;
    padding: 10px 20px;
    border: none;
    border-radius: 5px;
    cursor: pointer;
}

#contact-form input[type="submit"]:hover {
    background-color: #0056b3;
}
</style>

<form id="contact-form" action="/wp-admin/admin-post.php" method="post">
    <input type="hidden" name="action" value="submit_contact_form">
    <label for="name">Name:</label>
    <input type="text" name="name" id="name" required><br>
    <label for="email">Email:</label>
    <input type="email" name="email" id="email" required><br>
    <label for="message">Message:</label>
    <textarea name="message" id="message" required></textarea><br>
    <input type="submit" value="Submit">
</form>

Note/Advanced Tip:

The basic HTML form I created already accepts the styles. The <style> tag at the beginning of the HTML contains the CSS rules that style the form. These rules apply to all elements within the #contact-form element because of the way CSS works.

However, if you want to separate the CSS from the HTML, you can move the CSS code to a separate .css file and link it to your HTML file. Here’s how you can do it:

  1. Create a new .css file in your theme directory, let’s call it custom_form.css. Copy the CSS rules from the <style> tag and paste them into this file.
  2. Link the CSS file in your HTML file. You can do this by adding a <link> tag in the <head> section of your HTML file. Here’s an example:
<head>
    <!-- Other head elements -->
    <link rel="stylesheet" href="/path/to/your/theme/directory/custom_form.css">
</head>
  1. Replace /path/to/your/theme/directory/ with the actual path to your theme directory.

Now, the styles defined in contact-form.css will be applied to your form.

Step 3: Create a Function to Handle Form Submission

In your theme’s functions.php file, add the following PHP function to handle form submission:

<?php

/**
 * Some other theme functions
 */


function handle_contact_form_submission() {
    if( isset($_POST['action']) && $_POST['action'] === 'submit_contact_form' ) {
        $name = sanitize_text_field( $_POST['name'] );
        $email = sanitize_email( $_POST['email'] );
        $message = sanitize_textarea_field( $_POST['message'] );
        $adminEmail = get_option( 'admin_email' );

        // Here, you can add your code to process the form data (e.g., send an email).
        wp_mail($adminEmail, sprintf("New message from %s email:%s", $name, $email), $message);

        // Redirect the user back to the main or contact page after form submission.
        wp_redirect( home_url('/') );
    }
}


add_action( 'admin_post_nopriv_submit_contact_form', 'handle_contact_form_submission' );
add_action( 'admin_post_submit_contact_form', 'handle_contact_form_submission' );


?>

Step 4: Don’t forget to sanitize and validate user input

Before processing the form data, you should sanitize and validate it to protect your site from malicious inputs. WordPress provides several functions for this purpose, such as sanitize_text_field(), filter_var(), and validate_email().

Pro Tip: If your form has to handle a file upload on top of other functionalities, you need to sanitize and validate that file as well. 

And congrats! You’ve created a contact form in WordPress without plugins and extra files.

Create a callback function with validations and a captcha

Here, I’ll tell you how to create more advanced forms, get better spam protection, and improve user registration on your WordPress website with some JavaScript tricks

This step is more secure and easier to maintain, with just a tiny code snippet. 

To make everything neat and speed up the integration process for a custom form, I’ll create a single PHP function from all the code discussed under creating a contact form without a plugin. 

Then, you can use the function as the callback function of the shortcode. Here are the steps:

Step 1: Create a shortcode 

Create a shortcode that will output your form. This can be done in the functions.php file:

add_shortcode( 'custom_contact_form', 'custom_contact_form_shortcode' );
function custom_contact_form_shortcode() {
    // Code goes here
}

Step 2: Shortcode function

Inside the custom_contact_form_shortcode function, add the HTML structure of your contact form.

function custom_contact_form_shortcode() {
    ob_start(); ?>
    <form id="contact-form" action="<?php echo esc_url( $_SERVER['REQUEST_URI'] ); ?>" method="post">
     <input type="hidden" name="action" value="submit_contact_form">
     <label for="name">Name:</label>
     <input type="text" name="name" id="name" required><br>
     <label for="email">Email:</label>
     <input type="email" name="email" id="email" required><br>
     <label for="message">Message:</label>
     <textarea name="message" id="message" required></textarea><br>
     <input type="submit" value="Submit">
    </form>

    <?php return ob_get_clean();
}

Step 3: Handling form submissions

While still inside the custom_contact_form_shortcode function, add the code to handle form submissions, validate data input and display messages.

function custom_contact_form_shortcode() {
    ob_start();

    if( isset($_POST['action']) && $_POST['action'] === 'submit_contact_form' ) {
        $name = sanitize_text_field( $_POST['name'] );
        $email = sanitize_email( $_POST['email'] );
        $message = sanitize_textarea_field( $_POST['message'] );


        // Initialize an array to hold validation messages
        $validation_messages = [];

        // Validate the data
        if (strlen($name) === 0) {
            $validation_messages[] = 'Please enter a valid name.';
        }

        if (strlen($email) === 0 || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
            $validation_messages[] = 'Please enter a valid email address.';
        }

        if (strlen($message) === 0) {
            $validation_messages[] = 'Please enter a valid message.';
        }

        // Check if there are any validation messages
        if (!empty($validation_messages)) {
            foreach ($validation_messages as $validation_message) {
                echo '<div class="validation-message">' . esc_html($validation_message) . '</div>';
            }
        } else {
            // If there are no validation messages, send the email
            $adminEmail = get_option( 'admin_email' );
            $headers = array('Content-Type: text/html; charset=UTF-8');
            wp_mail($adminEmail, 'New message from ' . $name, $message, $headers);
            echo '<div class="success-message">Your message has been sent successfully.</div>';
        }
    }

    // Code for the form goes here

    return ob_get_clean();
}

Now, after taking the time to create a callback function, you can just use[custom_contact_form] in your WordPress pages or posts, and the contact form will show up. 

Nevertheless, my form isn’t ideal yet. For instance, if a user types invalid info, the system gets executed on a reloaded page, so the data is lost. This is as annoying as a floating popup and will surely make people churn. 

But, it can be solved if I replicate the PHP validation with JavaScript. I’ll be covering that in the JavaScript validation section. 

Step 4 Add Captcha to contact form

To implement reCaptcha, you’ll need to register your site on the Google reCaptcha website to get a site key and secret key. Then, you can add the reCaptcha widget to your form and verify the user’s response using the secret key.

This may seem as an overkill, but bots are getting smarter, so CAPTCHA gives you the extra edge to ward off malicious submissions. 

Step 5: Implement CSRF protection

To protect your form from Cross-Site Request Forgery (CSRF) attacks, you can use WordPress’s built-in CSRF API. 

First, you’ll need to generate a nonce (number used once) using the wp_nonce_field() function in your form. Then, you can verify the nonce in process-form.php using the wp_verify_nonce() function.

// In your form
wp_nonce_field( 'submit_contact_form_nonce', 'submit_contact_form_nonce_field' );

// In custom_contact_form_shortcode
if (!isset($_POST[submit_contact_form_nonce_field]) || !wp_verify_nonce($_POST[submit_contact_form_nonce_field], submit_contact_form_nonce)) {
    die('Invalid request');
}

Pro Tip

Some WordPress hosting providers may offer additional CSRF protection. However, this is typically done at the application level. So, you should better search wordpress.org for add-ons or libraries that fit your use case, or just implement the above. 

Step 6: Send Email

Finally, you can send an email using the $wpdb->get_row() function to retrieve the site administrator’s email address from the WordPress database, and the wp_mail() function to send the email.

Note: This isn’t the best solution since the given function is notoriously unreliable. No worries, I’ll tell you how to implement a proper email-sending service and avoid wp_mail() limitations. 

$adminEmail = get_option( 'admin_email' );
$headers = ['Content-Type: text/html; charset=UTF-8'];
wp_mail($adminEmail, 'New message from ' . $name, $message, $headers);

JavaScript validation

Client-side validation using JavaScript prevents the page from reloading when the form is submitted. Instead, it will perform the validation and display any validation messages on the page. If there are no validation messages, it will submit the form normally.

Here’s the code and logic:

  1. Add an event listener to the form that listens for the submit event. When the form is submitted, this event listener will execute a function that performs the validation.
document.getElementById('contact-form').addEventListener('submit', function(event) {
    // Prevent the form from being submitted normally
    event.preventDefault();

    // Perform validation
});
  1. Inside the event listener function, add the code to perform the validation. You can access the form fields using their IDs and the value property.
var name = document.getElementById('name').value;
var email = document.getElementById('email').value;
var message = document.getElementById('message').value;

var validation_messages = [];

if (name === '') {
    validation_messages.push('Please enter a valid name.');
}

if (email === '' || !(/^[^@]+@[^@]+\.[^@]+$/.test(email))) {
    validation_messages.push('Please enter a valid email address.');
}

if (message === '') {
    validation_messages.push('Please enter a valid message.');
}

Important note: 

For the sake of convenience, the code above contains a simple regex to validate emails. But it doesn’t cover all the cases, thus may return false positives. This goes double if you, for example, run a busy WooCommerce store and handle a bunch of submissions.

The truth is you can’t properly validate emails at a volume with a regex unless it’s super long. So, I suggest you integrate a proper validation library. Here are some options:

  1. After performing the validation, check if there are any validation messages. If there are, display them on the page.
if (validation_messages.length > 0) {
    var validationContainer = document.getElementById('validation-messages-container');
    validationContainer.innerHTML = '';
    validation_messages.forEach(function(message) {
        var div = document.createElement('div');
        div.className = 'validation-message';
        div.innerText = message;
        validationContainer.appendChild(div);
    });
} else {
    // If there are no validation messages, submit the form
    this.submit();
}

Here’s the complete code:

document.getElementById('contact-form').addEventListener('submit', function(event) {
    event.preventDefault();

    var name = document.getElementById('name').value;
    var email = document.getElementById('email').value;
    var message = document.getElementById('message').value;

    var validation_messages = [];

    if (name === '') {
        validation_messages.push('Please enter a valid name.');
    }

    if (email === '' || !(/^[^@]+@[^@]+\.[^@]+$/.test(email))) {
        validation_messages.push('Please enter a valid email address.');
    }

    if (message === '') {
        validation_messages.push('Please enter a valid message.');
    }

    if (validation_messages.length > 0) {
        var validationContainer = document.getElementById('validation-messages-container');
        validationContainer.innerHTML = '';
        validation_messages.forEach(function(message) {
            var div = document.createElement('div');
            div.className = 'validation-message';
            div.innerText = message;
            validationContainer.appendChild(div);
        });
    } else {
        this.submit();
    }
});

How to send an email with a WordPress contact form?

Here comes the part where I tell you how to integrate a proper email sending service, and I’ll be using Maitrap Email Delivery Platform

I could rant about all the goodies it offers, but you should see it yourself. Hit the play button below ⬇️. 

Step 1: Configure WordPress to use SMTP

To configure WordPress to use SMTP for sending emails, you need a plugin. Or you need to be making changes to the wp-config.php file and code in the sending functionality. 

I won’t cover that here, as I already blogged about sending emails from wordpress without a plugin in detail. Click the link to check it out. 

For this example, I’ll use WP Mail SMTP for convenience; simply, it’s proven reliable and straightforward to implement. 

Here are the basics:

  1. Install and activate the WP Mail SMTP plugin.
  2. Go to WP Mail SMTP > Settings in your WordPress admin panel.
  3. In the From Email field, enter the email address you want to send emails from.
  4. In the Mailer dropdown, select Other SMTP.
  5. Enter the SMTP settings provided by Mailtrap:
  • SMTP Host: live.smtp.mailtrap.io
  • SMTP Port: 587
  • Encryption: TLS
  • Authentication: Yes
  • Username: Your Mailtrap username
  • Password: Your Mailtrap password
  1. Click Save Settings.

The above is only a bare-bones tutorial. We already covered an extensive step-by-step guide including screenshots and detailed implementation, hit the link to check it out ⬅️. 

Note: The live.smtp.mailtrap.io is the endpoint for transactional emails. If you’d like to send bulk (email marketing) emails, use bulk.smtp.mailtrap.io

Step 2: Modify the contact form function

It’s necessary to modify the original contact form function to send emails via the Mailtrap SMTP you just configured. Here’s the exemplary script:

function custom_contact_form_shortcode() {
    ob_start();

    if( isset($_POST['action']) && $_POST['action'] === 'submit_contact_form' ) {
        $name = sanitize_text_field( $_POST['name'] );
        $email = sanitize_email( $_POST['email'] );
        $message = sanitize_textarea_field( $_POST['message'] );



        // Initialize an array to hold validation messages
        $validation_messages = [];

        // Validate the data
        if (strlen($name) === 0) {
            $validation_messages[] = 'Please enter a valid name.';
        }

        if (strlen($email) === 0 || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
            $validation_messages[] = 'Please enter a valid email address.';
        }

        if (strlen($message) === 0) {
            $validation_messages[] = 'Please enter a valid message.';
        }

        // Check if there are any validation messages
        if (!empty($validation_messages)) {
            foreach ($validation_messages as $validation_message) {
                echo '<div class="validation-message">' . esc_html($validation_message) . '</div>';
            }
        } else {
            // If there are no validation messages, send the email
            $adminEmail = get_option( 'admin_email' ); 
            $headers = array('Content-Type: text/html; charset=UTF-8');
            wp_mail($adminEmail, 'New message from ' . $name, $message, $headers);
            echo '<div class="success-message">Your message has been sent successfully.</div>';
        }
    }

    // Code for the form goes here

    return ob_get_clean();
}

With this setup, when a user submits the contact form, the form data will be sent to the admin’s email address using the SMTP settings you configured in WP Mail SMTP. 

The emails will be sent through Mailtrap’s SMTP server, meaning you won’t depend on WordPress’s unreliable wp_mail() function. 

Do you need to test emails before sending them?

The quick answer is – you need to test the emails! 

Besides testing the contact form functionality, you need to ensure all submitted forms are reaching the target address without a glitch. 

Also, you’ll most likely use the form to collect leads or critical user-generated messages about your service or product. Plus, you’ll be handling user email addresses, names, or maybe some other sensitive information, so you need to be 100% sure your form submission system isn’t buggy. 

The best way to do that is to use Mailtrap Email Testing. Yes, I’m tooting our own horn a bit but for a good reason. 

Mailtrap Email Testing is a sandbox to inspect and debug emails in staging, dev, and QA environments before emailing your recipients. 

You can preview and analyze content for spam and validate HTML/CSS. You get a bunch of other features including:

  • Fake SMTP Server
  • HTML/CSS check
  • Spam score check
  • API for QA automation
  • Ready to use integrations in 20+ like Ruby, Python, PHP, Node.js, .Net, etc.
  • Emails preview
  • Multiple inboxes for different projects and stages
  • User management, SSO

Now, the cool thing about testing is that you don’t need any additional installations. Again, I’ll be using WP Mail SMTP plugin, and modifying only the SMTP settings. So, I won’t repeat all the setup steps.

As a reminder, you’ll still need to choose Other SMTP in the Mailer dropdown to add Mailtrap Email Testing as Other SMTP. Here are the exemplary SMTP settings for testing:

  • SMTP Host: sandbox.smtp.mailtrap.io
  • SMTP Port: 2525
  • Encryption: TLS
  • Authentication: Yes
  • Username: Your Mailtrap username
  • Password: Your Mailtrap password

Now, you can test your email sending. When you send an email, it will be caught by Mailtrap sandbox and you can view it in your Mailtrap inbox.

Mailtrap email testing HTML preview

Pro Trick:

Mailtrap provides a hook that modifies the PHPMailer instance used by WordPress to send emails. 

You don’t need this when using the WP Mail SMTP plugin, as the plugin handles the modification of the PHPMailer instance for you. But, if you want to use the hook instead of the WP Mail SMTP plugin, and add the following code to your theme’s functions.php file:

function mailtrap($phpmailer) {
$phpmailer->isSMTP();
$phpmailer->Host = 'sandbox.smtp.mailtrap.io';
$phpmailer->SMTPAuth = true;
$phpmailer->Port = 2525;
$phpmailer->Username = 'Your_Mailtrap_Username';
$phpmailer->Password = 'Your_MailtrapEmailTesting_Password';
}

add_action('phpmailer_init', 'mailtrap');

The emails will be sent through Mailtrap Email Testing SMTP server, allowing you to catch and inspect them in Mailtrap without actually sending them to the recipient’s inbox.

Further reading:

Submissions galore

When all’s said and done, you now have all the power to create a great WordPress contact form. And just to remind you – don’t rely heavily on plugins and native WordPress email sending. 

If you have growing demand to handle data from form submissions, take the time to code a custom form and use Mailtrap to test, send, and control your emails. 

 

Article by Veljko Ristić Content Manager @ Mailtrap

Linguist by trade, digital marketer at heart, I’m a Content Manager who’s been in the online space for 10+ years. From ads to e-books, I’ve covered it all as a writer, editor, project manager, and everything in between. Now, my passion is with email infrastructure with a strong focus on technical content and the cutting-edge in programming logic and flows. But I still like spreading my gospels while blogging purely about marketing.