How External Images Works
External Images changes one thing about WordPress, but it is a thing that touches your disk usage, your import times and your page speed all at once. This article explains the mechanism, what the plugin does instead of the default, and where it plugs into your site. If you just want the practical steps, read the External Images Quick Start Guide first and come back here when you want to understand why it behaves the way it does.
What WordPress does by default
Out of the box, WordPress treats every image as something it must own. When you set a featured image, add a product image in WooCommerce, or run an importer that maps an image column, WordPress downloads the full image file onto your server and creates a Media Library attachment for it. It does not stop at one copy. For each original it generates a set of resized derivatives, thumbnail, medium, large, and whatever extra sizes your theme and WooCommerce register, so a single source image commonly becomes five, ten or more physical files on disk.
For a handful of hand-written posts this is fine. At scale it is the single biggest bottleneck on the site. Consider an affiliate or feed-driven catalogue of tens or hundreds of thousands of products. The importer has to fetch every remote image over the network, wait for it, write it, then spend CPU regenerating every registered size. Image download and resize is almost always the slowest stage of a large import, and it is the stage that fails intermittently when a remote host is slow or rate-limits you.
Skipping the image download is where the headline “20 times faster imports” comes from. When the importer no longer fetches, writes and resizes every image, what is left is mostly database writes, which run quickly. On a large feed-driven catalogue this is usually the difference between an import that finishes and one that stalls.
On top of the time cost you inherit the storage cost. Millions of files under wp-content/uploads make backups enormous, slow to restore, and awkward to move between servers. And because the images now live on your disk, you own the job of backing them up and regenerating them if a size ever changes.
What External Images does instead
External Images skips the download entirely. Rather than copying a remote image into the Media Library, it stores the image URL, exactly as it lives on the affiliate CDN, supplier feed, S3 bucket or your own image subdomain, in a custom field on the post or product. The meta key is external_image_url. There is no attachment, no resized derivatives, and nothing written to your uploads folder for that image.
Multiple URLs are held in that same single field, separated by the pipe character. The first URL becomes the featured image and the remaining URLs become the gallery. You can confirm this in the code: the plugin reads external_image_url and splits it with explode on the pipe (a legacy comma separator is still tolerated, but pipe is the safe one because commas can appear inside image URLs). Alt, title and caption text live in three parallel fields, external_image_alts, external_image_titles and external_image_captions, in the same order as the URLs.
There is also an internal, private counterpart, _external_image_url (with a leading underscore), plus _ei_wcgallery and an ei flag. These are the plugin’s own processed representation and you never write to them directly. You always import into external_image_url, the version with no leading underscore. Importing into the underscore field is the most common reason a URL saves but no image appears.
Always write your URLs into external_image_url (no leading underscore). The underscore fields (_external_image_url, _ei_wcgallery) are the plugin’s private processed copies. Import into an underscore field and the URL saves, but no image ever renders.
Where it hooks in
External Images intercepts the points where WordPress and WooCommerce would normally reach for a local attachment, and hands back your external URL instead. In practice that means:
- Featured images. The plugin filters post_thumbnail_html and the has_post_thumbnail and thumbnail-id checks, so any theme or block that renders the featured image gets your external URL, and code that asks “does this post have a thumbnail?” is answered truthfully even though no attachment exists.
- WooCommerce product images. It filters the product image id and the attachment URL resolution so the main product image on shop, archive and single pages comes from external_image_url.
- Galleries. It filters the WooCommerce gallery image ids (woocommerce_product_get_gallery_image_ids) so the gallery thumbnails under the main image are built from the remaining pipe-separated URLs.
- Variation images. It filters the variation gallery ids and swaps variation images in via an admin-ajax endpoint (ei_get_variation_images) so selecting a variation shows that variation’s own external images.
Behaviour around galleries and variations is tunable with constants defined in defines.php, including EI_ADD_FEATURED_IMAGE_TO_GALLERY, EI_SHOW_VARIATION_IMAGES_IN_MAIN_GALLERY, EI_GRAB_PARENT_GALLERY_IF_NO_GALLERY and EI_VARIATION_GALLERY_WRAPPER_CSS (which names the theme’s gallery wrapper selector, defaulting to .woocommerce-product-gallery). You rarely need to touch these unless a particular theme’s gallery markup needs pointing at.
In the editor, the plugin adds its own boxes beside the standard featured image area: an “External Featured Image” box and an “External Images Gallery” box, both registered in the sidebar below the native Featured Image panel. That is where you paste URLs by hand for a single post or product. See Changing external images for WooCommerce products manually and Adding external images to posts or custom post types for the hands-on version.
The SSL proxy, briefly
Serving a third-party image straight from its origin is usually fine, but sometimes the origin is plain http on an https page (mixed content), or a social scraper refuses an off-domain image. For those cases External Images can serve a remote image through your own domain so it appears to come from your site. It does this two ways: an optional “Proxy All Images” mode that fetches and caches remote images under wp-content/uploads/external-images/ and serves the cached copy from your domain, and a lightweight pass-through in ssl-proxy.php that streams a remote image out under your hostname on request. It also proxies Datafeedr comparison-set images through SSL. Proxying costs a first-load fetch and some disk, so it is off by default; the constant EI_NEVER_ATTEMPT_PROXY disables it outright. The full treatment, including when to turn it on, is in The SSL Image Proxy.
Still real images, nothing to maintain
An important point for SEO: nothing here is a trick or a hotlink hack that search engines dislike. What renders on the page is an ordinary img tag pointing at a real, reachable URL, with your alt, title and caption text attached from the parallel fields. Crawlers, PageSpeed and social scrapers see a normal image. It is SEO-neutral compared with a locally hosted image, and where http origins or scrapers are a problem the proxy makes the image look local anyway.
Because the page renders a normal img tag pointing at a real URL, with your alt, title and caption text attached, search engines and social scrapers treat it exactly like a locally hosted image. There is no hotlinking trick and no SEO penalty.
Because nothing is copied to your server, there is nothing local to look after. No attachments to back up, no thumbnail sizes to regenerate when your theme changes its registered sizes, and no uploads folder ballooning as your catalogue grows. The image is wherever you already host it, and your WordPress database just holds the URL. For a wider view of where you can safely host those images, see Guide to Third Party Storage, and if you are still deciding whether this model suits your site at all, Do I Need External Images? walks through the trade-offs.

Comments