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.
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 yourprofile
post type.You need to reorganize a bit:
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:I also just notices that your
WHERE
clause has a column that doesn’t exist. There is nothe_date
column in the$wpdb->posts
table. It should bepost_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.
Quick correction on s_ha_dum’s excellent post: There was a closing bracket at the end of the $sql statement that shouldn’t be there. This worked for me: