Feb 25, 2009

WordPress & jQuery Contact Form without a Plugin

There are lots of WordPress plugins for contact forms, but wouldn’t it be nice to have more control over the markup? In this tutorial, I am going to show how to use a custom page template to create a contact form in WordPress without a plugin.

Some people may want to skip the post and get to the demo and source files:

View Demo Download Source Files

So, why not use a plugin?

Well, I think that a contact form is so simple that a WordPress plugin that doesn’t provide exactly what I want is pretty lame. Plus, I don’t need all those fancy interfaces for building the form; I just need the code.

The Plan

Our plan is to create a custom WordPress Page Template, then create a page that uses that template. Finally, we will add in a little jQuery to improve the form. Let’s write a little pseudo code to help determine how our page template will be structured.

Pseudo Code

<code>If form was submitted validate it
 If the form was submitted successfully
  Send email(s)
 Else
  Set variables to show errors

If the form was submitted successfully
 Show thank you message
Else
 Show form (with errors if there are any)

Creating the WordPress Page Template

Alright, so first, we are going to start with some basic stuff: define the template name, include the header/sidebar/footer, and setup the basic structure of our pseudo code.

<code><?php
/*
Template Name: Contact Form
*/
?>

<?php 
//If the form is submitted
if(isset($_POST['submitted'])) {
 //If there is no error, send the email
 if(!isset($hasError)) {

 }
} ?>

<?php get_header(); ?>

<?php 
//If the email was sent, show a thank you message
//Otherwise show form
if(isset($emailSent) && $emailSent == true) {
?>

<?php } else { ?>

<?php } ?>

<?php get_sidebar(); ?>

<?php get_footer(); ?>

The Form

Next, let’s code the actual form. I also want to provide the ability for the user to enter some text to go above the form, so we are going to use the regular loop:

<code><?php if(isset($emailSent) && $emailSent == true) { ?>

 <div class="thanks">
  <h1>Thanks, <?=$name;?></h1>
  <p>Your email was successfully sent. I will be in touch soon.</p>
 </div>

<?php } else { ?>

 <?php if (have_posts()) : ?>
 
  <?php while (have_posts()) : the_post(); ?>
   <h1><?php the_title(); ?></h1>
   <?php the_content(); ?>
  
   <?php if(isset($hasError) || isset($captchaError)) { ?>
    <p class="error">
     There was an error submitting the form.
    <p>
   <?php } ?>
 
   <form action="<?php the_permalink(); ?>" id="contactForm" method="post">
 
   </form>
 
  <?php endwhile; ?>
 <?php endif; ?>
< } ?>

If the emailSent variable is set to true, we display the thank you message. Otherwise, we show the form. So we are outputting the title of the page, and any content that was entered. Then, we are checking to see if there was an error. Finally, we display the form:

<code><ol class="forms">
 <li>
  <label for="contactName">Name</label>
  <input type="text" name="contactName" id="contactName" value="
  <?php if(isset($_POST['contactName'])) echo $_POST['contactName'];?>"
   class="requiredField" />
  <?php if($nameError != '') { ?>
   <span class="error"><?=$nameError;?></span> 
  <?php } ?>
 </li>
 
 <li>
  <label for="email">Email</label>
  <input type="text" name="email" id="email" value="
  <?php if(isset($_POST['email']))  echo $_POST['email'];?>"
  class="requiredField email" />
  <?php if($emailError != '') { ?>
   <span class="error"><?=$emailError;?></span>
  <?php } ?>
 </li>
 
 <li class="textarea">
  <label for="commentsText">Comments</label>
  <textarea name="comments" id="commentsText" rows="20" cols="30" class="requiredField">
  <?php if(isset($_POST['comments'])) { 
   if(function_exists('stripslashes')) { 
    echo stripslashes($_POST['comments']); 
   } else { 
    echo $_POST['comments']; 
   }
   } ?></textarea>
  <?php if($commentError != '') { ?>
   <span class="error"><?=$commentError;?></span> 
  <?php } ?>
 </li>
 <li class="inline">
  <input type="checkbox" name="sendCopy" id="sendCopy" value="true"
  <?php if(isset($_POST['sendCopy']) && $_POST['sendCopy'] == true) 
   echo ' checked="checked"'; ?> 
  />
  <label for="sendCopy">Send a copy of this email to yourself</label>
 </li>
 <li class="screenReader">
  <label for="checking" class="screenReader">If you want to submit this form, do not enter anything in this field</label>
  <input type="text" name="checking" id="checking" class="screenReader" value="
  <?php if(isset($_POST['checking']))  echo $_POST['checking'];?>"
  />
 </li>
 <li class="buttons">
  <input type="hidden" name="submitted" id="submitted" value="true" />
  <button type="submit">Email me »</button>
 </li>
