How to submit a new post from outside the WordPress Admin panel

Thesis themes

How to submit a new post from outside the WordPress Administration Panel? That is the question that most of my clients asked me for their situations. Of course, it’s not a trivial question, what will you do if you want to create a job board whereby users could post a job from a specific page? Or you’re running a multiple authors website, and the authors don’t familiar with WordPress admin panel and/or the contact form plugins don’t suit your needs? So by posting this tutorial, I hope you will find a best working solution.

What am I going to do?

To help the new WordPress users can understand my tutorial, I will make this post panel based on a default Twentyten theme, but you can easily implement it to any WordPress theme that you want. My post panel includes two parts: the first part help you make a new post and the second part help you to edit or delete your posts without going to wp-admin section.

Part 1: Submitting Your New Post Outside The Admin Panel

Step 1: Create A New Posting Form For Your WordPress Site.

In this step I will create a newpost.php file in Twentyten directory (the file has a same structure with single.php so you can duplicate single.php file, rename it to newpost.php and then remove anything inside <div id=”content” role=”main”> tag).

To get started, you must tell WordPress knows that you are going to make a new page template by putting in this code:

/*
Template Name: New Post
*/

In this file I used $wpdb->hide_errors() to hide all SQL errors and nocache_headers() to set the headers to prevent caching for the different browsers. A newpost.php file has a main function is displaying your post panel form to users, so it needs a file to process the collected data, it’s form_process.php file (I put this file in “post” directory inside the Twentyten theme, we will work with it later).

Now, let’s code our newpost.php file:

<?php
/*
Template Name: New Post
*/
require_once dirname( __FILE__ ) . '/post/form_process.php'; // process the collected data
$wpdb->hide_errors(); 
nocache_headers();
get_header();
?>
		<div id="container">
			<div id="content" role="main">
				<div id="formbox">
				<?php
					if ($err != "") {
						echo "<p>".$err."</p>";
					}			
				?>
				<?php
					if ($_GET['success'] == "success") {
						echo "<p>Your post was successfully submitted.</p>";
					}
					else { ?>			
						<?php if (is_user_logged_in()) { // checking weather or not the user has logged in.
						?>
						<form action="" method="post" enctype="multipart/form-data">
							<input type="hidden" name="action" value="post" />
							<?php wp_nonce_field( 'new-post' ); ?>
								<p>
									<input type="text" id="post_title" name="post_title" value="<?php echo $post_title;?>" size="60" tabindex="1"/>
									<label for="title">Post Title</label>
								</p>
								
								<p>
									<?php wp_dropdown_categories('show_option_none=Choose Post Category&orderby=name&order=ASC&hide_empty=0&hierarchical=1'); ?>
									<label for="cat">Post Category</label>
								</p>	
								
								<p><label for="post_content">Post Content:</label><br />
									<script type="text/javascript" src="<?php echo get_template_directory_uri(). '/tiny_mce/'; ?>tiny_mce.js"></script>
									<textarea name="post_content" id="post_content" cols=88 rows=20 tabindex="2"><?php echo $post_content; ?></textarea>
										<script type="text/javascript">
										tinyMCE.init({
											theme : "advanced",
											mode : "textareas",
										});
										</script>		
								</p>
								
								<p>
									<input type="text" id="post_tags" name="post_tags" value="<?php echo $post_tags;?>" size="60" tabindex="3"/>
									<label for="post_tags">Post Tags</label>
								</p>							
								<input id="submit" type="submit" value="Submit Post" />
								
						</form>
						<?php } else { ?>
						<p>Sorry, you don't have permission to post new article!</p>
						<?php } ?>
					<?php } ?>
				</div>				
			</div><!-- #content -->
		</div><!-- #container -->

<?php get_sidebar(); ?>
<?php get_footer(); ?>

As you see, in the form code above, I used wp_nonce_field to output a WordPress hidden field for our form, this field will be used to validate that the contents of the form came from the current page and not somewhere else, I suggest that you should use wp_nonce_field in WordPress based forms.

In the textarea field, I used Tinymce (a web based Javascript HTML WYSIWYG editor) to enhance a posting process, it’s not obligatory, you could remove it from my code as well.

wp_dropdown_categories is the WordPress function used to retrieve the HTML dropdown list of your website categories, to learn more about this, please visit: http://codex.wordpress.org/Function_Reference/wp_dropdown_categories

