Support

Account

Home Forums ACF PRO Expire Posts on Datepicker Field

Solving

Expire Posts on Datepicker Field

  • I’ve built a little event calendar category that uses custom fields to allow the site’s admin to place a starting/ending date and time to posts. Part of my hope for this setup is to automatically expire posts that have gone past their ending date field.

    I found this topic on the setup but it haven’t had much luck getting it to work.

    I’m running the following code in my template:

    <?php
    
    if (!wp_next_scheduled('expire_posts')){
      wp_schedule_event(time(), 'hourly', 'expire_posts'); // running hourly for testing purposes
    }
    
    add_action('expire_posts', 'expire_posts_function');
    
    function expire_posts_function() {
    	$today = time('l, F j, Y'); // matches the output of my custom field
    	$args = array(
    		'post_type' => array('post'), // array of the post types you want to check
    		'category' => 'events',
    		'posts_per_page' => -1 // get all the posts
    	);
    	$posts = get_posts($args);
    	foreach($posts as $p){
    		if(get_field('event_ending_date', $p->ID) > $today){
    			$postdata = array(
    				'ID' => $p->ID,
    				'post_status' => 'draft'
    			);
    			
    			wp_update_post($postdata);
    		}
    	}
    }
    ?>

    Am I on the right track with this type of code? Any suggestions on what may get this working?

  • Hi @karks88

    Almost..
    But I would say there’s no need for you to query all posts and then do the check when you can just query all past posts directly and change their statuses..

    
    if (!wp_next_scheduled('expire_posts')){
    	wp_schedule_event(time(), 'hourly', 'expire_posts'); // running hourly for testing purposes
    }
    add_action('expire_posts', 'expire_posts_function');
    
    function expire_posts_function() {
    	$today = time('Ymd'); // matches the date in DB
    	$args = array(
    		'post_type' => array('post'), // array of the post types you want to check
    		'posts_per_page' => 200 // get all the posts but don't set it t o -1 since its a risk of overloading the server
    		'category' => 'events',
    		'post_status' => 'publish',
    		'meta_query' => array(
    			array(
    				'key' => 'event_ending_date',
    				'value' => $today,
    				'compare' => '<' // you might have to switch this out for >
    			)
    		)
    	);
    	$post_query = new WP_Query($args);
    	if( $posts->have_posts() ){
    		while( $post_query->have_posts() ){
    			$post_query->the_post();
    			wp_transition_post_status('draft', 'publish', $post);
    		}
    		wp_reset_postdata();
    	}
    }
    
  • Might could streamline the code a bit, but this is working for me. Hope it helps.

    // Expire events
    if ($expireTransient = get_transient($post->ID) === false) {
    	set_transient($post->ID, 'set for 1 minutes', 1 * MINUTE_IN_SECONDS );
    	$today = date('Y-m-d H:i:s', current_time('timestamp', 0));
    	$args = array(
    		'post_type' => 'events',
    		'posts_per_page' => 200,
    		'post_status' => 'publish',
    		'meta_query' => array(
    			array(
    				'key' => 'end_date_time',
    				'value' => $today,
    				'compare' => '<='
    			)
    		)
    	);
    	$posts = get_posts($args);
    	foreach( $posts as $post ) {
    		if(get_field('end_date_time', $post->ID)) {
    			$postdata = array(
    				'ID' => $post->ID,
    				'post_status' => 'draft'
    			);
    			wp_update_post($postdata);
    		}
    	}
    }
  • Hi @precisioncreations

    Thank’s for your example too. It’s pretty much the same as mine except you also run a transient check so as to avoid running it more than once a minute (I’m guessing?).

    A few key differences tho I think worth mentioning is:
    1. Always use WP_Query if you can. get_posts() is a wrapper for WP_Query which excludes filters. It’s just good practice tho, don’t think it has any real impact on load times.
    2. By using wp_transition_post_statusinstead of wp_update_post we only update the status column in wp_posts table. The benefit of this is that it only handles the status so it’s faster and also it wont trigger any save_post hooked functions.

  • Hey Gents,

    I’ve attempted to use both code snippets provided by @jonathan & @precisioncreations but without much luck. I’ve added both to my functions file (at different times) with the only difference being my post type and key value based on my client’s setup.

    I can confirm the meta_value shows as a previous date of “20161130” in the database, yet the posts remain in a published state.

    When first attempting to force the cron job manually through BackupBuddy’s server tools, I received the following error message from the method @jonathan provided:

    “Fatal error: Call to a member function have_posts() on a non-object in /path/functions/custom.php on line 220″

    Line 220 is:
    if( $posts->have_posts() ){

    I removed the if call from the code altogether and was able to manually run the cron job, but still with the same result of no posts updating.

    Below is the code I’m using in the site’s functions file:

    // Expire Post Settings
    if (!wp_next_scheduled('expire_posts')){
    	wp_schedule_event(time(), 'hourly', 'expire_posts');
    }
    add_action('expire_posts', 'expire_posts_function');
    
    function expire_posts_function() {
    	$today = time('Ymd');
    	$args = array(
    		'post_type' => 'ivy_event',
    		'posts_per_page' => 200,
    		'post_status' => 'publish',
    		'meta_query' => array(
    			array(
    				'key' => 'expire_post_date',
    				'value' => $today,
    				'compare' => '<='
    			)
    		)
    	);
    	$post_query = new WP_Query($args);
    		while( $post_query->have_posts() ){
    			$post_query->the_post();
    			wp_transition_post_status('draft', 'publish', $post);
    		}
    		wp_reset_postdata();
    }

    Any help here would be greatly appreciated. I’m sure it’s something simple, but I’m on the tail end of a week where 14 hour shifts have been the norm.

Viewing 5 posts - 1 through 5 (of 5 total)

You must be logged in to reply to this topic.