Monday, March 14, 2022

[SOLVED] Automatically draft WordPress Posts older than 30 days using CRON

Issue

I have a WordPress site with 1000s of posts. I'd like to set all posts older than 30 days to draft automatically when it reaches the specified date.

Been staring myself blind at the following code - triggering the CRON manually has now effect:

<?php
/**
 * Function that will draft specific posts on specific conditions
 *
 * @param \WP_Post $_post
 */
function tgs_maybe_draft_the_post( $_post ) {
    

    $publish_date = get_the_date( 'd M Y', $_post->ID);

    // Bail if no publish date set for some reason.
    if ( ! $publish_date ) {
        return;
    }
    
    // Set status to draft if older than 30 days.
    if (strtotime($publish_date) < strtotime('-30 days')) {
        wp_update_post( array(
            'ID'          => $_post->ID,
            'post_status' => 'draft'
        ) );
    }
}

/**
 * Register cron event on init action
 */
function tgs_cron_schedule_draft_posts() {
    $timestamp = wp_next_scheduled( 'tgs_draft_posts' );
    if ( $timestamp == false ) {
        wp_schedule_event( time(), 'hourly', 'tgs_draft_posts' );
    }
}
add_action( 'init', 'tgs_cron_schedule_draft_posts' );

/**
 * Handle deletion of posts periodically.
 * - Loop through the posts and call the tgs_maybe_draft_the_post function.
 */
function tgs_draft_posts_handler() {
    $posts = get_posts( array(
        'posts_per_page' => - 1,
        'post_type'      => 'post',
        'post_status'    => 'publish',
        'suppress_filters' => true,
    ) );
    foreach ( $posts as $_post ) {
        tgs_maybe_draft_the_post( $_post );
    }
}
add_action( 'tgs_draft_posts', 'tgs_draft_posts_handler' );

What am I doing wrong?


Solution

  1. You can troubleshoot your logic (change status to draft) by running that logic directly during a page view rather than from cron. Try using the wp_footer action, something like this.
    add_action( 'wp_footer', 'tgs_draft_posts_handler')
    
    You can then include print_r(); debugging code and it will show up on your rendered page: ugly but useful. You could do print_r('about to do get_posts'); for example.
  2. You can search for posts with date criteria. That way you don't need a separate check for the posts' age. With thousands of posts this is a significant time saver.
        $posts = get_posts( array(
         'posts_per_page' => - 1,
         'post_type'      => 'post',
         'post_status'    => 'publish',
         'suppress_filters' => true,
         'date_query' => array(
             array(
                'column' => 'post_date_gmt',
                'before' => '30 days ago'
             )
           ),
     ) );
    
  3. Once your basic logic works, you can get it working under cron.

And, turn on the WordPress debugging stuff. It helps a lot.

When it all works, don't forget to remove the print_r() statements (duh, obviously).



Answered By - O. Jones
Answer Checked By - Gilberto Lyons (WPSolving Admin)