Delete media programmatically in WordPress: attachments, unattached images, 404, orphaned

!! Before anything: make sure you made a backup!

Delete unattached media (orphaned images that are not attached to any WordPress post, page or custom post)

When you delete your posts, attachments from it don’t get deleted automatically. They keep staying in the WordPress Media Library and on your web server eating disk space and messing the things up.

The following function will delete them permanently both — from Media Library and from wp-content/uploads folder too.

Be careful what you are doing. For example, in one of the projects we added images and descriptions on tags archive pages for SEO purposes and these images as you understand are not attached to any post, however that doesn’t mean we want to get rid of them.

If you’ve thoroughly thought this out and you are  sure you want to get rid of this orphaned media, here you go:

Delete all attachments related to a specific custom post type

This function is useful when you need to delete all images that are attached to a specified CPT.  Mind to change “card” to your custom post type name.

This will delete both — an attachment from WordPress, and an actual file from your web server.

Clean up WordPress Media Library: delete all attachments which files no longer present on web server and give 404 error

Is your Media Library populated with images that are not displayed? When you click them it says image does not exist anymore and gives you 404 page?

This is a broken link issue. There is no file for that attachment stored on a web server anymore so you are seeing these empty squares in Media Library as ghosts of previously existed images.

This function will clean up your WordPress Media Library from non-existent images. It will delete all attachments which files no longer present on web server.

Caution: resource greedy.

*Mind that if you have a link to such file somewhere in posts it will stay there and still give 404 to users. To explore this issue and find such broken links in posts I use Screaming Frog.

You are always making a backup before something like that. Right?

How to delete not used images in WordPress:

If your website is more than few months old you know how surprisingly large your wp-content/uploads can become one day. You don’t know where all that stuff comes from and where it goes but it just occupies all free space on your web server.

This post will help you define useless media correctly and get rid of it. Just watch out what you are doing as delete means delete.

Case 1: all images on your site are stored as WP attachments

Good media: all WordPress attachments

Bad media: anything stored in uploads directory that is not WP attachment

This function will free up disk space on your hosting account. It will scan your wp-content/uploads directory (recursively) and check every found file whether it is WP attachment or not.

All files that are not WP attachments will be deleted. If you got rather large uploads folder (say 5 gb) you might want to split process into parts by folders.  I’ve got 1Gb checked and cleaned in 15 seconds (only 300 MB left!).

This is how we find and delete images which are not attachments.

But what if your images are not stored as WP attachments at all but are still used on your website?

Case 2: images on your site are uploaded through custom fields and are not stored as WP attachments

Good media: all images saved in specified custom fields

Bad media: anything else in uploads directory

Step 1: Define all good images

First, we need to get the combined list of all “good” images that are used on the website, so later we can delete all files that are not used.  

I’ll show one of the cases as an example. It’s an online bookstore. We’ve managed to get rid of 32 thousands of useless files and free up to 75% of disk space on web server. 

Before: 42096 images 4767 MB

After: 9202 images 1251 MB

Cleaned 32894 images and saved 3516 MB disk space

Here we’ve got 3 post types: posts (used for books), book author and booklist. Image for every post type is stored in a separate custom field (book cover, author’s pic and book list image). We’ll obtain the list of images used for each CPT and combine them together to get a full list of good images. These are the images that we will preserve.

Step 2: Delete images not used in WordPress

So we’ve got the complete list of good images that are used on the website in variable $all_good_pictures. Now we’ll  go through the wp-content/uploads directory and check every file whether it’s on list or not. If it’s not listed we’ll just delete it.

Wrap up

Here is how we can get our WordPress install clean and well-organized, reduce data amount and CPU load and even move to a cheaper hosting plan as we won’t store gigabytes of trash anymore.

And just in case, you’ve made a backup, right? 🙂

Delete media programmatically in WordPress: attachments, unattached images, 404, orphaned
Share this stuff:

5 Replies to “Delete media programmatically in WordPress: attachments, unattached images, 404, orphaned”

    1. hey,
      All functions can be placed in functions.php file of the current theme or in the plugin and fired with actions like «init», «wp_head» etc or run with shortcode depending on your goals. Good luck!

  1. It doesn’t work for me. I copied & paste the code into functions.php of the Twenty Seventeen theme right at the very bottom. I refresh my site but I don’t see it deleting unattachments

  2. Hi, I just came across your post here about deleting orphaned media. It looks great and just what I need. However I’m a little unsure just what to do with your code. Can you explain a little on what to do with it (for a relative newby)
    Many many thanks.

  3. Hey, nice functions!

    I wonder if you have any ideas on the following use case:

    I have a lot of images on my site, WordPress combined with WooCommerce.

    WordPress is creating 4 different image sizes on my site (thumbnail, medium, medium_large and large).

    In addition to that WooCommerce adds 6 image sizes (woocommerce_single, woocommerce_gallery_thumbnail, shop_catalog, shop_single and shop_thumbnail).

    I have implemented a function that makes sure that if the upload of an image is done on a product post type, the default wordpress image sizes are disabled. It also works the other way around, if not on a product post type, the woocommerce image sizes will not be generated.

    But, and this is a big but ( 😀 ), this only works for new uploads. For all my other, thousands of images, I can’t come up with a way to remove the default wordpress image sizes attached to a product post type as well as the other way around, remove all the woocommerce product sizes attached to non product post types.

    Do you have any ideas around this?

    Thanks in advance!

Leave a Reply

Your email address will not be published. Required fields are marked *