How to Submit WordPress Posts from the Frontend

You might want add new posts without having to log into the WordPress dashboard, or maybe allow your visitors a way to submit content of their own. You can do it. Figuring out how to submit a post from the front end is straightforward. In this article, we’ll cover a few ways you can create a new post form and save its results into a real, live WordPress post.

Accepting user submitted posts from the public-side of WordPress site isn’t the right solution to most problems, but it’s helpful in a few specific situations.

The big benefit of hand-rolling a front-end submission and posting plugin for WordPress is that you can trim all unnecessary features. The big downside is that you’ll be writing code. A few already-written plugin solutions are highlighted in the “Looking for a Complete Front-End Post Submissions Plugin for WordPress?” section below. These have the big benefit that if you’re not comfortable with code, or want more robust anti-spam features, you’ll be all set without a lot of complexity otherwise.

But without further-ado, let’s get to understanding how to accept user submitted posts in your WordPress site!

Why You Might (Not) Want to Allow User-Submitted Posts in WordPress

I’m sure someone who is reading this is hoping that they can just get lots of free high quality content on their WordPress site by letting random visitors submit their content. I wouldn’t say that’s not going to happen, but I’d counsel you not to count on it. I think you’d get way more spam submissions from bots than you would get content you cared about by allowing any and all users to create a post from the front end.

That said, there are a few reasons I’d think you may really want this functionality:

  • You have some contributors to your site who you don’t want to give admin accounts, but who you trust to write good (non-spam content).
  • You’re wanting to allow for the serendipity of the possibility that I’m wrong and that the spam submission will be minimal.
  • You’ll put this feature on an intranet or other private or protected site or page, so that you can easily not sweat the possibility of spammers finding it.
  • You have occasional emails from dedicated readers which would make great posts if you cut yourself out of the process.

3 Essential Steps for Making a Form for User Submitted Posts in WordPress

Basically, to allow user-submitted content in WordPress, you must first allow the user to… submit the content! Front end posting is most often done with a form plugin like Ninja Forms or Gravity Forms. Those will have extensions that provide the same functionality we’ll build from scratch here. But for (most of) this article, we’re gonna keep things at the lowest-common-denominator level—we’ll process the form ourselves, and create it with a basic WordPress shortcode.

Here’s the basic step to allowing a post to be created from the front-end of a WordPress site:

  1. Create a form by which a user can submit the post title, content, etc.
  2. When the user “submits” the form, catch the input and validate it as reasonable.
  3. With the “caught” input, use WordPress functions to create the post and save it.

Really, those three steps are all you need to have readers add a post from the front end. They leave aside issues of “spam submissions” and other possible complexities which are real and important.  If you’re deploying this sort of solution for a client, you must consider their long-term happiness with your solution. But they aren’t needed for a “happy path” technical implementation that works, so we’re going to skip them here.

The Basics of an HTML Form for Allowing User Post Submission

As I said above, step one in allowing the submission of user content from the the front-side of your WordPress site starts with HTML. For us to get the HTML to show up, we’re going to use a shortcode in WordPress. Shortcodes are contained in square-brackets, and can often be single tags that pull in another PHP function. That’s what we’ll do here, so our form will appear on a post, page, or other WordPress content type when someone uses [wpshout_frontend_post]. Here’s the full code.

