Chasing a Ghost Attachment ID: Fixing Featured Images After a Media Sync Import

I recently copied a batch of image files straight into wp-content/uploads/ by hand, rather than uploading them through wp-admin. They worked fine anywhere I referenced them directly by URL, but they were invisible to the Media Library: no thumbnail, no “Set featured image” option, nothing. That’s expected, and there’s a well-known fix for it: Media Sync, a free plugin that scans the uploads folder for files with no matching database record and lets you bulk-import them.

Running it fixed the Media Library problem cleanly. What it didn’t fix, and what took actual digging to understand, was that a chunk of my older posts still showed broken featured images afterward, even on posts where the underlying file was now correctly synced.

Where it actually went wrong

Copying a file onto disk only solves half the problem. WordPress doesn’t track a post’s featured image by filename or URL: it stores a single integer, _thumbnail_id, pointing at a specific attachment’s post ID in the database. Before I ran Media Sync, those posts’ _thumbnail_id values were already set, pointing at attachment IDs that had never actually existed as real database records (since the files were just dropped onto disk without ever being uploaded properly the first time). When Media Sync scanned the folder and created attachment records for those files, it necessarily gave them brand-new IDs, since there was no way for it to know or reuse whatever ID a post’s _thumbnail_id was already pointing at.

The result: every one of those posts kept quietly pointing at an ID that had simply never existed, while the correct image sat in the Media Library under a completely different ID, fully functional and orphaned from the post that was supposed to use it.

How I actually confirmed it

The real breakthrough was checking a post’s data directly rather than guessing from what rendered on the page. Pulling a broken post’s data showed featured_media: 978 and a has-post-thumbnail CSS class, meaning WordPress genuinely believed a featured image was assigned. But querying that attachment ID directly (/wp/v2/media/978) came back 404: Invalid post ID. That’s the smoking gun: not a broken image path, not a caching issue, just a foreign key pointing at nothing.

Reconciling old IDs to new ones

There’s no direct way to ask WordPress “what filename did this now-deleted attachment ID used to point at”: that record is simply gone. So the fix came down to cross-referencing by other signals instead:

  • Filename semantics. A lot of my images had genuinely descriptive names, like ZHA.png, Cloudflare_Logo.svg_.png, and FileBrowser-scaled.png, which map cleanly onto specific post topics with very little ambiguity.
  • Upload date proximity. Cross-referencing each broken post’s publish date against the newly-synced media library’s upload timestamps (both landing in the same year/month) narrowed candidates further.
  • Inline content cross-checks. A couple of posts embedded a different image inline in the body, separate from the featured image, which incidentally confirmed or ruled out candidate matches for the featured slot by elimination.

Where a filename gave a confident, unambiguous match, I updated featured_media directly to the new attachment ID and verified the fix by checking that the post’s data now actually resolved to a real, loadable image. Where the old files were just generic camera-roll names (P1400xxx.jpg, image-14.png) with no reliable way to tell them apart, I left those alone rather than guessing. Assigning the wrong photo as a featured image is a worse outcome than leaving it visibly broken, since a wrong-but-present image is much easier to miss on a casual scroll through the site.

The actual lesson

If you ever need to manually place files into wp-content/uploads/, whether restoring from a backup, migrating from another system, or whatever the reason, don’t stop at getting them into the Media Library. Anything that referenced those files before the sync (a _thumbnail_id, an ACF field storing an attachment ID, anything storing an ID rather than a URL) is still pointing at IDs that were never real, and will need reconciling by hand afterward. The files existing on disk and the database knowing about them are two completely separate problems.