Auto delete WordPress images/thumbnails (all sizes) and featured after X days/hours, or similar?

If you need to retain only images for last 50 posts, I don’t think that a cron job or a WP cron is the best thing you can do, in WordPress you can know when a post is published, and you can run a routine everytime it happen, deleting images for the post pubblished 50 posts ago.

That’s easy, better performing (you do nothing if you have nothing to do, a cron job runs regardless you have something to delete or not).

The workflow is pretty easy:

  1. Everytime a post is published get the 51th post id (ordered by publish date)
  2. delete all images having that id as post parent

the code:

add_action( 'save_post', 'cleanup_old_post_images', 10, 3 );

function cleanup_old_post_images( $post_ID, $post, $update ) {
  if ( $update ) return; // do nothing on update
  $postid51th = get51th_postid(); // see below
  if ( ! empty( $postid51th ) && is_numeric( $postid51th ) ) {
    delete_post_media( $postid51th ); // see below, function in OP
  }
}

function get51th_postid() {
  return $GLOBALS['wpdb']->get_var(
    "SELECT ID FROM " . $GLOBALS['wpdb']->posts .
    " WHERE post_type="post" AND post_status="publish" ORDER BY post_date DESC
    LIMIT 50, 1"
  ); 
}

function delete_post_media( $post_id ) {
  $attachments = get_posts( array(
    'post_type'      => 'attachment',
    'nopaging'       => TRUE,
    'post_parent'    => $post_id
  ) );
  if ( empty( $attachments ) ) return; // added this line to prevent errors
  foreach ( $attachments as $attachment ) {
    if ( false === wp_delete_attachment( $attachment->ID ) ) {
      // Log failure to delete attachment.
    }
  }
}

This works for posts published after you put the code in the site, but you can write a run-once function to delete images for older posts

add_action( 'shutdown', 'delete_older_attachments' );

function delete_older_attachments() {

  // run only on admin and use a transient to run once
  if ( ! is_admin() || get_transient('get_older_postids') ) return;     

  // the query to exclude last 50 posts
  $latest_query = "SELECT ID FROM " . $GLOBALS['wpdb']->posts .
    " WHERE post_type="post" AND post_status="publish" ORDER BY post_date DESC
    LIMIT 50"
  );

  // get older posts ids
  $older_ids = $GLOBALS['wpdb']->get_row(
    "SELECT ID FROM " . $GLOBALS['wpdb']->posts . 
    " WHERE post_type="post" AND post_status="publish"
    AND ID NOT IN (" . $latest_query . ")"
  );

  // get attachments for older posts
  if ( ! empty( $older_ids ) && is_array( $older_ids )  ) {
    $attachments = $GLOBALS['wpdb']->get_row(
      "SELECT ID FROM " . $GLOBALS['wpdb']->posts . 
      " WHERE post_type="attachments"
      AND post_parent IN (" . implode( ',', $older_ids ) . ")"
    );
  }

  if ( isset($attachments) && ! empty( $attachments ) && is_array( $attachments )  ) {
    foreach ( $attachments as $attachment ) {
      if ( false === wp_delete_attachment( $attachment ) ) {
        // Log failure to delete attachment.
      }
    }
    // set the transient to assure run once
    set_transient( 'get_older_postids', 1 );
  }
}

Leave a Comment