Hopefully the code will be sufficient to describe the key points, but please do comment if you have any further questions:
<?php
class WPSE_Submit_From_Front {
const NONCE_VALUE = 'front_end_new_post';
const NONCE_FIELD = 'fenp_nonce';
protected $pluginPath;
protected $pluginUrl;
protected $errors = array();
protected $data = array();
function __construct() {
$this->pluginPath = plugin_dir_path( __file__ );
$this->pluginUrl = plugins_url( '', __file__ );
add_action( 'wp_enqueue_scripts', array( $this, 'addStyles' ) );
add_shortcode( 'post_from_front', array( $this, 'shortcode' ) );
// Listen for the form submit & process before headers output
add_action( 'template_redirect', array( $this, 'handleForm' ) );
}
function addStyles() {
wp_enqueue_style( 'submitform-style', "$this->pluginUrl/submitfromfront.css" );
}
/**
* Shortcodes should return data, NOT echo it.
*
* @return string
*/
function shortcode() {
if ( ! current_user_can( 'publish_posts' ) )
return sprintf( '<p>Please <a href="https://wordpress.stackexchange.com/questions/210648/%s">login</a> to post links.</p>', esc_url( wp_login_url( get_permalink() ) ) );
elseif ( $this->isFormSuccess() )
return '<p class="success">Nice one, post created.</p>';
else
return $this->getForm();
}
/**
* Process the form and redirect if sucessful.
*/
function handleForm() {
if ( ! $this->isFormSubmitted() )
return false;
// http://php.net/manual/en/function.filter-input-array.php
$data = filter_input_array( INPUT_POST, array(
'postTitle' => FILTER_DEFAULT,
'location2' => FILTER_DEFAULT,
'postContent' => FILTER_DEFAULT,
));
$data = wp_unslash( $data );
$data = array_map( 'trim', $data );
// You might also want to more aggressively sanitize these fields
// By default WordPress will handle it pretty well, based on the current user's "unfiltered_html" capability
$data['postTitle'] = sanitize_text_field( $data['postTitle'] );
$data['location2'] = sanitize_text_field( $data['location2'] );
$data['postContent'] = wp_check_invalid_utf8( $data['postContent'] );
$this->data = $data;
if ( ! $this->isNonceValid() )
$this->errors[] = 'Security check failed, please try again.';
if ( ! $data['postTitle'] )
$this->errors[] = 'Please enter a title.';
if ( ! $data['postContent'] )
$this->errors[] = 'Please enter the content.';
if ( ! $this->errors ) {
$post_id = wp_insert_post( array(
'post_title' => $data['postTitle'],
'post_content' => $data['postContent'],
'post_status' => 'publish',
));
if ( $post_id ) {
add_post_meta( $post_id, 'location2', $data['location2'] );
// Redirect to avoid duplicate form submissions
wp_redirect( add_query_arg( 'success', 'true' ) );
exit;
} else {
$this->errors[] = 'Whoops, please try again.';
}
}
}
/**
* Use output buffering to *return* the form HTML, not echo it.
*
* @return string
*/
function getForm() {
ob_start();
?>
<div id ="frontpostform">
<?php foreach ( $this->errors as $error ) : ?>
<p class="error"><?php echo $error ?></p>
<?php endforeach ?>
<form id="formpost" method="post">
<fieldset>
<label for="postTitle">Post Title</label>
<input type="text" name="postTitle" id="postTitle" value="<?php
// "Sticky" field, will keep value from last POST if there were errors
if ( isset( $this->data['postTitle'] ) )
echo esc_attr( $this->data['postTitle'] );
?>" />
</fieldset>
<fieldset>
<label for="postContent">Content</label>
<textarea name="postContent" id="postContent" rows="10" cols="35" ><?php
if ( isset( $this->data['postContent'] ) )
echo esc_textarea( $this->data['postContent'] );
?></textarea>
</fieldset>
<fieldset>
<button type="submit" name="submitForm" >Create Post</button>
</fieldset>
<?php wp_nonce_field( self::NONCE_VALUE , self::NONCE_FIELD ) ?>
</form>
</div>
<?php
return ob_get_clean();
}
/**
* Has the form been submitted?
*
* @return bool
*/
function isFormSubmitted() {
return isset( $_POST['submitForm'] );
}
/**
* Has the form been successfully processed?
*
* @return bool
*/
function isFormSuccess() {
return filter_input( INPUT_GET, 'success' ) === 'true';
}
/**
* Is the nonce field valid?
*
* @return bool
*/
function isNonceValid() {
return isset( $_POST[ self::NONCE_FIELD ] ) && wp_verify_nonce( $_POST[ self::NONCE_FIELD ], self::NONCE_VALUE );
}
}
new WPSE_Submit_From_Front;