This is pretty simple. So simple you need to make sure your guests don't insert bad code into you DB. So read up on Data Validation and Validating Sanitizing and Escaping User Data before you add anything to your site from a front-end form.
- Create a new page at
/new-post
- Create a page template to target that page
- Setup AJAX actions
- Render your form inside the custom page template.
- Use jQuery to submit the form details to AJAX
- AJAX action will validate the data
- If good, the new post will be created
- AJAX will output a success or fail response
- jQuery on the front-end form will inform the user of success or failure.
First, create a page called new-post
that will hold your form. Then create a page template to target that page using the file structure page-{slug}.php
.
page-new-post.php
On that page you can check to see if is_user_logged_in and if they have the ability to create posts using current_user_can. If not, you can always wp_redirect elsewhere or just wp_die.
You'll need to do all this with AJAX so create a front-end form that when clicked; submits data to WP, validates, and creates a new post.
Take note of _nopriv
which you don't want to use in your case because someone will SPAM your site to a crawl.
// AJAX for logged in users
add_action( 'wp_ajax_create_new_post', 'ajax_create_new_post_action' );
// AJAX for non-logged in users
add_action( 'wp_ajax_nopriv_create_new_post', 'ajax_nopriv_create_new_post_action' );
Once you've collected the data and sanitized it in your ajax_create_new_post_action
then you'll need to create a new post with wp_insert_post.
Since there are quite a few steps involved I recommend generating most of this automatically using WP Secure Forms and filling in the gaps after. Here is an example of an AJAX email submission form to give you a pretty good overview of the AJAX parts -- including sanitization.
Title {30 characters limit}
> * 30
| Your Title
! Field specific error message
Textarea{150 characters limit}
> 150
| Content
|
|
! Field specific error message
This label is invisible
> H
Form
This script goes into the PHP file of your theme.
<p id="wpse_form_message_wrap" class="secureforms-message-wrap"></p>
<form id="wpse_form" method="post">
<div id="wpse_form_10000-wrapper">
<label for="wpse_form_10000">* Title <span>30 characters limit</span></label>
<input type="text" name="wpse_form_10000" id="wpse_form_10000" value="" placeholder="Your Title" required="required" maxlength="30" />
<p class="secureforms-error-msg">Field specific error message</p>
</div>
<div id="wpse_form_20000-wrapper">
<label for="wpse_form_20000">Textarea{150 characters limit}</label>
<textarea rows="3" name="wpse_form_20000" id="wpse_form_20000" value="" maxlength="150" ></textarea>
<p class="secureforms-error-msg">Field specific error message</p>
</div>
<div id="wpse_form_30000-wrapper" class="secureforms-hidden-wrapper">
<input id="wpse_form_30000" name="wpse_form_30000" type="hidden">
</div>
<div id="wpse_form_footer">
<input type="hidden" id="check_wpse_form" name="check_wpse_form" value="" />
<input type="hidden" name="action" value="wpse_form" />
<?php echo wp_nonce_field('wpse_form', '_nonce_eklwu', true, false); ?>
<input type="submit" name="wpse_form_submit_btn" id="wpse_form_submit_btn" value="Submit" />
</div>
</form>
Functions.php
This one goes into your functions.php
// WP SECURE FORMS - EMAIL VALIDATION & SENDING
require_once( 'ajax/wpse_form.php' );
// WP SECURE FORMS - ENQUEUE EMAIL JS
function enqueue_ajax_wpse_form() {
if (!is_admin()) {
wp_enqueue_script( 'ajax_wpse_form', get_template_directory_uri().'/ajax/wpse_form.js', array('jquery'), '', true );
wp_localize_script( 'ajax_wpse_form', 'ajax_wpse_form', array( 'ajax_url' => admin_url( 'admin-ajax.php' ) ) );
}
}
add_action( 'wp_enqueue_scripts', 'enqueue_ajax_wpse_form', 999 );
Validation
In your theme folder create an "ajax" folder with the file named wpse_form.php. Paste into it the code below.
<?php
function ajax_wpse_form_action() {
if ($_SERVER["REQUEST_METHOD"] == "POST"){
$return_message = '';
$status = 'success';
$fields_with_errors = array();
// validate nonce
if(!wp_verify_nonce($_POST['_nonce_eklwu'], $_POST['action'])){
$status = 'error';
}
// validate hidden field
if(!empty(trim($_POST['check_wpse_form']))){
$status = 'error';
}
if ($status == 'error') {
$return_message = 'Data verification error. Check marked fields.';
} else {
$wpse_form_10000 = strip_tags(trim(stripslashes($_POST['wpse_form_10000'])));
if(!empty($wpse_form_10000)){
if(strlen($wpse_form_10000) > 30){
$status = 'error';
$fields_with_errors[] = 'wpse_form_10000';
}
} else {
$status = 'error';
$fields_with_errors[] = 'wpse_form_10000';
}
$wpse_form_20000 = strip_tags(trim(stripslashes($_POST['wpse_form_20000'])));
if(!empty($wpse_form_20000)){
if(strlen($wpse_form_20000) > 150){
$status = 'error';
$fields_with_errors[] = 'wpse_form_20000';
}
}
$wpse_form_30000 = strip_tags(trim(stripslashes($_POST['wpse_form_30000'])));
if ($status == 'error') {
$return_message = 'Data verification error. Check marked fields.';
} else {
// message
$to = '[email protected]';
$header = 'From: '. get_bloginfo('name') . ' <[email protected]>'.PHP_EOL;
$subject = 'Test Email Subject';
$formMessage = '';
$formMessage .= 'Title {30 characters limit}' . "\n";
$formMessage .= $wpse_form_10000 . "\n\n";
$formMessage .= 'Textarea{150 characters limit}' . "\n";
$formMessage .= $wpse_form_20000 . "\n\n";
$formMessage .= 'This label is invisible' . "\n";
$formMessage .= $wpse_form_30000 . "\n\n";
if ( wp_mail($to, $subject, $formMessage, $header) ) {
$return_message = 'Thank you for contacting us. We will get in touch as soon as possible.';
} else {
$status = 'error';
$return_message = 'There was an error sending the message. Please try again.';
}
}
}
$resp = array(
'status' => $status,
'return_message' => $return_message,
'fields_with_errors' => $fields_with_errors,
);
header( "Content-Type: application/json" );
echo json_encode($resp);
die();
} else {
http_response_code(403);
}
}
add_action( 'wp_ajax_wpse_form', 'ajax_wpse_form_action' );
add_action( 'wp_ajax_nopriv_wpse_form', 'ajax_wpse_form_action' );
AJAX
In your theme folder create an "ajax" folder with the file named wpse_form.js. Paste into it this code.
jQuery(document).ready(function($) {
var wpse_form_btn = $('#wpse_form_submit_btn');
function init_wpse_form(){
/* VARS */
var form = $('#wpse_form'),
type = form.attr('method'),
requiredFields = ['wpse_form_10000 | textline'];
/* FUNCTIONS */
function showErrors(fieldsWithErrors){
form.find('.hasError').removeClass('hasError').end().find('.secureforms-error-msg.active').removeClass('active');
for(var i=0; i< fieldsWithErrors.length; i++){
if(fieldsWithErrors[i].length > 0){
$('#' + fieldsWithErrors[i]).addClass('hasError').next().addClass('active');
}
}
}
/* TRIGGER */
wpse_form_btn.on('click', function(e){
e.preventDefault();
e.stopPropagation();
if($('#check_wpse_form').val()){
return false;
} else {
var emptyErrors = [];
for(var i = 0; i<requiredFields.length; i++){
var fieldData = requiredFields[i].split(' | '),
field = $('#' + fieldData[0]),
fieldType = fieldData[1];
if(fieldType == 'select'){
var selected = field.find(':selected');
if(selected.length > 0){
if(selected.val() == 'wpse_form_select_null'){
emptyErrors.push(fieldData[0]);
}
} else {
emptyErrors.push(fieldData[0]);
}
} else if(fieldType == 'radio' || fieldType == 'checkbox'){
if(field.find('input:checked').length <= 0){
emptyErrors.push(fieldData[0]);
}
} else {
if(!field.val()){
emptyErrors.push(fieldData[0]);
}
}
}
if(emptyErrors.length > 0){
showErrors(emptyErrors);
$('#wpse_form_message_wrap').removeClass('success').addClass('error').text('Please fill all the required fields');
return false;
} else {
var data = form.serialize();
$.ajax({
type: type,
url: ajax_wpse_form.ajax_url,
data: data,
dataType: 'json',
success: function(response) {
if (response.status == 'success') {
$('#wpse_form_message_wrap')
.removeClass('error')
.addClass('success')
.text(response.return_message);
showErrors([]);
} else {
$('#wpse_form_message_wrap')
.removeClass('success')
.addClass('error')
.text(response.return_message);
showErrors(response.fields_with_errors);
}
},
error: function(xhr,err){
console.log("readyState: "+xhr.readyState+"\
status: "+xhr.status);
console.log("responseText: "+xhr.responseText);
}
})
}
}
});
};
if(wpse_form_btn.length > 0){
init_wpse_form();
}
});
JS
Paste this code into your theme's main js file.
$('body').on('click', 'input[type=radio]', function(){
var wrapper = $(this).parent(),
triggers = wrapper.find('.isTrigger');
if(triggers.length > 0){
triggers.each(function(){
if($(this).is(':checked')){
$('.' + $(this).attr('data-toggle')).slideDown(200);
} else {
$('.' + $(this).attr('data-toggle')).slideUp(200);
}
})
}
})
$('body').on('click', 'input[type=checkbox]', function(){
var that = $(this),
wrapper = that.parent(),
limit = wrapper.attr('data-limit'),
chosen = wrapper.find('input:checked').length;
// disabling / enabling choices
if(that.is(':checked')){
if(chosen + 1 > limit){
wrapper.find('input').not(':checked').prop('disabled', true);
}
} else {
wrapper.find('input').prop('disabled', false);
}
// conditional showing / hiding fields
if(that.hasClass('isTrigger')){
var targetClass = that.attr('data-toggle');
if(that.is(':checked')){
$('.' + targetClass).slideDown(200);
} else {
$('.' + targetClass).slideUp(200);
}
}
})
$('body').on('change', 'select', function(){
var that = $(this),
wrapper = that.parent(),
triggers = wrapper.find('.isTrigger'),
options = wrapper.find('option');
if(triggers.length > 0){
options.each(function(){
if($(this).is(':selected')){
if($(this).hasClass('isTrigger')){
$('.' + $(this).attr('data-toggle')).slideDown(200);
}
} else {
if($(this).hasClass('isTrigger')){
$('.' + $(this).attr('data-toggle')).slideUp(200);
}
}
})
}
})
CSS
Paste the code below into your theme's main css file.
form>div, form>p{
margin-top: 0;
margin-bottom: 1em;
}
form fieldset {
margin: 0;
border: none;
padding: 0;
}
form label, form legend{
display: block;
margin-bottom: .25em;
}
form label span, form legend span{
font-size: .8em;
font-style: italic;
}
form label span::before, form legend span::before{
content: '';
display: block;
}
input[type="checkbox"]+label, input[type="radio"]+label, input[type="number"]+label{
display: inline-block;
}
form .showOnTrigger{
display: none;
}
.secureforms-error-msg{
display: none;
color: red;
}
.secureforms-error-msg.active{
display: block;
}
.secureforms-hidden-wrapper{
display: none;
}
.secureforms-message-wrap.error{
border: 2px solid red;
}
.secureforms-message-wrap.success{
border: 2px solid green;
}