How to Add a Form in a WordPress Post

This is a simple step by step guide to creating a form that will capture data and store it in a mysql database on your server from within a wordpress post

Note: the below example is a live, working form on this page

Step 1:

Create a simple form for a petition, contact request, or registration:

Name:
Address:
City:
State:
Email:
Comment:

Here is the html code for it:

<table>
<tr><th>Name:</th><td><input id="userName" /></td></tr>
<tr><th>Address:</th><td> <input id="userAddress" /></td></tr>
<tr><th>City:</th><td> <input id="userCity" /></td></tr>
<tr><th>State:</th><td> <input id="userState> /></td></tr>
<tr><th>Zip:</th><td> <input id="userZip" /></td></tr>
<tr><th>Email:</th><td> <input id="userEmail" /></td></tr>
<tr><th>Comment:</th><td> <textarea id="userComment" ></textarea></td></tr>
<tr><th><td colspan=2><button type="button" onclick="saveUser();">Save</button></td></tr>
</table>

Step 2:

Create a javascript function to process the form and send it to the server. The following is a javascript function added to the page using the CSS & Javascript Toolbox plugin (it uses jquery because wordpress already has that available):

//Process the form and save the data record
function saveUser() {
  //First gather the form parameters and make sure name and email at least are populated
  var name = jQuery("#userName").val();
  var address = jQuery("#userAddress").val();
  var city = jQuery("#userCity").val();
  var state = jQuery("#userState").val();
  var zip = jQuery("#userZip").val();
  var email = jQuery("#userEmail").val();
  var comment = jQuery("#userComment").val();
  if (name.length<1 || email.length<1) {
    alert("Please at least enter your name and email.");
    return false;
  } else {
    //Now send the data to a server side function to really validate it and save it.
    jQuery.ajax({
      type: "POST",
      url: "/ajax/saveUser.php",
      data: { name:name,address:address,city:city,state:state,zip:zip,email:email,comment:comment }
    }).done(function( results ) {
      if(results.length<1){ // network error
        alert("There was a network error, please try again or contact support and tell them what you are trying to do.");
      } else { // this is a successful interaction
        var resultObj = jQuery.parseJSON(results);
                
        if (resultObj.errorMsg.length>0) {  
          alert(resultObj.errorMsg);
        } else {
    	  //Record save successful
          alert("Thanks for your information, it was saved successfully!");
          //Show the user what they have entered:
          jQuery("#userList").html(resultObj.userList);
        }
      }
    });
  }
}

Step 3:

Make sure you have a database table ready to store the information. Below is a simple table used to store the info in this example:

