• Resolved Alex

    (@bald_technologist)


    Hi, I’ve combed the forums and various results found via Google, but have yet to find a solution to an issue I have when trying to take action when a scheduled post is published. The code is pretty simple, so I hope I’m missing something obvious here.

    The goal: when a sticky post is published, remove the sticky flag from all other posts, so there is only one published sticky post at a time. It’s important that this only executes at the time the new sticky post is published, not saved/scheduled, as there should always be one sticky post visible.

    The code:

    add_action('publish_post', 'custom_sticky_save_post');
    add_action('publish_future_post', 'custom_sticky_save_post');
    
    add_action( 'auto-draft_to_publish', 'custom_sticky_save_post' );
    add_action( 'draft_to_publish', 'custom_sticky_save_post' );
    add_action( 'future_to_publish', 'custom_sticky_save_post' );
    add_action( 'new_to_publish', 'custom_sticky_save_post' );
    
    function custom_sticky_save_post($post_id) {
        if(defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
            return;
        }
        $sticky = isset($_POST['sticky']) && $_POST['sticky'] == 'sticky';
        if($sticky) {
            $sticky_posts = array($post_id);
            update_option('sticky_posts', $sticky_posts);
        }
    }

    This executes properly for sticky posts that are published immediately, but does nothing when a scheduled post publishes, so the previous sticky post(s) remains sticky. At present, this is all on my theme’s functions.php file, but once I resolve this, I will wrap it in a plugin for anyone to use. I think this should work solely with the first two add_actions, but I’ve included the others in an attempt to find something that works.

    Thanks in advance!

Viewing 7 replies - 1 through 7 (of 7 total)
  • Ran into some corners of WordPress I’ve never seen before tracking down a solution for this one.

    There’s a little-known filter called “pre_update_option” that runs before any specific option is updated: pre_update_option.

    Since you’re main goal is just to always have one sticky post published at time, I think it make sense to run a filter whenever that value is about to change.

    I didn’t thoroughly test this, but try this approach:

    function custom_sticky_init() {
    	add_filter( 'pre_update_option_sticky_posts', 'custom_update_sticky_posts', 10, 2 );
    }
    add_action( 'init', 'custom_sticky_init' );
    
    function custom_update_sticky_posts( $new_value = array() , $old_value = array() ) {
    
    	if ( ! is_array( $old_value ) ) {
    		return $new_value;
    	}
    
    	$value = array_diff( $new_value, $old_value );
    
        return $value;
    
    }
    Thread Starter Alex

    (@bald_technologist)

    Thanks Devin, this is close, but doesn’t quite meet my needs, as scheduling a sticky post results in removal of the sticky flag from the currently live sticky post. My goal is to always have one visible on the site. I tried to add a bit of logic to determine if the post being processed is scheduled or not, but I can’t find a way to access the post ID at the time this code is run, and thus cannot check the post’s status. Any advice on how to do that?

    Thanks!

    Okay, tested a few more things. Try this one:

    function prefix_transition_post_status( $new_status, $old_status, $post ) {
    
    	$stickies = get_option( 'sticky_posts', array() );
    	$new_sticky = isset($_POST['sticky']) && $_POST['sticky'] == 'sticky';
    
    	if ( 'publish' == $new_status && ( in_array( $post->ID, $stickies ) || $new_sticky ) ) {
    		update_option( 'sticky_posts', array( $post->ID ) );
    	}
    
    }
    add_action( 'transition_post_status', 'prefix_transition_post_status', 10, 3 );

    This will catch when a new post is published or a scheduled post is published.

    However, if you have other scheduled posts that are also marked sticky, it will remove the sticky marking from those. Very annoying that WordPress puts this in an option table rather than just post meta.

    The only workaround I can think of for that is:

    1) Check if there are any posts in the $stickies array.
    2) If so, remove the current $post->ID from that array if it exists
    3) Query all the remaining sticky posts
    4) If remaining sticky posts are not published, add them to a clean $new_stickies array
    5) Add the current post to the $new_stickies array
    6) update_option( ‘sticky_posts’, $new_stickies );

    Make sure that is all wrapped inside the “if” conditional, so it only gets run when a new sitcky is being published.

    If you do need that functionality, just let me know. I can probably code it up pretty quick.

    Thread Starter Alex

    (@bald_technologist)

    Awesome, thanks Devin! I’m working on a similar solution to specifically address the issue with multiple scheduled sticky posts as well. One of the things I discovered is that $_POST[‘sticky’] is populated when a post is immediately published, but not when it is moving from scheduled -> published. Whereas is_sticky($post_id) is exactly the opposite, so I’m now accounting for that. I’ve also had to account for whether $post_idis actually the post ID or a revision of the post. In the latter, I reset it to $post_id->ID. I think I’m well on my way, thanks in huge part to your help! I’ll post completed code once I have it in a cleaner state.

    Thanks again!

    Thread Starter Alex

    (@bald_technologist)

    It took me a bit longer to wrap up the submission and posting, but I’ve published a plugin for this functionality: https://wordpress.org/plugins/there-can-be-only-one/.

    Thanks again Devin!

    Hopefully this will be useful for others running into the issues I hit.

    Thread Starter Alex

    (@bald_technologist)

    marking as resolved

Viewing 7 replies - 1 through 7 (of 7 total)

The topic ‘publish_future_post not running’ is closed to new replies.