In this tutorial, for easy understanding purpose, I’m going to make a simple posting form that has only 4 necessary input fields: Post Title, Post Content, Post Category and Tags, it’s not enough for the real life, but you can make this form more complicated by adding more input fields, captcha question, file upload box…

Step 2: Create A Form Processing File

As I was said, the newpost.php will display a posting form and the form_process.php will process the submitted form. the next file will check the validity of submitted data, if there is any error, the file will output them and stop working.

Here is my form_process.php content:

<?php
set_time_limit(0);
if (isset($_POST['action']) && $_POST['action'] == 'post' && wp_verify_nonce($_POST['_wpnonce'],'new-post')) {
	if ( !is_user_logged_in() ){
		wp_redirect( get_bloginfo( 'url' ) . '/' );
		exit;
	};
	$cat = array();
	$err = "";
	$user_id 		= $current_user->user_id;
	$post_title 	= $_POST['post_title'];
	$post_content 	= $_POST['post_content'];
	$cat[0]	 		= $_POST['cat'];	
	$post_tags 		= $_POST['post_tags'];
	$current_page   = $_POST['_wp_http_referer'];

	if ($post_title == "") {
		$err .= __('Please fill in Post Title field') . "<br />";
	}
	if ( $cat[0] == "-1") {
		$err .= __('Please choose your Post Category') . "<br />";
	} else {
		global $wpdb;
		$cat_ids = (array) $wpdb->get_col("SELECT term_id FROM $wpdb->terms");
		if ( !in_array($cat[0], $cat_ids) && $cat != "-1") {
			$err .= __('This category doesn\'t exist') . "<br />";
		}
	}	
	if ($post_content == "") {
		$err .= __('Please fill in Post Content field') . "<br />";
	}
	
	if ( $err == "" ) {
		$post_id = wp_insert_post( array(
			'post_author'	=> $user_id,
			'post_title'	=> $post_title,
			'post_content'	=> $post_content,
			'post_category'	=> $cat,
			'post_status'	=> 'publish',
			'tags_input'	=> $post_tags
		) );
		wp_redirect( $current_page . '&success=success' );
		exit;
	}	
}
?>

To verify the submitted data, we first use wp_verify_nonce to verify that correct nonce was used in wp_nonce_field in newpost.php.

After that, if there isn’t any error was found, the code will submit a new post to WordPress through wp_insert_post function and then redirect to the request page. this function can insert posts (and pages) in the WordPress database, it takes an object as its argument. Here is another example of using wp_insert_post function from WordPress.org:

array(
  'ID' => [ <post id> ] //Are you updating an existing post?
  'menu_order' => [ <order> ] //If new post is a page, sets the order should it appear in the tabs.
  'comment_status' => [ 'closed' | 'open' ] // 'closed' means no comments.
  'ping_status' => [ 'closed' | 'open' ] // 'closed' means pingbacks or trackbacks turned off
  'pinged' => [ ? ] //?
  'post_author' => [ <user ID> ] //The user ID number of the author.
  'post_category' => [ array(<category id>, <...>) ] //Add some categories.
  'post_content' => [ <the text of the post> ] //The full text of the post.
  'post_date' => [ Y-m-d H:i:s ] //The time post was made.
  'post_date_gmt' => [ Y-m-d H:i:s ] //The time post was made, in GMT.
  'post_excerpt' => [ <an excerpt> ] //For all your post excerpt needs.
  'post_name' => [ <the name> ] // The name (slug) for your post
  'post_parent' => [ <post ID> ] //Sets the parent of the new post.
  'post_password' => [ ? ] //password for post?
  'post_status' => [ 'draft' | 'publish' | 'pending'| 'future' | 'private' ] //Set the status of the new post. 
  'post_title' => [ <the title> ] //The title of your post.
  'post_type' => [ 'post' | 'page' ] //Sometimes you want to post a page.
  'tags_input' => [ '<tag>, <tag>, <...>' ] //For tags.
  'to_ping' => [ ? ] //?
);  

Yes, it’s our key code, with the help of wp_insert_post function, you could add any information to your new post as in the wp-admin new post section, it includes post excerpt, post time, site to ping, comment status… everything :D

