After using WPML Media, a plugin that creates duplicates of each image for each language, we now have almost 100,000 duplicate images that we're not going to use and need to get rid of.

We need to not only delete these from the filesystem itself, but also need to make sure that deleting all references in the database as would typically happen if one were to manually delete them through the media gallery.

I'm looking for a WP-CLI solution, if it's possible. This solution was very helpful, but it does all images, not just those that are unattached / unused within the system.

How can I bulk delete media and attachments using WP-CLI?

Given another solution, the OP put in the comments that he achieved his solution ultimately with SQL.

How do I delete thousands of unattached images?

I'm no stranger to the command line or mysql, but am not familiar enough with WP tables to create a query to maintain the integrity of the database. If you are, then please suggest a pure database related solution, or PHP script that would hook into the system and do things the "wordpress" way.

I am not looking for a plugin based solution. I have tried DNUI, DX Delete Attached Media, and a score of others that all ended badly.

UPDATE: Using "parent=0" to determine if an image is attached or not was a very clever solution, and I marked it as the answer.

There is a way to legitimately use an image in a post and the parent still equals 0; that's when you visit the image details in the media library, and you copy the full image source URL to be manually pasted into a post. The accepted answer's solution will delete these as well. Because of that, I would like to encourage other solutions too that would take this into consideration.

That would perhaps require scanning the database to find instances of the image name, perhaps similar to the algorithm wp-cli search-replace would use?


You can try this (untested) modification to the answer you linked to by @something

wp post delete $(wp post list --post_type='attachment' --format=ids --post_parent=0)

to delete attachments without parents.

To target a given mime type, e.g. image/jpeg try:

wp post delete $(wp post list --post_type='attachment' \
    --format=ids --post_parent=0 --post_mime_type='image/jpeg')


  • Remember to backup first before testing!

  • Unattached images might still be used in the post content or e.g. in widgets.

  • 1
    This is clever solution. Looking for 'parent=0' as an attachment is a great way to determine if it's attached or not. – user658182 Apr 13 '17 at 18:11
  • For anyone coming across this who may need the same thing, just remember parent=0 does not mean that it would not be included in a page. A person can copy the full URL and include it manually in a post. This would not pick up that and those legitimately used images would also be delete. Marking as answer, but also updating question to encourage other answers that could also take this into consideration. Great solution nonetheless! – user658182 Apr 13 '17 at 18:13
  • Glad it helped. Thanks for the explanation. Maybe one could search the whole database as you mentioned, for each image, with a bash script, but that might be rather expensive in resources ;-) @user658182 – birgire Apr 13 '17 at 18:39
  • 1
    Use wp post delete --force if you do not have media trash active. – RRikesh Feb 26 at 9:59
  • 1
    Thanks for the tip @RRikesh – birgire Apr 15 at 18:32

The accepted answer will not delete unattached media for attachments where the parent doesn't exist anymore... this could happen when parents are deleted via the db or some other process that doesn't mark the attached media parents as 0.

Here is a cli command that will do that check.

wp post delete $(wp db query  --skip-column-names --batch "select DISTINCT p1.ID  from wp_posts p1
left join wp_posts p2 ON p1.post_parent = p2.ID
where p1.post_type = 'attachment'
AND p2.ID is NULL") --force
  • 1
    Props for showing how to perform a custom SQL query and use it's output as input for the wp post delete statement :) – Ramon Fincken Jan 12 at 10:29

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.