</ol>

Note: Line wrapping added for readability.

Ok, wow, that may seem like a lot. So let’s break down the name field to see what this code is actually doing:

<code><li><label for="contactName">Name</label>
 <input type="text" name="contactName" id="contactName" value="<?php if(isset($_POST['contactName'])) echo $_POST['contactName'];?>" class="requiredField" />
 <?php if($nameError != '') { ?>
  <span class="error"><?=$nameError;?></span> 
 <?php } ?>
</li>

We are displaying each form field in a list item, displaying the label, input field, and then showing an error message if there is one. We are also displaying the value in the form field if it was already submitted.

So in essence, we are just doing that for each field of the form. You could easily go into the code to add more fields.

We are also using honeypot captcha to see if a bot was trying to submit the form:

<code><li class="screenReader">
 <label for="checking" class="screenReader">If you want to submit this form, do not enter anything in this field</label>
 <input type="text" name="checking" id="checking" class="screenReader" value="<?php if(isset($_POST['checking']))  echo $_POST['checking'];?>" />
</li>

That list item is pushed off the page with CSS, and if there is a value in that field, we can assume that it is not a human trying to submit the form:

<code>.screenReader { 
 left: -9999px; 
 position: absolute; 
 top: -9999px;
}

The Validation

Next, we are going to have a conditional statement to determine if the form was submitted or not:

<code><?php 
//If the form is submitted
if(isset($_POST['submitted'])) {

} ?>

Within that conditional, is where we are going to do all of our validation of the required fields. First, let’s check to see if our honeypot captcha form field is filled in. If it is, then we will display an error and not check anymore of the form:

<code>//Check to see if the honeypot captcha field was filled in
if(trim($_POST['checking']) !== '') {
 $captchaError = true;
} else {

}

So if the captcha field was left blank, we will continue to validate the required fields:

<code>//Check to make sure that the name field is not empty
if(trim($_POST['contactName']) === '') {
 $nameError = 'You forgot to enter your name.';
 $hasError = true;
} else {
 $name = trim($_POST['contactName']);
}

//Check to make sure sure that a valid email address is submitted
if(trim($_POST['email']) === '')  {
 $emailError = 'You forgot to enter your email address.';
 $hasError = true;
} else if (!eregi("^[A-Z0-9._%-]+@[A-Z0-9._%-]+.[A-Z]{2,4}$", trim($_POST['email']))) {
 $emailError = 'You entered an invalid email address.';
 $hasError = true;
} else {
 $email = trim($_POST['email']);
}
 
//Check to make sure comments were entered 
if(trim($_POST['comments']) === '') {
 $commentError = 'You forgot to enter your comments.';
 $hasError = true;
} else {
 if(function_exists('stripslashes')) {
  $comments = stripslashes(trim($_POST['comments']));
 } else {
  $comments = trim($_POST['comments']);
 }
}

Again, that may seem like a little much, so let’s just take a look at the validation on the name field:

<code>if(trim($_POST['contactName']) === '') {
 $nameError = 'You forgot to enter your name.';
 $hasError = true;
} else {
 $name = trim($_POST['contactName']);
}

