Wordpress - Front end form to create a custom post with preview
There are many ways you could use to reach your goal. Here's one...
Steps:
- Create a shortcode that renders the form.
- Create and enqueue a JavaScript file that handles the form submission.
- Create PHP function for creating/updating Post/Custom Post.
In your functions.php:
/**
* @return string $html HTML form.
*/
function shortcode__new_post_form() {
/**
* @var WP_User $current_user
*/
$current_user = $GLOBALS['current_user'];
ob_start(); ?>
<form action="" id="form-new-post">
<fieldset>
<legend>NEW AWESOME POST</legend>
<div class="form-group">
<input type="text" class="form-control" name="post_title" required/>
</div>
<input type="hidden" name="ID" value=""/>
<input type="hidden" name="post_author" value="<?php echo $current_user->ID; ?>"/>
<button type="submit"
class="submit"
data-is-updated="false"
data-is-update-text="UPDATE">CREATE
</button>
</fieldset>
<a href=""
class="preview-link"
target="_blank"
style="display: none;"
rel="nofollow">Preview Link</a>
</form>
<?php
$html = ob_get_clean();
return $html;
}
function script__new_post_form() {
wp_enqueue_script(
'new-post-form',
// Insert here your JavaScript file URL,
array( 'jquery' ),
'1.0.0',
true
);
wp_localize_script(
'new-post-form',
'localized_new_post_form',
array(
'admin_ajax_url' => admin_url( 'admin-ajax.php' ),
)
);
}
function maybe_insert_new_post() {
/**
* @var array $r Initialize response variable.
*/
$r = array(
'error' => '', // Error message.
'html' => '', // Any message/HTML you want to output to the logged in user.
'preview_link' => '', // Preview link URL.
'post' => '' // The created/updated post.
);
/**
* @link https://developer.wordpress.org/reference/functions/wp_insert_post/
*/
$postarr = array(
'ID' => '', // If ID stays empty the post will be created.
'post_author' => '',
'post_title' => 'My name is Optimus Prime',
'post_status' => 'draft',
'post_type' => 'post',
'meta_input' => array( // Delete this line if you won't use it!
'your_NON_acf_meta_field_key' => 'your_NON_acf_meta_field_value'
)
);
parse_str( $_POST['form_data'], $form_data );
$postarr = array_merge( $postarr, $form_data );
/**
* wp_insert_post can either create posts or update existing ones, if ID is passed!
*
* @link https://developer.wordpress.org/reference/functions/wp_insert_post/
*
* @param array $postarr An array of elements that make up a post to update or insert.
* @param bool $wp_error Whether to return a WP_Error on failure.
*
* @return int|WP_Error The post ID on success. The value 0 or WP_Error on failure.
*/
$new_post = wp_insert_post(
$postarr,
true
);
// Post was not created/updated, so let's output the error message.
if ( is_wp_error( $new_post ) ) {
$r['error'] = $new_post->get_error_message();
echo json_encode( $r );
exit;
}
$post_id = $new_post; // Just for reference.
/**
* To save ACF fields use update_field() function. It doesn't matter if it's text field, repeater field, etc.
* Make sure the field exists in admin area.
* Use update_field() as many times as you want.
*
* @link https://www.advancedcustomfields.com/resources/update_field/
*/
update_field( 'your_acf_meta_key', 'field_value', $post_id );
// update_field( 'your_acf_meta_key', 'field_value', $post_id );
// update_field( 'your_acf_meta_key', 'field_value', $post_id );
/**
* @link https://developer.wordpress.org/reference/functions/get_preview_post_link/
*/
$preview_link = get_preview_post_link( $post_id );
if ( $preview_link ) {
$r['preview_link'] = $preview_link;
}
// Gets post info in array format as it's easier to debug via console if needed.
$post_array = get_post( $post_id, ARRAY_A );
if ( $post_array ) {
$r['post'] = $post_array;
}
echo json_encode( $r );
exit;
}
// Ads shortcode so you can use the form anywhere you want.
add_shortcode( 'new_post_form', 'shortcode__new_post_form' );
// Use wp_enqueue_scripts action hook so you can correctly localize the script with admin ajax URL.
add_action( 'wp_enqueue_scripts', 'script__new_post_form' );
// Prefix 'wp_ajax_' is mandatory.
add_action( 'wp_ajax_new_post', 'maybe_insert_new_post' );
Create a JavaScript file and write in it (don't forget to put its URL in your functions.php):
(function ($) {
var el_form = $('#form-new-post'),
el_form_submit = $('.submit', el_form);
// Fires when the form is submitted.
el_form.on('submit', function (e) {
e.preventDefault();
el_form_submit.attr('disabled', 'disabled');
new_post();
});
// Ajax request.
function new_post() {
$.ajax({
url: localized_new_post_form.admin_ajax_url,
type: 'POST',
dataType: 'json',
data: {
action: 'new_post', // Set action without prefix 'wp_ajax_'.
form_data: el_form.serialize()
},
cache: false
}).done(function (r) {
if (r.post !== '' && r.preview_link !== '') {
$('[name="ID"]', el_form).attr('value', r.post.ID);
$('.preview-link', el_form)
.attr('href', r.preview_link)
.show();
el_form_submit.attr('data-is-updated', 'true');
el_form_submit.text(el_form_submit.data('is-update-text'));
}
el_form_submit.removeAttr('disabled');
});
}
// Used to trigger/simulate post submission without user action.
function trigger_new_post() {
el_form.trigger('submit');
}
// Sets interval so the post the can be updated automatically provided that it was already created.
setInterval(function () {
if (el_form_submit.attr('data-is-updated') === 'false') {
return false;
}
trigger_new_post();
}, 5000); // Set to 5 seconds.
})(jQuery);
Now, create a new page and insert the shortcode [new_post_form]
in it. Open the page and test your form.
If it works for you, please accept my answer as your solution.