Quick Start Guide
Delayed Image Import turns slow imports into fast ones by skipping the image-download step entirely. Your importer writes URLs to a couple of post-meta fields and finishes in seconds. Visitors still see real images immediately — the plugin serves the supplier’s remote URLs straight away — and cron / WP-CLI downloads them locally in the background.
This guide gets you from “imported a CSV” to “site is live” in five minutes.
How it works in one paragraph
When you import, instead of downloading every product image into your media library (slow, ratelimit-prone, eats disk), you write the supplier URLs to two specific post-meta keys. That’s the whole import-time job. On the front end, the plugin’s renderer sees those meta keys and outputs the supplier URL directly in the <img src> — visitors see the real product image straight from the supplier’s CDN. Behind the scenes, a popularity counter ticks up every time a remote URL is rendered, and cron / WP-CLI processes the most-popular un-hydrated images first. Once an image is downloaded locally, the local URL is served from then on.
No JavaScript. No AJAX. No REST. Just two post-meta keys and a background download queue.
There is no placeholder phase. Because un-hydrated images are hot-linked from the supplier’s own CDN, your server does zero image work on the page view and search engines crawling the page see real images from the very first request.
The minimum: map your URLs to two meta keys
That’s it. Two keys.
Featured image
Write the supplier URL to the delayed_image_url post-meta key on the product (or post).
post_meta: delayed_image_url = "https://supplier.tld/image.jpg"
Gallery images (WooCommerce products)
Write the supplier URLs to the delayed_gallery_image_urls post-meta key, pipe-separated (|).
post_meta: delayed_gallery_image_urls = "https://supplier.tld/img-a.jpg|https://supplier.tld/img-b.jpg|https://supplier.tld/img-c.jpg"
Pipe (|) is the only supported separator — don’t use commas. Many supplier URLs contain commas in query strings, so a comma fallback would misclassify URLs. Comma-separated values are treated as ONE URL and fail to download.
That’s all the configuration this plugin needs. Run your import, finish in a tenth of the usual time, visit a product page — the image is there.
Optional: import the image meta too
If your CSV has alt text / titles / captions / descriptions, you can defer those alongside the URLs and they’ll be applied to each attachment when the image is eventually downloaded.
Featured image meta
| Post-meta key | Holds |
|---|---|
delayed_image_alt | The _wp_attachment_image_alt value |
delayed_image_title | The attachment’s post_title |
delayed_image_caption | The attachment’s post_excerpt |
delayed_image_description | The attachment’s post_content |
Each is a plain string. Empty values are skipped — never blanks existing attachment metadata.
Gallery image meta
Each of these is a pipe-separated string positionally aligned with delayed_gallery_image_urls. So the alt text for the third gallery image is the third entry in delayed_gallery_image_alts.
| Post-meta key | Holds |
|---|---|
delayed_gallery_image_alts | Alt text per gallery image, pipe-separated |
delayed_gallery_image_titles | Titles, pipe-separated |
delayed_gallery_image_captions | Captions, pipe-separated |
delayed_gallery_image_descriptions | Descriptions, pipe-separated |
Example:
delayed_gallery_image_urls = "url1|url2|url3"
delayed_gallery_image_alts = "Red shoe side view|Red shoe top view|Red shoe sole"
delayed_gallery_image_titles = "RX-200 side|RX-200 top|RX-200 sole"
You don’t have to populate all four — write whichever ones you have data for.
Super Speedy Imports shortcut
If you’re using Super Speedy Imports as your importer, you don’t need to map anything to these post-meta keys at all — and as of DII 2.26 you don’t even need to tick a box.
Deferring is ON by default while this plugin is active. Map your featured image and gallery columns in SSI as normal, run the import, and SSI automatically writes the URLs (and any alt / title / caption / description fields you mapped) into the delayed_* post-meta keys instead of downloading inline. This applies to every SSI import — including ones you configured before this plugin was activated.
To turn it off for a specific import, un-tick the Defer image downloads checkbox in SSI’s Additional Options panel and save. That import then downloads its images inline the old way; the un-tick is remembered per import.
One exception: SSI’s “Only refresh images” import mode always downloads inline, because refreshing images now is the whole point of that mode.
Defer-by-default arrived in DII 2.26 (paired with Super Speedy Imports 2.72+). Before that you had to tick a box on every import.
Background processing
Two ways to download the deferred images locally.
The background cron (on by default)
As of 2.26 the background cron is enabled out of the box — you don’t need to visit the settings page at all. Every minute, WP-Cron picks the most-requested un-hydrated images (the ones visitors have actually viewed get processed first), downloads a batch of up to 100 with the configured timeout, applies the meta, and they switch to local URLs from then on. Downloads round-robin across supplier domains so no single host gets hammered.
To tune it, go to Super Speedy → Delayed Image Import → Settings → Background cron: tick interval (default 1 minute), batch size (default 100), same-domain throttle. Un-tick Enable cron if you’d rather rely on visitor traffic and WP-CLI only.
Note WP-Cron itself only fires when your site gets requests. On a quiet staging site, either browse a few pages, run wp cron event run dii_process_batch, or use the CLI commands below.
Use the WP-CLI commands
Faster for bulk pre-warming after an import. Run any of these from the command line:
wp dii status One-line health summary (add --watch to poll)
wp dii pending Image-level counts of delayed / loaded / failed images
wp dii load-featured Bulk-download every delayed featured image
wp dii load-galleries Bulk-download every delayed gallery image
wp dii load-all Both - featured plus gallery
wp dii failed List failed images with reason / attempts / when
wp dii retry-failed Re-queue failed images with a fresh retry ladder (--host= for one supplier)
wp dii pause / resume Toggle the background hydration cron
Common workflow after a big import:
wp dii pending
wp dii load-featured --batch=100
wp dii load-galleries --batch=100
wp dii pending # check there's nothing left
A few things worth knowing
Visitors see real images, not placeholders. Until an image is downloaded locally, the renderer outputs the supplier’s URL directly in <img src>. The visitor’s browser fetches it from the supplier’s CDN. There’s no placeholder flicker, no AJAX, no JavaScript. Search engines crawling the page see real images too.
Deduplication is automatic. If 100 products share the same image URL, the plugin creates exactly one local attachment and reuses it. No CLI cleanup needed — the dedup check happens at download time before any file is written.
The Status tab tells you where you are. A progress bar with image-level counts (pending / loaded / failed), downloads-per-hour with an ETA, a cron heartbeat that goes red when WP-Cron has stalled, per-supplier stats, and one-click Process-a-batch-now / Pause buttons. The counts auto-refresh while images are pending, so you can watch the backlog drain. There’s also a dashboard widget and an admin-bar count so you don’t have to keep the page open.
An escalating retry ladder handles slow suppliers. Every image’s download timeout starts short (default 3 s) and doubles on each failure — 3, 6, 12, 24 — up to a 30-second ceiling, with the wait between retries growing too. Three failures at the ceiling mark the image failed and it lands in the Failed Images tab with its reason, attempt count, a live preview of the remote URL and one-click Retry / Dismiss actions. So dead URLs fail fast, slow suppliers succeed on the patient rungs, and only the genuinely unreachable need a human.
Hot-link-blocking suppliers degrade gracefully. Some image hosts return 403 when a browser loads their URL cross-origin. The plugin emits an onerror fallback to a local SVG placeholder so visitors see something instead of a broken image, and you can add those hostnames to the Hot-link blocklist in Settings so the SVG renders directly without a network attempt.
With the defaults (one cron tick per minute, batch of 100 posts) you drain roughly 6,000 posts’ worth of images per hour, so a 50,000-product catalogue finishes overnight. wp dii load-all does the same job now instead of overnight.
Troubleshooting checklist
There’s a full guide covering downloads-not-happening, failed images, hot-link 403s and more — see Troubleshooting Delayed Image Import. The quick version, if un-hydrated products show no image on the front end:
- Check the Status tab — does it show pending featured / gallery counts? If zero, no products were deferred. Check your importer’s column mapping.
- Pick one product and inspect its post-meta directly:
SELECT * FROM wp_postmeta WHERE post_id = <id> AND meta_key LIKE 'delayed_%'. Ifdelayed_image_urlis empty, the importer didn’t write to the right key. - View source on the archive / product page. Look for
class="dii-remote"on the image tag — that confirms the renderer is emitting the supplier URL. If you seeclass="woocommerce-placeholder", the renderer didn’t see the post (file a bug with the URL). - Turn on Diagnostic logging in Settings → Diagnostics, reload the page, then check
wp-content/debug.logforDII-prefixed lines. Each render decision is logged with the post ID and which branch it took.
Where the data ends up
Once an image is downloaded:
- A normal WP attachment is created (under
wp-content/uploads/<yyyy>/<mm>/) _thumbnail_idis set on the product so it renders the local URL from then on_product_image_galleryis populated with the gallery attachment IDs- The image meta you supplied is applied (alt / title / caption / description)
- The attachment carries an
original_image_urlpost-meta pointing back at the supplier URL — this is what powers the dedup check on future imports - The
delayed_*meta keys are cleaned up
From that point on the product is indistinguishable from one imported the old slow way — except yours took seconds instead of hours.

Comments