1

I'm trying to unpublish (set post_status to draft) all posts when a new one (with specific conditions that don't really matter right now) is published.

Here's what I currently have:

function rsc_unpublish_all_ads( $post_id ) {

    // don't do anything if the post is not an ad
    $post_type = get_post_type($post_id);
    if ( 'rsc-ads' != $post_type ) return;

    // select all ads other than the current one
    $args = array(
        'posts_per_page' => -1,
        'post__not_in' => array($post_id),
        'post_type' => 'rsc-ads',
        'post_status' => 'publish',
    );

    $published_ads = get_posts( $args );

    if ( !empty($published_ads) ) {

        // set each of the published ads as draft
        foreach ($published_ads as $published_ad) {

            // check again just for the sake of it?
            if ( $published_ad->ID == $post_id ) return;

            $unpublish = array(
                'ID' => $published_ad->ID,
                'post_status' => 'draft'
            );

            wp_update_post( $unpublish );
        }

    }

}

add_action( 'save_post', 'rsc_unpublish_all_ads' );

What happens is all rsc-ads posts are set to draft including the one I'm saving/updating – even though I'm checking against it twice (post__not_in in the $args AND comparing the ID in the foreach loop).

I know $post_id is correct because I'm checking for post type at the beginning of my function and that works fine.

Any ideas how to exclude the currently-being-saved post from being updated?

0

There's a more elegant way of updating your posts using the global $wpdb.

function rsc_unpublish_all_ads( $post_id, $post, $update ) {

// select all ads other than the current one
$args = array(
    'nopaging' => true,
    'post__not_in' => array($post_id),
    'post_type' => 'rsc-ads',
    'post_status' => 'publish',
    'fields'=>'ids'
);

$query = new WP_Query($args);

$published_ads = $query->posts;//array of post ids

 if ( !empty($published_ads) ) {

    global $wpdb;

    $ids = implode(',', $published_ads);

    $wpdb->query("UPDATE $wpdb->posts SET post_status = 'draft' WHERE ID IN ($ids)");

 }

}
    add_action( 'save_post_rsc-ads', 'rsc_unpublish_all_ads', 10, 3 );

I think you were having a problem calling wp_update_post() while the function was still running. In this implementation, if the $query is returning the post IDs properly, you make one trip to the database and fix all the posts without running a loop. Note I changed your hook to be specific to the "rsc-ads" post type so it will only fire on this post type.

  • Thanks for this, using $wpdb worked great! Note: had to use $published_ads = wp_list_pluck( $query->posts, 'ID' ); to get the array of posts IDs. – Jusi Sep 16 '17 at 9:50
  • @Jusi glad it worked but I'm surprised you needed that function when the WP_Query I wrote returns only the post IDs as an array. You may want to consider using the transition_post_status hook going forward since the save_post_rsc-ads hook is going to fire when you're still in draft of the new ad. I believe you only want this function to fire when you go from some status into 'publish' for the first time but I could be wrong. If so, write back and I'll be happy to modify the function for you. – jdp Sep 18 '17 at 13:56
  • @Jusi You needed that wp_list_pluck() because you used get_posts() that returned an array of $post objects as $published_ads. – jdp Sep 18 '17 at 15:13
0

You ended it by return, so your function will stopped when found the post that should not (or should?) be update, instead return it:

        if ( $published_ad->ID == $post_id ) return;

you can:

            if ( $published_ad->ID != $post_id ) {
// unpublishing ads
}

to get current post id in front end:

get_the_ID();

while in wp admin editor:

$_GET['post'];

dont forget adding condition is_admin to make sure you executing this in wp admin

  • You're of course right about return, I changed that now. I shouldn't really need to use that if statement anyway, since post__not_in is set to ID of post being saved. It hasn't helped though, it's still selecting ALL posts, including the one being edited. – Jusi Sep 15 '17 at 12:33
  • have you try if ( $published_ad->ID != $post_id ) { do unpublishing others } or after loop of unpublished: $republish = array( 'ID' => $post_id, 'post_status' => 'publish' ); wp_update_post( $republish ); yes that's inefficient, but just to prepared if your current ad post being unpublished – Asisten Sep 15 '17 at 16:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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