If the name field if empty, set a variable that will display the name error and set a flag saying that there was an error on the form. Otherwise, set a variable that will contain the name value from the form.

Sending the Email

Now, we want to send the email if there are no errors:

<code>//If there is no error, send the email
if(!isset($hasError)) {

 $emailTo = '<strong>me@somedomain.com</strong>';
 $subject = 'Contact Form Submission from '.$name;
 $sendCopy = trim($_POST['sendCopy']);
 $body = "Name: $name nnEmail: $email nnComments: $comments";
 $headers = 'From: My Site <'.$emailTo.'>' . "rn" . 'Reply-To: ' . $email;
 
 mail($emailTo, $subject, $body, $headers);

 if($sendCopy == true) {
  $subject = 'You emailed <strong>Your Name</strong>';
  $headers = 'From: <strong>Your Name</strong> <<strong>noreply@somedomain.com</strong>>';
  mail($email, $subject, $body, $headers);
 }

 $emailSent = true;

}

Note: Items bolded are values that you will want to change before implementing.

I personally like to have the contact form submission come from myself. That way, I just setup a filter in Gmail, and I can guarantee that it won’t get caught in my spam filter. The second email is only sent if the user checks the checkbox to send a copy to themselves.

View Entire Custom Page Template

Creating the Page in WordPress

First, you want to upload the contact-form.php page template to your themes folder. Next, you will create the page in WordPress and select Contact Form as the page template.

Adding WordPress page template

Then, just publish your page and you will have your contact form. Well, the form will be usable, but we are going to add in some CSS and jQuery to finish it off.

Styling the Form

I recently wrote an article about styling forms, so we are just going to stick with some basic styles:

