Troubleshooting Delayed Image Import
Work through the section that matches your symptom. Almost every problem falls into one of four buckets: the meta never got written, the renderer isn’t emitting the remote URL, the background downloads aren’t running, or the downloads are running but failing.
Throughout this guide, “hydrated” means the image has been downloaded into your media library and attached — the post is finished with. “Delayed” means the URL is still sitting in post meta waiting.
First stop: the Status tab
Super Speedy → Delayed Image Import opens on the Status tab. It shows a progress bar with image-level counts (pending / loaded / failed), downloads-per-hour with an ETA, a cron heartbeat line that goes red with advice when ticks have stalled, per-supplier-host stats, and one-click Process-a-batch-now / Pause buttons. The counts auto-refresh while images are pending. Thirty seconds here usually tells you which section of this guide you need:
- Pending counts are zero right after an import → the meta was never written. See “No images were deferred”.
- Pending counts are stuck at the same number for hours → downloads aren’t running. See “The backlog isn’t shrinking”.
- Failed counts are climbing → downloads are running but failing. See “Images keep timing out”.
- Counts look right but the front end shows no images → renderer problem. See “Products show no image”.
No images were deferred (pending counts are zero after an import)
The importer didn’t write to the delayed_* meta keys.
Using Super Speedy Imports? Deferring is on by default (DII 2.26+, SSI 2.72+), but check two things:
- Open the import’s config and look at Additional Options — is Defer image downloads un-ticked? Someone may have switched it off for this import. Tick it and save.
- Was the run an “Only refresh images” run? That mode always downloads inline by design — the images went straight into the media library instead. Check the media library before assuming failure.
Using another importer? Verify the mapping writes to exactly delayed_image_url (featured) and delayed_gallery_image_urls (gallery, pipe-separated). Then check one post directly:
SELECT meta_key, meta_value FROM wp_postmeta
WHERE post_id = <id> AND meta_key LIKE 'delayed%';
If the keys are missing, the importer mapping is wrong. If the keys exist but the values are empty, your CSV column was empty for that row — note the plugin cleans up empty delayed meta on activation, so blank rows don’t linger.
Gallery URLs comma-separated? Only pipe (|) is supported. Comma-separated values are treated as ONE URL and fail to download. Fix the mapping to emit pipes and re-import.
Products show no image on the front end
The meta is there but visitors see a placeholder or nothing.
- View source on the product/archive page and search for
dii-remote. If present, the renderer IS emitting the supplier’s URL — the problem is the supplier not serving it (see hot-linking below). - If you see
woocommerce-placeholderinstead, the renderer didn’t recognise the post. Turn on Settings → Diagnostics → Diagnostic logging, reload the page, and read theDII-prefixed lines inwp-content/debug.log— every render decision is logged with the post ID and the branch taken. - Theme doesn’t use the standard hooks. The renderer filters
post_thumbnail_html,woocommerce_product_get_image, the WooCommerce product-image block, and the WC gallery. A theme that builds<img>tags by hand from_thumbnail_idwill show nothing until the image is actually downloaded. Workaround: hydrate faster (runwp dii load-all, or shorten the cron interval). - Broken-image icons instead of the SVG placeholder? Check Settings → Diagnostics → On-error fallback isn’t set to “Show the broken image” — that mode is a debugging aid, not for production.
Hot-linking suppliers (images fail only in the browser)
Some suppliers return 403 when a browser requests their images cross-origin, while server-side downloads work fine. Symptoms: the SVG fallback appears (the onerror swap fired), but wp dii load-featured downloads the same URLs happily.
Add those hostnames to Settings → Hot-link blocklist (one per line, subdomains matched). Listed hosts skip the doomed browser request and render the SVG immediately; the background downloads still fetch them fine. To find out which hosts are blocking, temporarily set the on-error fallback to “Show the broken image” and check the failing URLs in DevTools’ Network tab.
The backlog isn’t shrinking
Delayed counts sit still even though cron is meant to be draining them.
- Is the cron scheduled? The Status tab shows “Next tick” when it is. If it says disabled, someone un-ticked Enable cron in Settings (it’s on by default as of 2.26).
- Is WP-Cron firing at all? WP-Cron only runs when the site receives requests. A staging site nobody visits never ticks. Check with
wp cron event list— ifdii_process_batchshows a next-run time in the past, WP-Cron isn’t being triggered. Fixes: real traffic, a server cron hittingwp-cron.phpevery minute, orDISABLE_WP_CRONplus a system crontab (the standard WP setup for reliable crons). DISABLE_WP_CRONis set but no system cron exists. This is the most common cause. Checkwp-config.php.- Force one tick manually to prove the pipeline works:
wp cron event run dii_process_batch. If that drains a batch, your only problem is WP-Cron scheduling. - In a hurry? Skip cron entirely:
wp dii load-allbulk-downloads everything now, with a progress bar, using the same per-domain round-robin as the cron.wp dii load-all --dry-runfirst shows you the image count per supplier host. - One supplier’s images sitting still while others drain? That host has probably tripped the circuit breaker and is in a timed backoff (2 minutes doubling up to an hour after repeated failures). Turn on Diagnostic logging and look for “skipping backed-off host” lines to confirm. A CLI run ignores the backoff if you want to force the issue now.
- One post stuck while others drain? It may be in a failure cooldown (default 60 s after each failure) or holding a stale lock. Settings → Clear cooldowns / Clear locks resets both.
DISABLE_WP_CRON set with no matching system crontab is by far the most common cause of a backlog that never moves. Check that before anything else on a self-managed server.
Images keep timing out
Downloads run but images keep failing (climbing attempt counts, or landing in the Failed Images tab).
First, read the reasons — they’re recorded per image:
wp dii failed
Or open the Failed Images tab — each row has a live preview thumbnail of the remote URL. A thumbnail that renders next to a server-side failure reason means the supplier blocks server downloads but not browsers — that one glance is the whole diagnosis. A hidden/broken thumbnail means the URL is genuinely dead.
Common reasons and what they mean:
http_404/http_403— the URL is dead or the supplier blocks server requests. Fix the source data; retrying won’t help. A 403 on server-side fetches (not just browser hot-linking) means the supplier blocks your server’s IP or user agent — talk to the supplier.- cURL timeout errors — the supplier is slow. Early attempts deliberately use a short timeout (default 3 s), but the ladder doubles it on every failure up to the 30 s ceiling, so a genuinely slow supplier succeeds on a later rung by itself. If images are failing outright at 30 s, raise Settings → Maximum download timeout.
- SSL errors — often caused by Force HTTPS on supplier URLs rewriting an
http://URL for a host with a broken certificate. Un-tick it if your supplier genuinely only serves HTTP.
How the retry ladder works
- Every image climbs an escalating-timeout ladder: 3 s, 6 s, 12 s, 24 s, then up to 3 attempts at the 30 s ceiling (both ends configurable). The wait between attempts escalates too (attempt count × the retry-spacing setting), so nothing gets hammered.
- An image that exhausts the ladder is marked failed, stops being retried automatically, and appears in the Failed Images tab with its reason, attempt count and per-row Retry now / Dismiss actions.
- Manual override: the Retry All Failed Images button (or
wp dii retry-failed, with--host=to target one supplier) re-queues failures with a completely fresh ladder — use it after fixing whatever was wrong at the source.
Duplicate images in the media library
The plugin dedups by URL: before downloading, it checks whether any attachment already carries that exact URL in its original_image_url meta, and reuses it. The Loaded Images tab has a “Dupes” column showing how many attachments share each remote URL — anything above 1 in red predates the dedup (added in 2.23) or was created by a concurrent run.
Two honest caveats:
- Dedup is exact-URL. The same image at two different URLs (e.g. with/without a cache-busting query string) downloads twice.
- Images downloaded inline by Super Speedy Imports 2.55+ are tracked in SSI’s own lookup table, not in
original_image_urlmeta, so DII can’t currently see them (and vice versa). If you switch a catalogue between inline and deferred imports you can get duplicates across that boundary. A dedup bridge is on the roadmap.
Everything is stuck and I just want to start fresh
In order of escalation, all non-destructive to your actual images:
- Settings → Clear cooldowns — removes all per-post failure cooldowns.
- Settings → Clear locks — removes stale in-flight locks (safe unless a download is genuinely running this second).
- Retry All Failed Images (admin) or
wp dii retry-failed(CLI) — every failed image goes back in the queue with a fresh ladder. - Process a batch now (Status tab) — run a batch synchronously, bypassing cooldowns and host backoffs, and see the result immediately.
wp dii load-all— synchronously drain the whole queue while you watch.
Still stuck?
Turn on Diagnostic logging (Settings → Diagnostics), reproduce the problem once, and send us the DII lines from wp-content/debug.log plus the output of wp dii status and wp dii failed --format=csv. That’s everything we need to diagnose it.

Comments