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 🙂