Automatically change published posts to draft status when a custom expiration date is reached. Useful for news websites, event listings, job postings, offers, and temporary announcements.
/**
* Automatically expire posts based on a custom field.
*
* Custom Field Key:
* post_expiry_date
*
* Date Format:
* Y-m-d (Example: 2026-12-31)
*/
add_action( 'wp', 'wpfolks_expire_scheduled_posts' );
function wpfolks_expire_scheduled_posts() {
if ( ! wp_next_scheduled( 'wpfolks_check_expired_posts' ) ) {
wp_schedule_event( time(), 'hourly', 'wpfolks_check_expired_posts' );
}
}
add_action( 'wpfolks_check_expired_posts', 'wpfolks_process_expired_posts' );
function wpfolks_process_expired_posts() {
$args = array(
'post_type' => 'post',
'post_status' => 'publish',
'posts_per_page' => -1,
'meta_query' => array(
array(
'key' => 'post_expiry_date',
'compare' => 'EXISTS',
),
),
);
$posts = get_posts( $args );
$today = current_time( 'Y-m-d' );
foreach ( $posts as $post ) {
$expiry_date = get_post_meta(
$post->ID,
'post_expiry_date',
true
);
if ( ! empty( $expiry_date ) && $expiry_date <= $today ) {
wp_update_post(
array(
'ID' => $post->ID,
'post_status' => 'draft',
)
);
}
}
}