But, how about adding custom fields? it’s easy for you too, put these code below wp_insert_post:

 <?php add_post_meta($post_id, $meta_key, $meta_value, $unique); ?>

example:

		$post_id = wp_insert_post( array(
			'post_author'	=> $user_id,
			'post_title'	=> $post_title,
			'post_content'	=> $post_content,
			'post_category'	=> $cat,
			'post_status'	=> 'publish',
			'tags_input'	=> $post_tags
		) );

add_post_meta($post_id, 'price', $price, true);

For more informaton about add_post_meta function, please visit: http://codex.wordpress.org/Function_Reference/add_post_meta

Notes:

In my code, I used the built-in PHP $_POST function to collect values in a form, it’s ok in most cases but in your website, don’t trust the user inputted data, maybe you will faced with cross-site scripting (XSS ) attacks, this way, you can use htmlspecialchars() to convert HTML characters into HTML entities or using HTML Purifier for more advanced uses.

Visit: http://en.wikipedia.org/wiki/Cross-site_scripting for more information about this kind of attack.

Step 3: Wrap It Up!

In this step we are going to make two files above into life. First, I create a new blank page in WordPress admin section, this page will use our New Post template:

add page 1 How to submit a new post from outside the Wordpress Admin panel

Second, I create a menu item which will use to access to this page in wp-admin/nav-menus.php:

add to menu 1 How to submit a new post from outside the Wordpress Admin panel

Finally, bring our new menu to the front of website by adding Custom menu in WordPress widgets:

font site 1 How to submit a new post from outside the Wordpress Admin panel

You can look at our final result:

result 1 How to submit a new post from outside the Wordpress Admin panel

Part 2: Manage Your Posts Outside The Admin Panel

In this part I will show you how to programming a Posts manager panel outside the WordPress admin section. Like the previous part, I’m going to create 2 new files, the first will display the logged in user’s posts, give an ability to edit or delete posts and the second file will process the submitted data.

Step 1: Listing Posts of Logged in User

This step is actually really simple, I named my new file is postmanager.php and put it in the Twentyten theme directory. To get all of the current user’s posts I will use a global variable $wpdb which was provided by WordPress to get necessary data from the database:

$wpdb->get_results("SELECT * FROM $wpdb->posts WHERE post_author = $current_user->ID AND post_status = 'publish' AND post_type = 'post' ORDER BY post_date DESC");

Except of using wpdb class, the other parts of this file is just like files in part 1, so my postmanager.php is:

<?php
/*
Template Name: Post Manager
*/
$wpdb->hide_errors(); 
nocache_headers();
get_header();
?>
		<div id="container">
			<div id="content" role="main">
				<div id="formbox">
				<?php if (is_user_logged_in()) {
				$memberposts = $wpdb->get_results("SELECT * FROM $wpdb->posts WHERE post_author = $current_user->ID AND post_status = 'publish' AND post_type = 'post' ORDER BY post_date DESC");
				?>
					<?php if ( !empty($memberposts) ) {
					require_once dirname( __FILE__ ) . '/post/manage.php';

					if ($err != "") {
						echo "<p>".$err."</p>";
					}
					if ($_GET['edit'] == "success") {
						echo "<p>Your post was successfully edited.</p>";
					}					
					
					?>					
						<p><b>List of your posts:</b></p>
						<form action="" method="post" enctype="multipart/form-data">
						<?php wp_nonce_field( 'manage-post' ); ?>
							<ul class="post_list">
							<?php
							foreach ($memberposts as $memberpost) {
								echo "<li><input type="."checkbox"." name="."id[]"." value="."$memberpost->ID"." />&nbsp;<a href="."$memberpost->guid".">".$memberpost->post_title."</a> (<em>".date("d/m/Y",strtotime($memberpost->post_date))."</em>)</li>";
							}
							?>
							</ul>
						<br class="clear" />
						
						
						<select name="action">
							<option value="edit">Edit Post</option>
							<option value="del">Delete Post</option>						
						</select>
						
						<input id="submit" type="submit" value="Proceed" />						
						</form>
					<?php } ?>				
				<?php } else { ?>
				<p>Sorry, you must be logged in to manage your posts!</p>
				<?php } ?>
				</div>				
			</div><!-- #content -->
		</div><!-- #container -->

