1

I have a custom post type for the user profile page. My client wants all users to update their profile at least once a month, so we want their profile (custom post) to be automatically set to draft after 30 days. They will then receive an email asking them to update the post. The post needs to be set to draft again 30 days after the last modified date and another reminder sent out, etc.

So far I have this code to expire the posts after 30 days of the published date, which doesn't seem to work. I assume I am missing something regarding the cron scheduling:

if ( ! wp_next_scheduled( 'run_post_expiration' ) ) {
    wp_schedule_event( time(), 'hourly', 'run_post_expiration' );
}    
add_action( 'run_post_expiration', 'expire_posts' );

function expire_posts() {
    global $wpdb;
    $daystogo = "30";
    $sql = "UPDATE wp_posts 
        SET `post_status` = 'draft' 
        WHERE `post_type` = 'profile' 
        AND DATEDIFF(NOW(), `the_date`) > '$daystogo')";
    $wpdb->query($sql);
}
add_action('init', 'expire_posts');

I have this code to set the post_date to the post_modified date, therefore enabling the code above to still work every 30 days:

function reset_post_date_wpse_121565($data,$postarr) {
    $data['post_date'] = $data['post_modified'];
    $data['post_date_gmt'] = $data['post_modified_gmt'];      
    global $post;
    if ($post->post_type == 'profile'){
        return $data;
    } 
}
add_filter('wp_insert_post_data','reset_post_date_wpse_121565',99,2);

The above code to modify the post_date does actually work, but it is also causing some problems with other post types which I wasn't expecting, so I think there may be an error somewhere.

Can anybody help me to get this to work? Or am I even going about this in the right way? Perhaps there is a better solution. I have tried the "Post Expirator" plugin, but this only works with the post_date; once someone has updated their profile once, it no longer works.

EDIT:

I edited the original code to set the posts to draft to this (based on some code I found elsewhere):

add_action( 'my_trash_hook', 'my_trash_hook_function' );
if (!wp_next_scheduled('my_trash_hook')) {
    wp_schedule_event( time(), 'hourly', 'my_trash_hook' );
}

function my_trash_hook_function() {
    global $wpdb;
    $daystogo = "1";
    $sql = "UPDATE {$wpdb->posts}
        SET 'post_status' = 'draft'
        WHERE 'post_type' = 'tests'
        AND DATEDIFF(NOW(), 'the_date') > '$daystogo')";
    $wpdb->query($sql);
}

I have another function set up to send me an email when the post is set to draft and another to send me an email when the post is published again.

What is happening is that when I log in to the site I am sent an email saying the post has been published, but not one saying the post was set to draft. Not sure if the two pieces of code are conflicting with each other or just plain wrong.

1

Don't use global $post. Everything you need should be passed into the function in the $data and $postarr parameters.

Secondly, you have to return the $data in all cases. What you are doing now is effectively erasing data for everything but your profile post type.

You need to reorganize a bit:

function reset_post_date_wpse_121565($data,$postarr) {
  if ($data['post_type'] == 'profile'){
    $data['post_date'] = $data['post_modified'];
    $data['post_date_gmt'] = $data['post_modified_gmt'];
  } 
  return $data;
}
add_filter('wp_insert_post_data','reset_post_date_wpse_121565',99,2);

I have not tested that thoroughly but that is the right idea.

As for a better way...

Your expire_posts function is not going to be reliably portable as it uses a hard-coded database prefix. At the very least, rewrite that SQL so that the prefix is not hard-coded:

function expire_posts() {
  global $wpdb;
  $daystogo = "30";
  $sql = "UPDATE {$wpdb->posts} SET `post_status` = 'draft' WHERE `post_type` = 'profile' AND DATEDIFF(NOW(), `post_date`) > '$daystogo')";
  $wpdb->query($sql);
}
add_action('init', 'expire_posts');

I also just notices that your WHERE clause has a column that doesn't exist. There is no the_date column in the $wpdb->posts table. It should be post_date.

Honestly, if you were to deal with the modified date only, you should be able to get this to work without ever altering the post date at all. I don't think you need that second block of code at all.

  • Hey s_ha_dum. Thanks again for the help! And for cleaning up my code! Do I still need the wp_schedule_event function? Is there anything else I need to add to get this to run as this is the bit that I am most unsure of? Thanks D – user36987 Nov 29 '13 at 16:43
  • Yes, you still need to change the modified date with wp_cron. I don't use wp_cron that much but it looks right. Try it and see. Set your interval to five minutes and see if it works. – s_ha_dum Nov 29 '13 at 16:47
  • Thanks will do. Just tested the code to reset the modified date though and this no longer seems to work! Any ideas? Thanks D – user36987 Nov 29 '13 at 16:50
  • Your code actually doesn't modify the "modified" date. It sets the post date to the modified date. I copies that over without change, assuming that that is what you wanted. But... fixed. $data is an array, not an object. I'm an idiot. – s_ha_dum Nov 29 '13 at 17:03
  • Aha! Yes, that works perfectly now. Thank you! Just waiting for the cron job to see if the other bit of code works now. Cheers D – user36987 Nov 29 '13 at 17:09

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.