<code>.screenReader { left: -9999px; position: absolute; top: -9999px; }
.thanks { background: #F2F3F6; border: 1px solid #7E8AA2; padding: 10px; }

/*****Forms*****/
ol.forms { float: left; list-style: none; margin: 0; width: 100%; }
ol.forms li { 
 clear: both; 
 float: left; 
 margin-bottom: 18px; 
 position: relative;
 width: 100%;
}
ol.forms label {
 cursor: pointer;
 display: block;
 float: left;
 font-weight: bold;
 padding-right: 20px;
 width: 100px;
}
ol.forms input, ol.forms textarea {
 border: 1px solid #7E8AA2;
 border-radius: 3px;
 font: inherit;
 -moz-border-radius: 3px;
 padding: 2px;
 -webkit-border-radius: 3px;
 width: 214px;
}
ol.forms textarea { height: 300px; width: 334px; }
ol.forms input:focus, ol.forms textarea:focus { background-color: #f2f3f6; border-color: #ff9800; }
.error { color: #f00; }
ol.forms li .error { font-size: 12px; margin-left: 20px; }
ol.forms li.textarea .error {
 display: block;
 position: absolute;
 right: 0;
 top: 0;
 width: 100px;
}
ol.forms li.screenReader { margin-bottom: 0; }
ol.forms li.buttons button {
 background: #ff9800;
 border: none;
 color: #000;
 cursor: pointer;
 font: 16px/16px "Avenir LT Std", Helvetica, Arial, sans-serif;
 overflow: hidden;
 padding: 6px 3px 3px 3px;
 text-transform: uppercase;
 width: auto;
}
ol.forms li.buttons button:hover { color: #222; }
ol.forms li.buttons button:active { left: -1px; position: relative; top: -1px; }
ol.forms li.buttons, ol.forms li.inline { float: right; width: 460px; }
ol.forms li.inline input { width: auto; }
ol.forms li.inline label { display: inline; float: none; width: auto; }

So drop that CSS in your theme stylesheet and you will see the form start to look much better.

Enhancing the form with some jQuery

I have also already written about creating AJAX forms with jQuery, but I thought I would specifically talk about an AJAX script for a contact form.

First, we want to execute our jQuery when the document is ready and the form was submitted:

<code>$(document).ready(function() {
 $('form#contactForm').submit(function() {
  
  return false;
 });
});

Next, we want to hide any error messages if there are any and validate any required fields which are denoted with a class of requiredField:

<code>$('form#contactForm .error').remove();
var hasError = false;
$('.requiredField').each(function() {
   
});

After that, we want to validate that the field is not empty and append an error message if it is:

<code>if(jQuery.trim($(this).val()) == '') {
 var labelText = $(this).prev('label').text();
 $(this).parent().append('<span class="error">You forgot to enter your '+labelText+'.</span>');
 hasError = true;
}

If the field is not empty and also has a class of email, we want to validate that the email address is valid:

<code> else if($(this).hasClass('email')) {
 var emailReg = /^([w-.]+@([w-]+.)+[w-]{2,4})?$/;
 if(!emailReg.test(jQuery.trim($(this).val()))) {
  var labelText = $(this).prev('label').text();
  $(this).parent().append('<span class="error">You entered an invalid '+labelText+'.</span>');
  hasError = true;
 }
}

If there are no errors, then we want to replace the submit button with a loading image:

<code>if(!hasError) {
$('form#contactForm li.buttons button').fadeOut('normal', function() {
 $(this).parent().append('<img src="/wp-content/themes/td-v3/images/template/loading.gif" alt="Loading…" height="31" width="31" />');
});

Note: You will need to update the source of the image to wherever you upload it in your theme.

Finally, let’s submit the form via an AJAX request, slide the form up, and show a thank you message:

<code>var formInput = $(this).serialize();
$.post($(this).attr('action'),formInput, function(data){
 $('form#contactForm').slideUp("fast", function() {       
  $(this).before('<p class="thanks"><strong>Thanks!</strong> Your email was successfully sent. I check my email all the time, so I should be in touch soon.</p>');
 });
});

Take a look at the entire script:

<code>$(document).ready(function() {
 $('form#contactForm').submit(function() {
  $('form#contactForm .error').remove();
  var hasError = false;
  $('.requiredField').each(function() {
   if(jQuery.trim($(this).val()) == '') {
    var labelText = $(this).prev('label').text();
    $(this).parent().append('<span class="error">You forgot to enter your '+labelText+'.</span>');
    hasError = true;
   } else if($(this).hasClass('email')) {
    var emailReg = /^([w-.]+@([w-]+.)+[w-]{2,4})?$/;
    if(!emailReg.test(jQuery.trim($(this).val()))) {
     var labelText = $(this).prev('label').text();
     $(this).parent().append('<span class="error">You entered an invalid '+labelText+'.</span>');
     hasError = true;
    }
   }
  });
  if(!hasError) {
   $('form#contactForm li.buttons button').fadeOut('normal', function() {
    $(this).parent().append('<img src="/wp-content/themes/td-v3/images/template/loading.gif" alt="Loading…" height="31" width="31" />');
   });
   var formInput = $(this).serialize();
   $.post($(this).attr('action'),formInput, function(data){
    $('form#contactForm').slideUp("fast", function() {       
     $(this).before('<p class="thanks"><strong>Thanks!</strong> Your email was successfully sent. I check my email all the time, so I should be in touch soon.</p>');
    });
   });
  }
  
  return false;
  
 });
});

Just include it in the head of your document after jQuery, and you are good to go:

<code><script type="text/javascript" src="<?php bloginfo('template_directory'); ?>/scripts/jquery.js"></script>
<script type="text/javascript" src="<?php bloginfo('template_directory'); ?>/scripts/contact-form.js"></script>

Note: You may need to change the source depending upon where you upload the files in your theme.

Conclusion

View Demo Download Source Files

That’s it! Just upload the files and you’ve got your form. Since you’ve got the code right in front of you, it should be very easy to tweak and add on to. Enjoy!

CenturyLink Deals: Internet, Phone, & TV Bundles

Categories