<?php get_sidebar(); ?>
<?php get_footer(); ?>

By creating a new WordPress page which used this template file and adding a new menu item pointed to this page for easy access, you may have something like this screenshot:

post listing How to submit a new post from outside the Wordpress Admin panel

Step 2: Edit or Delete The Selected Post

In this step I will make a new file called manage.php in Twentyten/post directory to process the data submitted by postmanager.php file:

<?php
set_time_limit(0);
	if ( !is_user_logged_in() ){
		wp_redirect( get_bloginfo( 'url' ) . '/' );
		exit;
	};

if (isset($_POST['action']) && wp_verify_nonce($_POST['_wpnonce'],'manage-post')) {
	$action = $_POST['action'];
	$ids = $_POST['id'];
	$err = "";
	
	switch ($action) {
	case 'del' :
			if ( !empty($ids) ) {
			foreach ($ids as $post_id) {
				wp_delete_post( $post_id );
			}
			$err .= __('Your Post was deleted.') . "<br />";
			}
	break;

	case 'edit' :
	if ( !empty($ids) ) {
		if (isset($_POST['edit']) && $_POST['edit'] == 'edit' && wp_verify_nonce($_POST['_wpnonce'],'manage-post')) {
			$cat = array();
			$err = "";		
			$post_id		= $_POST['id'];
			$post_title 	= $_POST['post_title'];
			$post_content 	= $_POST['post_content'];
			$cat[0]	 		= $_POST['cat'];
			$current_page   = $_POST['_wp_http_referer'];
			
				if ($post_title == "") {
					$err .= __('Please fill in Post Title field') . "<br />";
				}
				if ( $cat[0] == "-1") {
					$err .= __('Please choose your Post Category') . "<br />";
				} else {
					global $wpdb;
					$cat_ids = (array) $wpdb->get_col("SELECT term_id FROM $wpdb->terms");
					if ( !in_array($cat[0], $cat_ids) && $cat != "-1") {
						$err .= __('This category doesn\'t exist') . "<br />";
					}
				}	
				if ($post_content == "") {
					$err .= __('Please fill in Post Content field') . "<br />";
				}
				
				if ( $err == "" ) {
					$post_id = wp_update_post( array(
						'ID'	=> $post_id,
						'post_title'	=> $post_title,
						'post_content'	=> $post_content,
						'post_category'	=> $cat,
					) );
					wp_redirect( $current_page . '&edit=success' );
					exit;
				}		
		}
		
		else {
		$post = get_post($ids[0]);
		$post_id 		= $post->ID;
		$post_title 	= $post->post_title;
		$post_content 	= $post->post_content;
		$cat 			= get_the_category( $post_id );	
		?>
						<form action="" method="post" enctype="multipart/form-data">
							<?php wp_nonce_field( 'manage-post' ); ?>
							<input type="hidden" name="action" value="edit" />
							<input type="hidden" name="edit" value="edit" />
							<input type="hidden" name="id" value="<?php echo $post_id; ?>" />						
								<p>
									<input type="text" id="post_title" name="post_title" value="<?php echo $post_title;?>" size="60" tabindex="1"/>
									<label for="title">Post Title</label>
								</p>
								
								<p>
									<?php wp_dropdown_categories('show_option_none=Choose Post Category&orderby=name&order=ASC&hide_empty=0&hierarchical=1&selected='.$cat[0]->cat_ID); ?>
									<label for="cat">Post Category</label>
								</p>	
								
								<p><label for="post_content">Post Content:</label><br />
									<script type="text/javascript" src="<?php echo get_template_directory_uri(). '/tiny_mce/'; ?>tiny_mce.js"></script>
									<textarea name="post_content" id="post_content" cols=90 rows=20 tabindex="2"><?php echo $post_content; ?></textarea>
										<script type="text/javascript">
										tinyMCE.init({
											theme : "advanced",
											mode : "textareas",
										});
										</script>		
								</p>
								
								<input id="submit" type="submit" value="Edit Post" />							
						</form>
						<hr />
		<?php
		}
	}
	break;

	default:
		wp_redirect( get_bloginfo( 'url' ) . '/');
		exit;
	}	
}
?>

At first, the file will check the validity of the submitted data based on wp_verify_nonce method, if the data is ok then using PHP switch statement to execute a different piece of code depending on which value of a $action variable.