CREATE TABLE IF NOT EXISTS `user_info` (
  `userID` int(11) NOT NULL AUTO_INCREMENT,
  `userName` varchar(80) DEFAULT NULL,
  `address` varchar(100) DEFAULT NULL,
  `city` varchar(80) DEFAULT NULL,
  `state` varchar(40) DEFAULT NULL,
  `zip` varchar(5) DEFAULT NULL,
  `email` varchar(80) DEFAULT NULL,
  `comment` text DEFAULT NULL,
  `userIP` VARCHAR( 30 ) DEFAULT NULL,
  `dateAdded` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`userID`),
  KEY `userIP` (`userIP`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

Step 4:

Create the server side code to accept the form data, really validate it, and put it in the database or send back an error. Here is the contents of a server side code which will do all that for the example data above. Since this form is “in the wild”, I’m capturing the IP address because I will only show results to people that they entered themselves:

/*
 * File: saveUser.php
 * Description: This file takes the passed in user information and validates it before
 * 	saving it to the database and returning content to show on the page. 
 * Inputs (in POST): 
 * 	userName, address, city, state, zip, email, comment
 * Outputs:
 * 	either an error or nothing
 */
include("db.php"); // define your database credentials in another file

#connect to the database
$db = mysqli_connect($servername, $username, $password, $dbname);
mysqli_select_db($db,$dbname) or die('Could not select database');

#Get the passed in parameters into local variables, escaped for database input
$userName = empty($_POST['userName'])?'':addslashes($_POST['userName']);
$address = empty($_POST['address'])?'':addslashes($_POST['address']);
$city = empty($_POST['city'])?'':addslashes($_POST['city']);
$state = empty($_POST['state'])?'':addslashes($_POST['state']);
//only accept 5 numbers for zip
$zip = empty($_POST['zip'])?'':substr(preg_replace('/\D/','',$_POST['zip']),0,5);
$email = empty($_POST['email'])?'':addslashes($_POST['email']);
$comment = empty($_POST['comment'])?'':addslashes($_POST['comment']);
$userIP = $_SERVER['REMOTE_ADDR'];

#This is an array used for gathering all the outputs of this file
$jsonObj = array();
$jsonObj['errorMsg'] = "";
$debug=false;

#Validate inputs
if (empty($userName) or empty($email)) {
	$jsonObj['errorMsg'] = "Please at least enter your name and email.";
} else if (strpos($email,'@')===false) {
	//there are many more validations that can be made for emails but this is a start
	$jsonObj['errorMsg'] = "Please enter a valid email.";
}

#Enter the data record
if (empty($jsonObj['errorMsg'])) {	
	$sql = "insert into user_info (userName,address,city,state,zip,email,comment,userIP) 
			values
			('".$userName."','".$address."','".$city."','".$state."','".$zip."','".$email."',
			'".$comment."','".$userIP."')";
	if ($debug) echo "about to run $sql ";
	mysqli_query($db, $sql); $err = mysqli_error($db); if (!empty($err)) $jsonObj['errorMsg'] = $err;
}

#Now get the list of data entered by this IP, without any script tags to prevent XSS:
$jsonObj['userList']='';
if (empty($jsonObj['errorMsg'])) {	
	$sql = "select userName,city,state from user_info where userIP='".$userIP."'";
	$rs = mysqli_query($db, $sql); $err = mysqli_error($db); if (!empty($err)) $jsonObj['errorMsg'] = $err;
	while($row = mysqli_fetch_assoc($rs)) {
		$jsonObj['userList'].= "<tr><td>".strip_tags($row['userName'])."</td><td>".strip_tags($row['city']).
				"</td><td>".strip_tags($row['state'])."</td></tr>";
	}
}

#Now send back the data in json format
echo json_encode($jsonObj);

Step 5:

Do something with the results! You could export them, feed them into another system using an API, send them in an email to someone, or just display them like so:

Name City State
You have not entered any user records yet, try it out!

How to use Ajax in a WordPress Post

I recently put together an Ajax autocomplete example using PHP and Mysql so I could post it on my blog, but after getting it working outside wordpress on an independent page I had trouble getting it into wordpress.

I had used plugins in the past which allowed for php code to be used with shortcodes, but inline javascript calls are not something I had gotten past the wordpress editor before. The php code used for retrieving data from the database is in a separate file so no shortcode is needed for that portion.

The inclusion of the javascript autosuggest functions is something I first tried putting in a code block in the wordpress post itself as a link to the external file (autosuggest.js), but unfortunately that didn’t work. Then I saw an article where someone suggested putting the javascript in the theme file header.php and surround it with a php if statement checking for the specific post you want it to appear on. I tried that but later removed it because I wanted my ajax to work on the index page, archive pages, and category/tag/author pages – not just the “single post” page.

Then I went back to the plugin I had installed (CSS & JavaScript Toolbox) for css and javascript and tried putting the entire contents of the autosuggest.js file into one javascript block and installing that in the footer. That worked perfectly so I did the same thing for the css file using the same plugin.

The next challenge was to add the inline JavaScript (ajax) function calls from within the html code for the sample input box in the wordpress post. When I tried just putting it all into the html editor for wordpress the javascript was removed. This was not just a snippet of complete javascript or css though, so I couldn’t just use the same plugin to make another code block and put it in the header or footer.

Since PHP is executed as the page loads, I figured I could put my auto-complete input box with ajax call into a php shortcode and put the shortcode where I wanted the input box to be in my html code. That way wordpress would not filter out the javascript when saving the post contents to the database because it would be hidden behind a shortcode which would be replaced during page loading.

This worked beatifully, including the inline javascript by putting it inside a php shortcode. I used the Shortcode Exec PHP plugin for this, which is very easy to work with.

Allow Email as Username within WP-Members Plugin

Today I figured out how to let people use their email to login instead of their username to the WordPress driven site called Jacked Pack. I had already installed the WP-Members plugin in order to add custom registration fields to the WordPress account page (for the “HUGEness profile”), but when I tried installing the WP Email Login plugin it didn’t have any effect. I figured this was because the WP-Members plugin already supercedes the regular login functionality, so I asked Chad Butler (who created the WP-Members plugin) about the issue.

Fortunately Chad had already created a way for people to add plugins to his plugin, so that’s what I ended up doing in this case. I followed his instructions by creating a file called wp-members-pluggable.php in my /wp-content/plugins directory and copying the wpmem-login function into it (I found that function in the wp-members-core.php file in the wp-members plugin folder). Then I added my own simple function (which was taken from the WP Email Login plugin) to get the username from an email address in case someone enters an email in the username field. Then I added just one line to the wpmem-login function which calls my function. Once I got that working, I copied the wpmem_inc_login function (which I found in the wp-members-dialogs.php file in the wp-members plugin folder) into my wp-members-pluggable.php file and changed one line to tell people they can use Username or Email in the first field.

See below for my complete plugin for the WP-Members WordPress Plugin, or download it here:

<?php
/**
 * WP-Members Pluggable Functions
 *
 * These functions replace those in the wp-members plugin
 * 
 */

if( ! function_exists( 'wpmem_login' ) ):
/**
 * Logs in the user
 *
 * Logs in the the user using wp_signon (since 2.5.2). If login 
 * is successful, it redirects and exits; otherwise "loginfailed"
 * is returned.
 *
 * @since 0.1
 *
 * @uses apply_filters Calls 'wpmem_login_redirect' hook to get $redirect_to
 *
 * @uses wp_signon
 * @uses wp_redirect Redirects to $redirect_to if login is successful
 * @return string Returns "loginfailed" if the login fails
 */
function wpmem_login()
{
	if( isset( $_POST['redirect_to'] ) ) {
		$redirect_to = $_POST['redirect_to'];
	} else {
		$redirect_to = $_SERVER['PHP_SELF'];
	}
	
	$redirect_to = apply_filters( 'wpmem_login_redirect', $redirect_to );

	if( isset( $_POST['rememberme'] ) == 'forever' ) {
		$rememberme = true;
	} else {
		$rememberme = false;
	}

	if( $_POST['log'] &amp;amp;amp;amp;amp;&amp;amp;amp;amp;amp; $_POST['pwd'] ) {
		
		$user_login = sanitize_user( $_POST['log'] );

		$user_login = wpmem_login_check_for_email($user_login);
		
		$creds = array();
		$creds['user_login']    = $user_login;
		$creds['user_password'] = $_POST['pwd'];
		$creds['remember']      = $rememberme;
		
		$user = wp_signon( $creds, false );

		if( ! is_wp_error( $user ) ) {
			if( ! $using_cookie )
				wp_setcookie( $user_login, $user_pass, false, '', '', $rememberme );
			wp_redirect( $redirect_to );
			exit();
		} else {
			return "loginfailed";
		}
	
	} else {
		//login failed
		return "loginfailed";
	}	

} // end of login function
endif;


if ( ! function_exists( 'wpmem_login_check_for_email' ) ):
/**
 * Get Username from Email
 *
 * Takes the username and checks if there is a user with an email that matches.
 * 	If there is, the username associated with the email is returned.
 * 	Otherwise the username is returned as it was passed in.
 *
 * @uses get_user_by
 * @return string Returns username associated with email or the same
 * 	username that was passed in
 */
function wpmem_login_check_for_email($username) {
	if ( !empty( $username ) )
		$user = get_user_by( 'email', $username );
	if ( isset( $user->user_login, $user ) )
		$username = $user->user_login;
	return $username;
} // end of check for email in the username
endif;



if ( ! function_exists( 'wpmem_inc_login' ) ):
/**
 * Login Dialog
 *
 * Loads the login form for user login
 *
 * @since 1.8
 *
 * @uses apply_filters Calls wpmem_restricted_msg filters message content
 * @uses wpmem_login_form()
 *
 * @param string $page
 * @return string the generated html for the login form
 */
function wpmem_inc_login( $page="page" )
{ 	
	global $wpmem_regchk;

	$str = '';
	$arr = get_option( 'wpmembers_dialogs' );

	if( $page == "page" ){
	     if( $wpmem_regchk!="success" ){
		
			// this shown above blocked content
			$str = '<p>' . stripslashes($arr[0]) . '</p>';
			
			// filter blocked content message
			$str = apply_filters( 'wpmem_restricted_msg', $str );

		} 	
	} 

    //$arr = array( __( 'Existing users Login', 'wp-members' ), __( 'Username', 'wp-members' ), 'text', 'log', __( 'Password', 'wp-members' ), 'password', 'pwd', 'login', __( 'Login', 'wp-members' ), 'username', 'password' );
	$arr = array( __( 'Existing users Login', 'wp-members' ), __( 'Username or Email', 'wp-members' ), 'text', 'log', __( 'Password', 'wp-members' ), 'password', 'pwd', 'login', __( 'Login', 'wp-members' ), 'username', 'password' );
	
	$str = $str . wpmem_login_form( $page, $arr );
	return $str;
}
endif;
?>

Update July 5th, 2013

I was asked about the registration function as well (see comments from Brian Weiss below) and although I haven’t made a plugin for the WP-Members registration function I have done auto registrations in a separate file. I tried posting code in a comment and it didn’t turn out well, so here is the relevant code I used (in a separate php file I created in the wordpress directory) to auto create wordpress accounts based on their email and firstname (you could do it without using their name if you want, since the users will never need to know their username). If someone puts this into a plugin for the WP-Members registration function please let me know and I’ll link to it so others who want to do that can see the solution.

#Initial try at an unclaimed username
$username = $firstName.rand(1,1000);

#Now create a WP account
include('wp-config.php');

// Initialize connection and select database
mysql_connect(DB_HOST, DB_USER, DB_PASSWORD)
    or die('Could not connect: ' . mysql_error());
//echo 'Connected successfully';
mysql_select_db(DB_NAME) or die('Could not select database');
//echo "connected to db<br>";

#WP Username has to be unique
while (username_exists( $username )) {
	$username = $firstName.rand(1,1000);
}
$random_password = wp_generate_password( $length=12, $include_standard_special_chars=false );
//echo "about to create user $username with pwd $random_password and email $email<br>";
$user_id = wp_create_user( $username, $random_password, $email );
if (is_int($user_id)) {
	//echo "new user id is $user_id<br>";
} else {
    if(is_wp_error($user_id)) { echo $user_id->get_error_message(); }
    exit;
}
// then send a welcome email and/or redirect wherever you want...

How to Add the Sidebar to WordPress Twenty Eleven Theme Single Posts

This is my first post since splitting off my technical posts into a new blog focused in that area. Part of the process was setting up a new wordpress blog, and of course I wanted to try a new theme, the Twenty Eleven theme. After I began importing a few posts I realized that there was no simple option to add the sidebar to the single post view. I tried messing with the CSS for a few minutes and then realized that there must be plenty of answers from people about this issue already.

I found one that looked promising at http://tricksmommy.com/2011/07/08/add-sidebar-in-single-post-pages-of-twenty-eleven-wordpress-theme/. Unfortunately after following the detailed instructions there the single post page had the sidebar added but the main index page was shifted off to the right. I couldn’t figure out the exact reason why, but the instructions mentioned copying css from another view so I figured it must be a different setup or something. I chose the left sidebar on my site whereas they used the default with the sidebar on the right, so that might be why it didn’t work for me. After removing those changes I came up with a simpler solution (step 1 is the same as the site mentioned above, step 2 is where we differ):

  1. Go the the Theme Editor and select the Single Posts(single.php). Search for the following line:
    <?php get_footer(); ?>
    

    Just above it place the following code:

    <?php get_sidebar(); ?>
    
  2. In the same file, look for the following code:
    <?php get_template_part( 'content', 'single' ); ?>
    					
    <?php comments_template( '', true ); ?>
    

    You’ll want to add another div around the above two lines and give it a new class name so you can set the positioning, like this:

    <div class="singlePostWrapper">
    <?php get_template_part( 'content', 'single' ); ?>
    					
    <?php comments_template( '', true ); ?>
    </div>
    
  3. Next you’ll open the style.css and add a simple definition for the new css class you created above as a wrapper around the post and comments on the single post pages. You can add this at the end of the file:
    /*Allow room for sidebar in single posts*/
    .singlePostWrapper {
      position:relative;
      left:25%;
      width:75%;
    }
    

    Note that the above class definition works well for the sidebar on the left, but if you chose to put the sidebar on the right in the theme settings you can change the word ‘left’ above to ‘right’ and it should work fine.