add_shortcode( 'wpshout_frontend_post', 'wpshout_frontend_post' );
function wpshout_frontend_post() {
<div id="postbox">
    <form id="new_post" name="new_post" method="post">

    <p><label for="title">Title</label><br />
        <input type="text" id="title" value="" tabindex="1" size="20" name="title" />

        <label for="content">Post Content</label><br />
        <textarea id="content" tabindex="3" name="content" cols="50" rows="6"></textarea>

    <p><?php wp_dropdown_categories( 'show_option_none=Category&tab_index=4&taxonomy=category' ); ?></p>

    <p><label for="post_tags">Tags</label>

    <input type="text" value="" tabindex="5" size="16" name="post_tags" id="post_tags" /></p>

    <?php wp_nonce_field( 'wps-frontend-post' ); ?>

    <p align="right"><input type="submit" value="Publish" tabindex="6" id="submit" name="submit" /></p>

There’s nothing special with this form really. The most interesting things are the wp_dropdown_categories() and wp_nonce_field() function calls. Because we’re wanting users to set a category (and prevent that dreaded “Uncategorized”, wp_dropdown_categories() creates the list of categories you can select from. You can learn more about the wp_dropdown_categories function on the WordPress Codex.

Everything else you enter into the form will automatically create a new entry, including tags. Make sure no matter what you do, always include the wp_nonce_field(). Verifying nonces is an important WordPress security strategy to prevent what is called a cross-site request forgery (or CSRF) attack. (You can learn more about that in our “WordPress Security Principles” post).

Where Should the Form Submit Its Data To in WordPress?

As written, our shortcode form above will “submit” its data to the same page on which it ran. That can work, and is the simplest overall way to create a form for a shortcode in WordPress. Submitting to either an “Admin-Ajax” or REST API endpoint would also work. But to keep this as simple as possible, we’ll actually just have our above code include a call of our “post saving” function. So what that would look like is the above change to the above code snippet:

add_shortcode( 'wpshout_frontend_post', 'wpshout_frontend_post' );
function wpshout_frontend_post() {
    <!-- here and below is all the same as above -->

Writing that code would, if we just started executing it, create a fatal error. That’s because we must create the wpshout_save_post_if_submitted function.

Capturing the Input from the Front-End User Post Submission Form

Creating a function to save our front-end user content in WordPress would look a little like that:

function wpshout_save_post_if_submitted() {
    // Stop running function if form wasn't submitted
    if ( !isset($_POST['title']) ) {

    // Check that the nonce was set and valid
    if( !wp_verify_nonce($_POST['_wpnonce'], 'wps-frontend-post') ) {
        echo 'Did not save because your form seemed to be invalid. Sorry';

    // Do some minor form validation to make sure there is content
    if (strlen($_POST['title']) < 3) {
        echo 'Please enter a title. Titles must be at least three characters long.';
    if (strlen($_POST['content']) < 100) {
        echo 'Please enter content more than 100 characters in length';

    // Add the content of the form to $post as an array
    $post = array(
        'post_title'    => $_POST['title'],
        'post_content'  => $_POST['content'],
        'post_category' => $_POST['cat'], 
        'tags_input'    => $_POST['post_tags'],
        'post_status'   => 'draft',   // Could be: publish
        'post_type' 	=> 'post' // Could be: `page` or your CPT
    echo 'Saved your post successfully! :)';

This code is bare-bones, but should help you understand. We start the function wpshout_save_post_if_submitted with four different “guard” clauses. A guard clause prevents an error-y submission from proceeding. That’s what the return statements do. I chose, for simplicity, to echo (or show to the user) any errors, and then return. The core functionality here means that a user will always see the “add a new post” form, and that the success or failure message will appear before that in WordPress. Perhaps this is ideal for you, but it may not be.

To get past the guard clauses, we’d have to have submitted the form and had a nonce set. If you submitted the form you’ll do this easily, but if you’re a bad attacker you will not. Then we just make sure that at least a little about the post got set: that the title was at least three characters long, the post content (or “post body”) was at least 100 characters. That’s pretty short content, but it’s the least we can do to cut down on the various unwanted post drafts we’d otherwise get from spam bots.

Then, if those checks pass, we use the wp_insert_post() function to actually create the post by passing in an associative array of the post content. So the post title will become the post_title element of the $post array. And so on. It’s very noteworthy that our last two lines there are a post_status and post_type. If you wanted to make these frontend user submitted posts publish immediately, you’ll make the status into publish. And you want this form to allow visitors to create WordPress pages instead, you’ll change the post_type to page. (So too with a “custom post type” or CPT that you created already.)

Looking for a Complete Front-End Post Submission WordPress Plugin?

As I mentioned above, there are a few big issues with using all the above code for allow front end posting. Spam is one of the big ones—our only protection is that if you keep this code making the new posts into drafts, you’ll be protected by them only going live after you’ve approved (“Published”) the drafts.

The other big downside: You’re also forced to write code where good alternative versions exist. Most form plugins—Gravity Forms, Ninja Forms, etc—have this functionality close-at-hand, and there are also a number of plugins that do just this.

Here’re some different ways to accomplish your goal of allowing user-submitted posts on a WordPress website, and how they’re better than our code:

  • User Submitted Posts WordPress plugin (Free) — This works as a shortcode, much like the code we have above. The big advantage it has over our version: USP has built in Google reCAPTCHA and a few other anti-spam measures. While there are other benefits, that one looms large.
  • Tutorial on Creating Posts with Gravity Forms. While Gravity Forms costs money (starting at $59 at the time I write this), it’s a popular plugin and most WordPress developers will already have a copy. Plus, this version will be relatively comfortable to customize for those who already use the Gravity interface.
  • Ninja Forms Front-End Posting Plugin ($39). This is a paid extension to the free Ninja Forms plugin. If you like Ninja Forms already, this has similar advantages to the Gravity Forms option: familiar interface, comfortable controls.

There are a lot of other ways to do allow a user to submit a post from the front end. At least a few other free plugins I chose not to link, and probably at least a dozen other paid options. If you have a different favorite forms plugin, I’d first look there for if they have this feature of “front end WordPress content submission” baked in.

You Now Know How to Save WordPress Submitted Posts

We ran through the code required to do a basic form-submission and front-end user submitted post in WordPress first. Hopefully you found some of that content interesting, and useful if you’re bound and determined to do it on your own.

As I said above, I think the times are rare (and generally when you need lots of front-end polish or custom behavior in saving) where you should actually be doing that. For most use case in WordPress today, you’re better off taking advantage of someone else’s work, be it in Ninja Forms, Gravity Forms, WPForms, or the free User Submitted Posts plugin on the WordPress plugin repository. All of those will save you time and energy debugging and fixing issues with the code over time. And that’s a great deal.

Good luck! And may your users write well 🙂

Most Voted
Newest Oldest
Inline Feedbacks
View all comments
August 6, 2019 6:46 am

This work great.. now my question how you set it for admin only?
please let me know thanks!

January 5, 2019 5:08 am

The easier option would be to use a plugin. Since it is submitting from the front-end, I would assume it’s a Wiki style website.

There aren’t much option for creating a WordPress wiki, but there is a plugin called Helpie Wiki which allows ofr front-end submission and editing. Hope this helps people who read are looking for a solution.

Wp Error Fix
November 12, 2018 2:22 am

How can I upload image from the front end submission? I am trying to do that for a custom post type.
If you can show me an example it would be so helpful for me.


Aurovrata Venet
October 17, 2016 3:16 am

You could also use the excellent Contact Form 7 plugin along with the Post My CF7 Form extension plugin ( which will allow you to save any custom forms to a post, including images as featured attachments, and select/checkbox/radio inputs as taxonomies.

Miraz Mac
September 7, 2015 6:25 am

Is there any way to upload/set a featured image?

December 14, 2011 12:02 pm

Great tutorial 🙂 Thanks for sharing 🙂

April 29, 2011 12:55 am

I’ve got most of this working, but I hope you can help with one other thing. I want the user to be able to select multiple categories. I thought I achieved this by setting the category dropdwown to only display children of a certain parent. Then I duplicated that drop down to show children of another parent. That way they can select a category from parent A, and another from parent B.

This didn’t work. If a category is selected it no longer applies that selection. Can you explain how to allow for this sort of multi category drop down selection ability? Thanks!

April 29, 2011 5:41 am
Reply to  Mark

You need to use a single select element and add the attribute to it for multiple. so…
<select multiple=”multiple”>

Then you need to make the php variable set as an array. so you would do something like this in the $post array

‘category’ => array( $catVariable ),

That should do it. not 100% sure that’s all you need to do though.

February 18, 2011 10:32 am

you can also add the image upload?


October 27, 2010 11:40 am

Looks good – actually I am searching for weeks for a good answer – question script that works with WordPress – I’ve seen a good solution that allows user “to post a page” and this is what your code does. As far as I’ve seen you need to be logged in to ‘post a page’ (I checked your demo sites) – ok, I’ll try this out seems to the solution for very simple WP Q&A or user generated pages 😉

thx Heiko

October 23, 2010 2:32 pm

Okay, I got the image upload working, but I’m not able to attach the upload to the post. How do I get the ID of the post being created?

if ($_FILES) {
foreach ($_FILES as $file => $array) {
$newupload = insert_attachment($file,$post_ID);
// $newupload returns the attachment id of the file that
// was just uploaded. Do whatever you want with that now.

Where $post_ID is is where the post id is supposed to go and that should attached the image to the post being created.

October 25, 2010 9:29 pm
Reply to  Erich

Yes it is possible. You need to do something like:

update_post_meta( $post_id, ‘_thumbnail_id’, $thumbnail_id );

Hope this helps out some.

Daniel Almeida
February 1, 2019 6:19 pm
Reply to  Erich

if ( $result && ! is_wp_error( $result ) ) {
$post_id = $result;
echo $post_id;

This works for me.

October 8, 2010 10:15 am

Thanks for the article!

For most posts I use custom fields for images (portfolio images).

Any thought on how to add a file upload field that would add it to a custom field key.

Maybe, add_post_meta()?


brian fidler
September 15, 2010 11:36 pm

How would I modify the code above if I wanted to also submit custom fields with a front end form?

For instance I have a custom field titled event_Cost that I want a user to be able to submit with the rest of the post.


Nathan Hawkes
May 24, 2019 10:00 am
Reply to  brian fidler

Don’t know if you ever found the solution, but for those that haven’t:

To submit meta data, you add an array of ‘meta_items’. It will look something like this:

`’meta_items’ => array(
‘event_cost’ => $_POST[‘event_cost’],
‘meta_field_name’ => $_POST[‘post_field_name’],

August 29, 2010 9:45 pm

I too am getting the perpetual 404 errors and no success actually posting to WP 3.0.1.

Has anyone had success getting this to work?

Also two questions for the group:

1) Has anyone tried to get this to work with the Multi-Site features of 3.0.1?

2) Have you had success posting custom post_types?

I’m wanting users to be able to submit posts JUST of one type and posting them to just the blog that they own…. Any tips/advice are appreciated!