Introduction
In this tutorial we are going to talk about how to submit feedback to your website, validate it, and capture it for approval. Let’s get started!
The idea behind this is fairly straight forward. We want to submit user reviews to a post type called “reviews”. However, we want to make sure we have some kind of validation so we are less likely to get a bunch of bots that submit feedback. If you’re a little more of an advanced user, and want to incorporate Advanced Custom Fields (ACF), then just continue on to the final step of the tutorial.
Prerequisites:
Register Custom Post Type
If you’re not quite grasping the concepts behind the above codex link, I’ll show you a quick and dirty way to register a post type. There is a more in-depth tutorial here.
Call the function
function your_custom_post_type_function() {
//args
}
add_action( 'init', 'your_custom_post_type_function' );
Name the function
Name your function something that make sense for the group of post types you’re registering. Since you can’t re-declare the same function name, it’s probably best if you organize your post type registrations by group. For example, group all your “author-related” post types together under one function and all your “types of pudding” post types under another function.
Add Arguments
Okay, so next, you need the arguments to create the actual post type:
function your_custom_post_type_function() {
$args = array(
'public' => true, // Visibility to Authors and readers.
'label' => 'Reviews' // This will be the label you see on the WordPress Dashboard.
);
register_post_type( 'reviews', $args ); // This is your custom post_type name "reviews"
}
add_action( 'init', 'your_custom_post_type_function' );
Great, now we have a new post type called reviews.
The Template File
This is pretty basic, so if you’re more advanced just skip to the next heading.
The first thing you should do is create a child theme to test this feature. If you don’t know how to do that, or don’t want to bother with it, we can do the next best thing: create a test page.
First thing you’ll need to do is copy and rename your page.php
to, let’s say, reviews.php
. Then next thing we will want to do is add a special comment at the top that tells WordPress that the page is a template:
<?php
/*
Template Name: User Reviews
*/
?>
Set up the Form
This will be the form to submit feedback. I’m not going to worry about styling very much with this form, this will just be a very basic submission form.
<form action="<?php the_permalink(); ?>#submission" method="post">
<div>
<!-- This is where your warning messages will go. -->
</div>
<label for="firstname">First Name*</label>
<input name="rev_fname" type="text" value="<?php echo wp_kses($firstname, 'none'); ?>" placeholder="John" />
<label for="lastname">Last Name*</label>
<input name="rev_lname" type="text" value="<?php echo wp_kses($lastname, 'none'); ?>" placeholder="Doe" />
<label for="email">Email</label>
<input name="rev_email" type="text" value="<?php echo wp_kses($email, 'none'); ?>;" placeholder="[email protected]" />
<label for="rating">Rating (out of 5)*</label>
<select id="rating" name="rating">
<option value="null">0</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option selected="selected" value="5">5</option>
</select>
<label for="firstname">Comments on Review*</label>
<textarea name="rev_comment" rows="7" placeholder="Tell us the reason behind your rating..."><?php echo wp_kses($content, 'none'); ?>;</textarea>
<div>
<!-- This is where your CAPTCHA will go. -->
</div>
<input id="action" name="action" type="submit" value="submit" />
</form>
Let’s break this down:
form action="<?php the_permalink(); ?>#submission"
-We are submitting the form to itself usingthe_permalink();
function in WordPress. Then we add a local anchor tag called submission because if the form is at the bottom of the page, upon submission we want to page to “load” at the local anchor for usability.- Warning messages –We will add these later as the comment implies.
wp_kses()
-This is a form of stripping dangerous tags WordPress provides. It allows certain HTML element names, attribute names and more. If you’re interested in the specifics read the docs. The'none'
value that I pass into the function is telling it to allow no protocols. You don’t want links passed into your forms.- CAPTCHA –This will also be set up later, but for now we have a place for it.
input type="submit"
-Make sure you have both theinput type="submit"
and theform method="post"
Adding Variables
My recommendation whenever adding variables that relate to a $_POST
or $_REQUEST
kind of action, is to always put them in a conditional isset()
statement. This is because by default isset()
determines whether a variable is null, or set, kinda like the name of the function suggests. For more information here are the docs.
In order to test what your form is going to be submitting do a simple test by adding the following snippet above your form:
<?php
echo '<pre>';
print_r($_POST);
echo '</pre>';
?>
When you refresh the page you will see:
Array
(
)
That is to be expected. Since you have not submitted anything yet the $_POST
variable is not yet set. In order to test if you can submit feedback, enter some bologna information and hit submit, you should see something that resembles this:
Array
(
[rev_fname] => firstname
[rev_lname] => lastname
[rev_email] => email
[rating] => 3
[rev_comment] => Text area field
[action] => submit
)
This is also expected, yes, even the value of submit. We have not yet set up a CAPTCHA, but when we do, that value will submit as well. Then we’ll need to debug using this technique to find out what that is going to be, but more on that later.
For now, let’s get back to setting our variables. In order to set our variables we are going to have to use array notation. This is because, using the above example, [rev_fname]
is not an object, it’s a string. So to access this we simply need to use our $_POST
variable to access it, for example: $_POST['rev_fname']
is how we’ll use it with isset()
.
We will attempt to be handling two cases from now on out, the first way is if you’re not using ACF to submit feedback, and the second is if you’re relying on it for your reviews. I’ll try to integrate both into the rest of the post. So let’s say you have ACF Fields that are first name, last name, email address, and rating. Then you’re just using the default WordPress content block as the review content. Now, using the printed array from above, let’s set some variables:
if( isset( $_POST['rev_fname'] ) ) { $firstname = $_POST['rev_fname']; } else { $firstname = null; }
if( isset( $_POST['rev_lname'] ) ) { $lastname = $_POST['rev_lname']; } else { $lastname = null; }
if( isset( $_POST['rev_email'] ) ) { $email = $_POST['rev_email']; } else { $email = null; }
if( isset( $_POST['rating'] ) ) { $rating = $_POST['rating']; } else { $rating = null; }
if( isset( $_POST['rev_comment'] ) ) { $content = $_POST['rev_comment']; } else { $content = null; }
if( isset( $_POST[''])) { $captcha = $_POST['']; } else { $captcha = null; }
Great. Now we have our variables set, except for the CAPTCHA, but that will just be a placeholder for now. If you’re more advanced you can use the shorthand if-else syntax of:
( isset( $_POST[''] ) ) ? $captcha = $_POST[''] : $captcha = null;
If you’re new at shorthand, here is a good Stack Overflow Answer about it.
Have WordPress do the Work
Ready the fan-fare, because this is the best part of being able to submit feedback using WordPress. We are going to use the wp_insert_post()
function. This is the description in the codex:
This function inserts posts (and pages) in the database. It sanitizes variables, does some checks, fills in missing variables like date/time, etc. It takes an array as its argument and returns the post ID of the created post (or 0 if there is an error).
The documentation is kinda muddy but here is the gist of it in the context that we need it:
$post_id = wp_insert_post(array (
'post_type' => 'reviews',
'post_title' => "Review from ".$firstname." ".$lastname,
'post_status' => 'draft',
'comment_status' => 'closed', // if you prefer
'ping_status' => 'closed', // if you prefer
));
Okay, so let’s break this down. First we declare a variable called $post_id
and set it to the array of wp_insert_post()
. We have set the post type to reviews
, which is the post type we have established. Then we name the post title Review from $firstname $lastname
. When we access the dashboard this will label the new post that gets created. If you want a more relevant call to action you can say [NEW ATTN REQ] Review from $firstname $lastname
. Then the next step is we save it as a draft, because we want to be able to make sure it’s not a spammer.
Using Advanced Custom Fields
If you’re not using ACF then you can skip to the next section. If you are, stick around, because this next part is required for you to submit feedback to the fields in your dashboard. Since ACF is built on the premise of custom fields or meta-data we will want some non-manual way to enter the fields. Luckily WordPress saves the day again by providing such a function called add_post_meta()
it can be a little tricky to use with validation, but more on that later.
The usage is as follows: add_post_meta($post_id, $meta_key, $meta_value, $unique);
- The
$post_id
is the ID of the post to insert the values into. Since we want to do it per-post-type we will use the variable we declared called$post_id
, and pass it in as the first parameter of the function. - The
$meta_key
is next, to discover your meta key go grab your ACF meta key, you can find this in your Dashboard > Custom Fields and under the field group you’re targeting, you’ll find the field label and field name. You want to use the field name. - The
$meta_value
is the user input, so for an extra layer of sanitation we’ll pass inwp_kses($firstname, 'none')
as the value for that parameter.
Once we have built that both functions should look something like this:
$post_id = wp_insert_post(array (
'post_type' => 'reviews',
'post_title' => "Review from ".$firstname." ".$lastname,
'post_status' => 'draft',
'comment_status' => 'closed', // if you prefer
'ping_status' => 'closed', // if you prefer
));
if ($post_id) {
// insert post meta
add_post_meta($post_id, 'first_name', wp_kses($firstname, 'none'));
add_post_meta($post_id, 'last_name', wp_kses($lastname, 'none'));
add_post_meta($post_id, 'email', wp_kses($email, 'none'));
add_post_meta($post_id, 'rating', wp_kses($rating, 'none'));
}
Implement Validation
By this point the form should be just about ready to go. Upon testing it, you should be able to see posts coming in, at the same time this should make you a little nervous. If a bot hits your site and tries to submit feedback, you’re going to get a bunch of junk.
I have done a little research on CAPTCHA, and have found that Google’s Re-Captcha is pretty good. So you’ll need to register a new site and obtain an API key from them. It’s pretty self-explanatory, so I won’t go too much into the set up except for the $_POST
portion of it.
After this point I’m going to assume you have registered your site, put the script in the appropriate place (after you sign up there are instructions) and are able to see the CAPTCHA on your site. Remember the comment in our form that says <!-- This is where your CAPTCHA will go. -->
. This is where you’ll place the div
that Google provided you.
On the other comment that says <!-- This is where your warning messages will go. -->
, you’ll now want to insert:
<?php if( $warning_response !== null ) { echo $warning_response; }
elseif( $falure_respnse !== null ) { echo $falure_response; }
elseif( $success_response !== null ) { echo $success_response; } ?>
After all this is done, note that the value you’re going to be getting from the $_POST
variable is g-recaptcha-response
. So let’s add that into our variables we previously set.
if( isset( $_POST['rev_fname'] ) ) { $firstname = $_POST['rev_fname']; } else { $firstname = null; }
if( isset( $_POST['rev_lname'] ) ) { $lastname = $_POST['rev_lname']; } else { $lastname = null; }
if( isset( $_POST['rev_email'] ) ) { $email = $_POST['rev_email']; } else { $email = null; }
if( isset( $_POST['rating'] ) ) { $rating = $_POST['rating']; } else { $rating = null; }
if( isset( $_POST['rev_comment'] ) ) { $content = $_POST['rev_comment']; } else { $content = null; }
if( isset( $_POST['g-recaptcha-response'])) { $captcha = $_POST['g-recaptcha-response']; } else { $captcha = null; }
Okay, now comes the fun part. You need to account for three different scenarios of success for the captcha.
if() {
//the warning case
} elseif() {
//the failure case
//the success case
}
Great, now that the framework is down, we need to figure out the conditions. The first condition is to check if the g-recaptcha-response
if not null (meaning $_POST
has been submitted), and then by putting the bang in front of the variable for $captcha
we’re turning it into a Boolean statement. If the number, array, or string is not empty it will return as true. Next, we set a variable called $warning_response
so we can access and display it if the condition is right. This is what the code looks like:
if(($_POST['g-recaptcha-response'] !== null) && (!$captcha)) {
$warning_response =
'<div>
<p>It looks like you may not have done the captcha.</p>
</div>';
} elseif() {
//the failure case //the success case
}
Now on to the elseif-statement. There will be two cases inside. The first case will hit if something fails the CAPTCHA test, or on the very off-chance, an unlucky person. So we want to make sure we offer reassurance if it made a mistake in failing a human. After all, we’re trying to submit feedback and if the user gets failed, they might have second thoughts about giving good feedback; if they were leaving bad feedback you may have just helped them get more content for their review! In any case, we want to check, once again, for a non-null g-captcha-response
. This means the form was submitted, however, we wanted to check for failure first. Then we want to execute the wp_insert_post()
and add_post_meta()
functions within the success case. Inside this elseif-statement we also want to check for the proper API key that you set up earlier. Let’s take a look at the code:
if(($_POST['g-recaptcha-response'] !== null) && (!$captcha)) {
$warning_response =
'<div>
<p>It looks like you may not have done the captcha.</p>
</div>';
} elseif( $_POST['g-recaptcha-response'] !== null ) {
$response=file_get_contents("https://www.google.com/recaptcha/api/siteverify?secret=<YOUR API KEY HERE>&response=".$captcha."&remoteip=".$_SERVER['REMOTE_ADDR']);
if($response.success==false) {
$failure_response = '
'<div>
<p>Your review was not submitted. This might mean you're a spammer, if this is a mistake, please let me know.</p>
</div>';
} else {
$success_response = '
'<div>
<p>Thank you for taking the time to submit a recommendation. I will review it, and post it very shortly.</p>
</div>';
$post_id = wp_insert_post(array (
'post_type' => 'reviews',
'post_title' => "Review from ".$firstname." ".$lastname,
'post_status' => 'draft',
'comment_status' => 'closed', // if you prefer
'ping_status' => 'closed', // if you prefer
));
if ($post_id) {
// insert post meta
add_post_meta($post_id, 'first_name', wp_kses($firstname, 'none'));
add_post_meta($post_id, 'last_name', wp_kses($lastname, 'none'));
add_post_meta($post_id, 'email', wp_kses($email, 'none'));
add_post_meta($post_id, 'rating', wp_kses($rating, 'none'));
}
}
}
We are setting a variable called $response
to see what we get back from Re-Captcha. We need to access our verified site’s API, so replace <YOUR API KEY HERE>
with your actual API key. Then we’re submitting our $captcha
variable as true or false depending on what the CAPTCHA returns on $_POST
. We also include our server address.
Then on failure, or if response success is returned false it will most likely be a spammer, but we’re not sure. So we don’t want to give out any personal information. Since the person will likely know us, we can simply say please let me know if this is a mistake. You can write whatever suits your needs the best here.
On success we want to display a confirmation as well as submit feedback data to a new post.
Submit Feedback and Wrap Up
You should be well on your way to using ACF to submit feedback in no time. Other things you can do are use FontAwesome or some other symbol font to place stars based on the rating number the reviewer submits. Also, for bonus points how could you use the wp_create_nonce()
function and the wp_verify_nonce()
to make this process even less susceptible to spam? Also, what are your experiences using wp_insert_post()
and the add_post_meta()
function? Leave your responses in the comments, I’d love to hear them.