How To Build Your Own WordPress Contact Form and Why

I’m a massive fan of building stuff from the ground up. There are loads of plugins around for everything you could ever wish for in a WordPress blog, but I feel both rewarded and secure when I build features from scratch.

Why bother? Most of the time I don’t want to mess around with a plugin’s UI, or the plugin does way more than I actually want it to do. Without hacking the core files, plugins can be very rigid with what you’re allowed to do.

The solution? Roll your own! It’s a great learning experience, you know what’s going on under the hood and you’re gaining skills for another time. And trust me, you will need these skills down the track. I’ve rarely learnt how to do something with WordPress that I haven’t ended up repeating in another project.

Why Don’t I Just Use a Plugin?

Here are four good reasons why plugins are bad for simple contact forms:

  1. Plugins pack in way more than you (should) care for
  2. Using a UI to build a simple contact form is overkill
  3. Knowing what’s under the hood is good for your knowledge, and your peace of mind
  4. Default stylesheets kill me slowly from the inside

I could probably go on.

I hate bulky UIs with a passion. I hate bad UX and I especially hate too much functionality. Hate is a very strong word, but these days most forms that boast contact forms are in competition with each other to create the best, most feature rich plugin. And it ends up looking like this

Or even worse, this

You hated scrolling past that as much as I did!

But I Need All Those Features!!1!

Really? This isn’t Web 2.0 anymore. Complex forms scare customers.

How many times have you gone to fill out a form, only to be daunted by the amount of personal data you have to put in? It happens all the time. People even get halfway and are then distracted by something else. People on the web have a very short attention span. So in order for you to make it as easy as possible for your potential clients and customers to get in touch with you, you really should be stripping to the bone.

So What’s Absolutely Essential?

Name, email, message and human verification. But I think you knew that already.

These four small bits of information are as simple as commenting on a blog — why would you want to make getting in touch any more difficult? I don’t think I’ve ever built a form with more information than that, unless absolutely required.

If people want to leave their phone number and address, they will do so in the message. Visual cues such as asking them in a short paragraph above the form is enough!

Surely It’s a Pain Coding Everything From scratch!?

Not really. I mean, if you’re patient you’ll smash through this tutorial in under half an hour. All it really consists of is:

  1. A custom template file
  2. Some PHP

Yep, that’s it. You can handle displaying the form, human verification, validation, emailing the admin and thanking the reader for getting in touch all in one file. In fact, here it is.

Getting started

As per usual, I’m starting with a fresh WordPress installation. If you’re unsure how, educate yourself on the Codex.

To follow good practice, I’m going to create a child theme of TwentyTwelve — available here — with just a stylesheet and our custom page template. You can take out the custom page template and drop it into any of your current themes, and it should work flawlessly (bar some CSS modifications).

In wp-content/themes, add a new folder called “contact-form.” Within that, create two new files — style.css and page-contact-us.php.

Inside style.css, paste the following:

/*
Theme Name:     Contact Form Page Template
Theme URI:      http://premium.wpmudev.org/blog/
Description:    A super simple, self-contained contact form you can drop into your existing theme.
Author:         Harley
Author URI:     http://premium.wpmudev.org/
Template:       twentytwelve
Version:        0.1
*/

@import url("../twentytwelve/style.css");

Ignore my shameless premium plug — I work here. It’s a requirement!

By now, you should be able to go ahead and activate the theme on your test site, and be ready to roll.

The next step is to create a page, aptly-named “Contact Us.” This name is special. It relates immediately to the template file we made previously called page-contact-us.php. This solution for creating a custom page template is not a catch-all, just a convention WordPress provides and I like. Page-about-us.php would automatically be used to display a page titled “About Us.” It’s kinda handy!

If you’ve created page-contact-us.php and left it empty, visiting your newly created “Contact Us” page will yield a blank page.

That’s alright though! Quickly pad it out with the following, and it will look just like a normal page again.