If the $action variable equals to del: delete the post based on post ID by using wp_delete_post:

	case 'del' :
			if ( !empty($ids) ) {
			foreach ($ids as $post_id) {
				wp_delete_post( $post_id );
			}
			$err .= __('Your Post was deleted.') . "<br />";
			}
	break;

If the $action variable equals to edit: the file will display the edit form and using WordPress get_post function to get the database record for that post: Post Title, Post Content, Post Category. After this form was submitted, the file will use wp_update_post function to update post information:

post edit How to submit a new post from outside the Wordpress Admin panel

Conclusion

When writing this article, I hope this will be useful for your next project, let’s think about building a market place, a job board, a free lancing website based on WordPress… If you combine the code from my tutorial with some WordPress plugins that give your visitor an ability to register, login and logout in front of the site, that’s it! You’ve made a community WordPress website!

Now that you’ve had read my tutorial completely, could you tell me what do you think about it? I know my code needs more improvement on programing such about the code consistency and security fixing…, if you have any good idea, don’t hesitate share with me, thank you for your reading.

About Jenni R

I'm a Chief Branding Officer of IntenseBlog Website, a knowledge-hub to help you build a profitable blog. For the last 3 years I have dedicated myself to blogging and online marketing solutions.

Connect with me on: Google+, Facebook and Twitter.

