WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

Is there an efficient way to change a post status from 'published' to 'draft' when a user of a certain type tries to update their posts. I tried something along these lines

function change_post_status($post_id)
    $current_post = get_post( $post_id, 'ARRAY_A' );
    $current_post['post_status'] = 'draft';


The code looks good to me but for some reason it doesnt work properly and I think it creates an endless loop(forcing me to restart my SQL server).

share|improve this question
You get endless loop because your hook calls wp_update_post() which calls wp_insert_post() which calls your hook... And the circle have closed. – Rarst Oct 26 '12 at 21:57

Have you tried to use "wp_insert_post_data" instead of "pre_post_update"?

share|improve this answer
something like this: add_filter('wp_insert_post_data', 'change_post_status', 99, 2); – Daniel Oct 26 '12 at 21:27
I have not, I will give it a shot. Never used that filter before. Not sure how to use it without $post_id as a parameter. – tyler Oct 29 '12 at 15:02

Since your logic is based on role, just not give it publish_posts capability? The way native Contributor role works.

share|improve this answer
This would work, however the way it is set up I made custom post types and the user posts listings via gravity forms. Once their listing is accepted an admin publishes it so after that point the user can update whenever they want. I need it so when they update the post becomes a draft until it is reviewed again. – tyler Oct 29 '12 at 15:01
up vote 0 down vote accepted

So I ended up using the wp_insert_post_data filter and came up with the following, which after testing, seems to be working properly.

add_filter('wp_insert_post_data', 'change_post_status', '99');

function change_post_status($data)
    if( (current_user_can('role')) && ($data['post_type'] == 'custom_post_type') )
        if(defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;
        //then set the fields you want to update
        $data['post_status'] = 'draft';     
    return $data;
share|improve this answer

I would like to add one more issue. When you use the code above, it will happen to EVERY post, also if you do an update in the backend! Because wp_insert_post_data is triggered eveytime a post is updated, so also if e.g. the admin wants to publish a post - it will automatically trigger again, and set the post to draft. So it will not be possible to publist anymore. Here a modified code which worked for me, check if we are in the admin backend:

function change_post_status( $data, $postarr ) {
      $data[ 'post_status' ] = 'draft';
      return $data;
if (!(is_admin())) {
  add_filter( 'wp_insert_post_data' , 'change_post_status' , '99', 2 );
share|improve this answer
This is wrong. is_admin() does not check for the administrator role, and the code should run in backend too, that’s the whole point. The check for a user role works exactly as it should. – toscho Sep 13 '13 at 0:24
If the original issue needed to be done to every post, then its OK. My issue was setting a status to 'draft' after a user edited his post in the frontend (with wp_user_frontend). After that the admin in the backend could not publish the post, because it updated the status to "draft" all the time. That is why i needed to restrict it to the frontend, and that is exactly what is_admin() does - checks if you are in the backend. – Asped Sep 13 '13 at 7:55

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.