The database row outlived the image file
WordPress still lists the image, the product page still asks for it, and the file is not on disk. The admin looks healthy; the storefront shows a gap.
The symptom
A product page with a blank space, a broken-image icon, or a placeholder where the photograph should be. In the Media Library the image is listed by name and looks like any other attachment — its thumbnail may even still render from a cached variant.
The row in the database is intact. The file it points to is not on the server.
This almost always arrives in one of four ways: a migration that copied the database but not
wp-content/uploads, a staging sync that ran in the wrong direction, a media-offloading plugin
that was removed while the files were still on the remote, or a well-meant clean-up of the uploads
folder.
What it costs
- The product looks broken, not just unillustrated. A missing photograph reads as neglect, and the judgement lands on the whole store, not on the one product.
- It converts far below a product with a photo, which is why it belongs in the money section of any honest audit rather than in a technical appendix.
- It is invisible from the admin. Product lists show the attachment title, not whether the file exists. Nothing in WordPress checks this, ever, on its own.
- Backups can carry it forward. A database backup restored onto a server whose uploads were never restored produces exactly this state, at scale.
How to check it yourself
This one cannot be answered by SQL, because the question is about the filesystem. WP-CLI can ask both sides at once:
wp eval '
foreach ( get_posts([
"post_type" => "attachment",
"post_mime_type" => "image",
"posts_per_page" => -1,
"fields" => "ids",
]) as $id ) {
$file = get_attached_file( $id );
if ( $file && ! file_exists( $file ) ) {
printf( "%d\t%s\n", $id, $file );
}
}'
On a large library this walks every attachment, so run it outside peak hours. If it prints nothing, every image WordPress knows about is where WordPress expects it.
How to fix it
- Find out whether the files exist anywhere before touching the database. A backup, the old server, the staging copy, the offload bucket. Restoring the folder is always cheaper than re-shooting or re-sourcing photography.
- If they are gone, replace the image on the products that use it, then delete the orphaned attachment. Deleting the attachment first leaves products with no image and no record of what the image was.
- Check the count. Two missing files is an accident; two thousand is a migration that did not finish, and the repair is to finish it rather than to fix products one at a time.
- After any migration, run the check again. This is the single most useful moment for it.
When it is a false positive
- Offloaded media. If your images live on S3, R2 or a similar service, the local file is legitimately absent by design and the site serves them from the remote perfectly well. This is the most common false positive by a wide margin, and if you offload, this check is not measuring something meaningful for you — hide it once and it stays hidden.
- A CDN that rewrites URLs without moving files still keeps the local copy, so it is not affected.
- Attachments used by nothing. Still worth cleaning, but harmless.
How Merchlint finds it
Merchlint takes the path stored for each product image and asks the filesystem whether that file exists. Nothing is fetched over the network — no request is made to the store’s own front end or to anywhere else — so the check works identically on a local copy, a staging site and production.
The finding shows the attachment ID, the stored path and which products use it.
Confidence: F — fact from the database and the filesystem. The path resolves to a file, or it does not.
Because one image can belong to many products, the finding reports the attachment. Fixing it once fixes every product that used it.
Disagrees with what you see in your store? Write to us — we read every message. contact@merchlint.com