Comments

  1. Reddy Rk says:

    Hi, Jenni … Thank’s for a Great Post … I Wanted This Snipped … for along Time …
    Finished for Implemented This … but for my Trouble … How to Submit New Post with upload image Thumnail , Please :( Help me….

  2. Deb SinghaRoy says:

    recently im developing a website … your post is very useful to me for that … but the thing is that in my theme TinyMCE is not working… can you help me for that purpose????

  3. Hello Jenni,

    Thanks so much for writing this, I only wish I had found it a few days earlier, I have been working on this for the past week struggling through finding all the documentation and trial and error.

    I am working on a cool feature which will allow you to choose a post format or regular blog, then it shows a ‘custom’ formatted posting form and say you have a video format selected if presents a url and a caption field, when you enter the url it goes all ajax and uses the internal WordPress functions to fetch the video either by oEmbed.

    Image offers an upload option or a url which again will pull in the oEmbed from flickr or the direct file path.

    Quote and link are a bit more basic no oEmbed but still, finally getting some tumblr features into a WordPress theme will be nice!

  4. Wow, very good tutorial :)
    Thanks for putting it together.

  5. JarrodMccurine says:

    I am here to say hi to every body.
    Nice to meet you hear.

  6. cardaddy says:

    Cool website ! I’ve just bookmarked it.

  7. Jenni, doesn’t this open up some security issues with your WordPress blog now? If it were discovered by a malicious hacker, this could easily be exploited.

    • Hello Maggie, I understand your concern, however, as you see that I used all WordPress function to do this, therefor, I don’t think There’s any problem about security issues here.

  8. Very nice
    1 – why do you need them both in the menu and in the sidebar? i.e. add new post
    2 – the redirection does work for me i get errors

    • Hi Boaz,
      1 – why do you need them both in the menu and in the sidebar? i.e. add new post
      Me: it’s up to you, we just create a public page to do a new article for website and you can call it anywhere, menu, sidebar or just a link.

      2 – the redirection does work for me i get errors
      Could you give me more details on this error? I think you should re-checking all of the site code, might be there’s a conflict somewhere.

    • the redirect when the articule submitted sucessfully doesn’t work. redirecting to the post or index or post manager should be ok.

    • I think you can change wp_redirect( $current_page . ‘&successsuccess=success’ );

      to $redirectaddress=get_permalink($post_id); wp_redirect($redirectaddress);

      that should do the trick :)

    • Same problem to me, the redirection doesnt work, my redirection is to a blank page, I dont get the confirmation text into the page template. How can I find is there any conflicts?

    • thanks Fajar, but still doesnt work :|

    • thanks Fajar. its works!

  9. nice article. you saved a lot of my research time! superb!!
    thanks!!!

  10. Thomas Herold - Financial Education says:

    This is a great article! I was looking for a plugin that allows guest posts. There are three available, however they all have flaws and are blown up. I guess I could use your scripts as a basis for a guest post plugin.

    Would you consider developing one via payment?

    Thomas

  11. Hello Jenni,

    Well, how much would it cost me to get these into a plugin with maybe some minor tweaks here and there?

    Thomas

  12. when i use wp_dropdown_categories in my form process, i goto sessionupdate which handles my processing , how come when i try to utilize wp_dropdown_categories it just redirects me to the category page that i selected? it only happens once i hit action button to perform the form processing. Is it something to do with $_POST issues?

    form code for wp_dropdown:

    sessionupdate.php code:

    $cat_select = array(); //get the category selected to update
    $cat_select[0] = ($_POST['cat']);
    $my_post['post_category'] = $cat_select;

    is my code… its taking the posted cat (or atleast i think) to sessionupdate to process and update my post. I’m not using insert_post but wp_update_post as im simply updating it. thanks

  13. I was’nt even aware you could do this! Thanks for bringing it to my attention. Offhand, I can’t think of how I would actually use it at the moment, but it’s certainly got me thinking. I’m going to make a note of this, and I’m sure I’ll find a way to put it into practice in the future.

  14. When I try editing a post, i get this:
    Warning: Cannot modify header information – headers already sent by (output started at X:\xampp\htdocs\wordpress\wp-includes\general-template.php:1691) in X:\xampp\htdocs\wordpress\wp-includes\pluggable.php on line 934

    Not sure why though.

  15. This is one of the best WP Tutorials i’ve seen. Thank you very much Jenni :D

  16. nice tutorial ^^

    Without having to log in………..password protected publish….Everyone posting

    admin & post writer view……. help~~~~~ help ~~~~~~

  17. I simply couldn’t depart your site before suggesting that I extremely loved the usual information an individual provide for your guests? Is gonna be back often in order to check up on new posts

  18. Hi there.

    In your manage post section where you display the checkbox, post title and date posted
    you use the ->guid property to create the link. However the guid is a permanent id that should never be changed, it is usually the very first permalink used for a post (http://codex.wordpress.org/Changing_The_Site_URL#Important_GUID_Note)
    Wordpress advise to never change the guid.

    Therefore, if one moves their website to a new url, the guid stays the same and those links are broken!
    I fixed the problem by using this instead :

    echo “ID”.” /> ID”.”>”.$memberpost->post_title.” (“.date(“d/m/Y”,strtotime($memberpost->post_date)).”)”;

    I subsituted guid”.”> by something like ID”.”>

  19. Gorgeous!!! It works lovely!! Thank you~~

  20. After hours I can’t make it work. !!!

    After edit or delete a post I can’t see the error or success message. If I turn on display errors I get this:
    Warning: Cannot modify header information – headers already sent by (output started at /usr/local/pem/vhosts/132265/webspace/httpdocs/wp-content/themes/test/header.php:9) in /usr/local/pem/vhosts/10082265/webspace/httpdocs/wp-includes/pluggable.php on line 866

    Also on post manager page I get this error:
    Notice: Undefined variable: err in /usr/local/pem/vhosts/10082265/webspace/httpdocs/wp-content/themes/test/postmanager.php on line 17
    Notice: Undefined index: edit in /usr/local/pem/vhosts/10082265/webspace/httpdocs/wp-content/themes/test/postmanager.php on line 23

    The rest of the features are working, even the posts are being deleted or edited.

    • Sinclair Lee says:

      I have same trouble as like Daniel has when I edit the post … How can I fix this error?

      Warning: Cannot modify header information – headers already sent by (output started at /home/hosting_users/d7cwood/www/wp-content/themes/dk/header.php:12) in /home/hosting_users/d7cwood/www/wp-includes/pluggable.php on line 866

  21. Hi, Jenni

    I am a Japanese and am still a beginner level about English and PHP.

    This is a wonderful code.
    I used it instantly. very good!

    but I worry about one problem.
    Supposing it is possible, please let me know.
    Help me if you please!

    I would like to use two categories by a drop-down menu.
    Since the 1st is parent_category, it is OK in as [ this ].
    I would like only for child_category belonging to parent_category
    to display the 2nd on a drop-down menu, and for a problem to
    contribute them from form.

    If Jenni or some people understand someone, please let me know how,
    a way, and a code.
    Thank you for your consideration.

Speak Your Mind

*