<?php get_header(); ?>

  <div id="primary" class="site-content">
    <div id="content" role="main">

      <?php while ( have_posts() ) : the_post(); ?>

          <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>

            <header class="entry-header">
              <h1 class="entry-title"><?php the_title(); ?></h1>
            </header>

            <div class="entry-content">
              <?php the_content(); ?>

              <p>FORM CODE GOES HERE</p>

            </div><!-- .entry-content -->

          </article><!-- #post -->

      <?php endwhile; // end of the loop. ?>

    </div><!-- #content -->
  </div><!-- #primary -->

<?php get_sidebar(); ?>
<?php get_footer(); ?>

Alrighty. Now we’ve got the base page in, it’s time to drop in a very simple form.

Replace the FORM CODE GOES HERE paragraph with the following:

<style type="text/css">
  .error{
    padding: 5px 9px;
    border: 1px solid red;
    color: red;
    border-radius: 3px;
  }

  .success{
    padding: 5px 9px;
    border: 1px solid green;
    color: green;
    border-radius: 3px;
  }

  form span{
    color: red;
  }
</style>

<div id="respond">
  <?php echo $response; ?>
  <form action="<?php the_permalink(); ?>" method="post">
    <p><label for="name">Name: <span>*</span> <br><input type="text" name="message_name" value="<?php echo esc_attr($_POST['message_name']); ?>"></label></p>
    <p><label for="message_email">Email: <span>*</span> <br><input type="text" name="message_email" value="<?php echo esc_attr($_POST['message_email']); ?>"></label></p>
    <p><label for="message_text">Message: <span>*</span> <br><textarea type="text" name="message_text"><?php echo esc_textarea($_POST['message_text']); ?></textarea></label></p>
    <p><label for="message_human">Human Verification: <span>*</span> <br><input type="text" style="width: 60px;" name="message_human"> + 3 = 5</label></p>
    <input type="hidden" name="submitted" value="1">
    <p><input type="submit"></p>
  </form>
</div>

Excuse the inline style! This is purely for error/success messages, and to put the whole thing in one file. Feel free to put it in your style.css.

There are a number of things going on here. Firstly, we echo the $respond variable, which we’ll look at a bit later.

The rest is just form tags, but you’ll note that the value of them echoes a $_POST variable. This is so that in the case the form is submitted incorrectly, all data is retained so the user doesn’t have to type out everything from scratch.

There’s also a sneaky “hidden” form input, that allows us to check if a user has posted anything or not. I’ll get to that later though.

I’ve added an asterix next to each input, to signify they are required.

If you save that and refresh, you’ll have a nice looking contact form!

The logic

The logic that follows upon form submission is simple. There are several components that need to be built.

  1. Response generation and messages (based on validation)
  2. Validation
  3. Sending an email

Response Generation

To save having messy PHP code, we’ve placed the $response variable within the form. That’s cool, keeping logic mostly separate from views. How do we set this though?

It’s pretty easy really, we need to write a function that fills the $response variable with the feedback we get from validation. This must contain messages to address each validation requirement.

At the top of your page-contact-us.php before get_header(), paste the following.

<?php

  //response generation function
  $response = "";

  //function to generate response
  function my_contact_form_generate_response($type, $message){

    global $response;

    if($type == "success") $response = "<div class='success'>{$message}</div>";
    else $response = "<div class='error'>{$message}</div>";

  }
?>

Cool. This doesn’t do a whole lot yet, but if you have basic PHP knowledge you’ll understand that we a) create an empty $response variable, and b) fill it with the $message passed depending on its $type, which will either be error or success.

Now when we build the validation, we can call generate_response() at each case (whether it be a success or failure), pass a message (i.e. Email address invalid), and it will be spat out right above the form!

A few variables to get us going

There are 3 groups of variables we need for a successful contact form.

  • Validation Messages
  • Form Input Variables
  • PHP Mailer Variables

The validation process will use all three of these groups to validate, send an email and notify the user of a sent message.

Below the my_contact_form_generate_response() function, write up the following twelve variables:

//response messages
$not_human       = "Human verification incorrect.";
$missing_content = "Please supply all information.";
$email_invalid   = "Email Address Invalid.";
$message_unsent  = "Message was not sent. Try Again.";
$message_sent    = "Thanks! Your message has been sent.";

//user posted variables
$name = $_POST['message_name'];
$email = $_POST['message_email'];
$message = $_POST['message_text'];
$human = $_POST['message_human'];

//php mailer variables
$to = get_option('admin_email');
$subject = "Someone sent a message from ".get_bloginfo('name');
$headers = 'From: '. $email . "\r\n" .
  'Reply-To: ' . $email . "\r\n";

Each group is fairly straight forward. The Response Message group stores all our feedback messages in variables.

The User Posted Variables pick up what has been put into the form, and places them in nicely named variables to save having to access the $_POST variable over and over. $_POST contains all information submitted via a form.

Finally, we set up a couple of variables that are required by PHP’s mail() function, which tell it who to go to, a subject line, and some headers that specify from and reply-to addresses.

Validation

This is the meaty bit. We want to check for all possible problems, in the most succinct way possible. This requires several nested if/else conditional statements, but not enough to blow out your brains.

In order, we check for

  1. If the user has submitted the form (using the hidden input)
  2. If not, check the human verification passes (i.e. the user can do math properly!)
  3. If passed, validate the email address
  4. If passed, check for presence of a name and message (as they’re required)
  5. If all the above passes, send an email!

So let’s get stuck into it!

Human verification

This is pretty simple really. We want to test to see if the form user has entered some math correctly, to ensure they are human. If you look back at our form field, you’ll notice the equation is ? + 3 = 5. So obviously, we want to test firstly if the value is NOT 2, spit out an error. If it is 2, we then proceed. Below the variable groups, paste the following.

if(!$human == 0){
  if($human != 2) my_contact_form_generate_response("error", $not_human); //not human!
  else {

    //validate email
    //validate presence of name and message
    //send email
  }
}
else if ($_POST['submitted']) my_contact_form_generate_response("error", $missing_content);

Here, we first check if the human verification is not equal to 0. If it is, then check if it’s incorrect. If so, generate a matching response. The last line checks if the hidden field has been submitted, and if it has, throw another error.

This tests for two cases: empty content and human verification.

If you try submit the form while it’s empty, you should get a nice error message.

Cool! If you enter anything other than “2” into the human verification, you’ll also get an error.

The next part of validation is email validation. Now we know they’re human, we want to be sure they’re supplying a legit reply address you can contact them with.

To do so very easily, we use a PHP function called filter_var() which has a number of validation models. Obviously, we’ll use the FILTER_VALIDATE_EMAIL model to validate email.

Replace the three lines of comments smack bang in the middle of our validation with the following.

//validate email
if(!filter_var($email, FILTER_VALIDATE_EMAIL))
  my_contact_form_generate_response("error", $email_invalid);
else //email is valid
{
  //validate presence of name and message
  //send email
}

Here, we filter the $email variable checking if it’s a valid email address. If not, throw an error. Else, continue!

One line email validation!

Checking for presence of a name and message is relatively easy. We just use PHP’s empty() function, which returns true or false depending whether the variable you pass to it is empty.

//validate presence of name and message
if(empty($name) || empty($message)){
  my_contact_form_generate_response("error", $missing_content);
}
else //ready to go!
{
  //send email
}

Finally, the last piece of our puzzle is sending the email. Once all our validation has passed, we use the mail() function PHP has built in to swiftly send an email. We’ve also got to generate a response on success, and on failure as well.

Replace //send email with:

$sent = wp_mail($to, $subject, strip_tags($message), $headers);
if($sent) my_contact_form_generate_response("success", $message_sent); //message sent!
else my_contact_form_generate_response("error", $message_unsent); //message wasn't sent

Believe it or not, you’re done! You’ve now got a fully functional contact form.

If you fill everything out properly, you should get a happy success message that says your email has been sent.

Success!

And that’s it. Rolling your own contact page isn’t hard, and it keeps things as fast as possible without any overhead. Depending on your skills, you can of course build on top of this. It’s a great way to learn new things as well as build on your experience. Let alone know exactly what happens under the hood!

Extra Credit

If you want to take this further, try getting the form to insert each entry as a custom post type post. You’ll need to use nonces, and wp_insert_post(). You can then even turn it into a completely user-driven testimonials engine!

Download Source Code