External Images Troubleshooting

July 4, 2026

This page collects the most common External Images problems and their fixes, based on five years of support in our Discord server. If your issue isn’t here, see the Frequently Asked Questions or ask us on Discord.

The URL is there but the image is broken or blank (the #1 issue)

If a product clearly has an image URL but shows a broken or placeholder image, work through these in order – together they explain the large majority of “no image” reports:

  • Wrong field. You must import into external_image_url (no leading underscore). WP All Import sometimes suggests _external_image_url – that’s the private serialized field and importing to it bypasses the hooks that build the image, so the front end looks broken. See the field reference in the FAQ.
  • do_action calls disabled. If you disabled do_action calls in WP All Import for speed, External Images’ hooks never fire, so the images aren’t mapped. Fix: add a custom field to your import that sets ei_converted to 0 (see the next section).
  • Cache. Flush your object cache – with Redis, changes aren’t shown until you flush.

Re-running an import doesn’t update the images or texts (the ei_converted flag)

External Images sets the postmeta flag ei_converted to 1 once it has mapped a post’s images into its internal fields. If you re-import with changed URLs, alt/caption/title text, or a new gallery order and nothing updates, it’s because that flag is still 1 (this happens when do_action calls are disabled). The fix is to set it back to 0 – add an extra custom-field update to your import that writes ei_converted = 0 (rather than 1). External Images then re-reads external_image_url and rebuilds the featured image, gallery, variation images, variation galleries and all the alt/caption/title texts next time the post is used. Setting ei_converted to 0 is also the fix after you manually delete a product’s media-library entry and want it regenerated.

Long image URLs save but don’t appear in Media (no image, or no alt/caption/title)

WordPress stores the “fake” attachment URL in the guid column of wp_posts, which defaults to varchar(255). If your URLs are longer than 255 characters (common with Cloudinary and on-the-fly resizer URLs), WordPress refuses to insert the fake attachment – so the image may not appear in galleries or variation galleries, and can’t carry alt, caption or title text. The featured image often still works via a fallback path, which is why only galleries seem affected. It’s purely the length, not commas or == in the URL. Fix by widening the column:

SET sql_mode='';
ALTER TABLE wp_posts MODIFY COLUMN guid varchar(2048);

Then re-save the affected products, or force a re-map by setting ei_converted to 0. Note you may need to re-run this on a fresh WordPress install. Alternatively, use shorter URLs or a URL shortener.

This means your import is passing an empty value between the pipe separators. To be fast, External Images doesn’t check whether an image exists (and can’t just test for .jpg/.png, since extensionless image URLs are valid), so it only skips an image when it receives a genuinely empty string between the | separators. If you build image URLs by concatenating a domain + path + extension, add a test at the start of your concatenation function so that when the path part is empty it returns an entirely empty string. This is covered in the import guide.

Multiple images: use the pipe separator, not commas

Load all your image URLs into external_image_url separated by the pipe | character (the first URL becomes the featured image, the rest become gallery images). Commas are still accepted for backwards compatibility, but pipes are safer because commas can appear inside image URLs – a missing image with commas produces a broken value like image.jpg,,. A WP All Import example to convert commas to pipes: [str_replace(',', '|', {additional_image_link[1]})]. Also remove any query string like ?auto=webp&quality=75 from the URLs if a gallery image won’t display. (Spaces around the pipe were a bug fixed in 3.28, but trimming them is still good practice.)

Cloudflare is caching posts/products without images after a WP All Import

This happens because WP All Import creates the post first and adds the image custom fields a moment later, by which point Cloudflare has already cached the post without images (flushing the Cloudflare cache makes them appear). Newer versions map the images immediately at import via the wp_after_insert_post hook, so update first. If it persists, force the imported post to re-publish (which purges its cache) by adding this to functions.php:

add_action( 'pmxi_saved_post', 'my_publish_post', 10, 3 );
function my_publish_post( $id, $xml, $update ) {
  wp_publish_post( $id );
}

Broken images from an HTTP (non-SSL) source

External Images has two techniques for HTTP images on an HTTPS site. First, the lightest, it tries simply swapping http for https in the URL; if that image loads, it remembers it can do that for all images from that domain. If that fails, it proxies the image through your own server’s SSL certificate (which uses some server resource). If you still see broken images, right-click one and Inspect to find the failing URL – it’ll look like .../external-images/ssl-proxy.php?img=http%3A%2F%2F...; loading it directly surfaces any PHP config error. As a quick manual fix, tell External Images it can https-swap that domain by editing its stored settings:

select * from wp_options where option_name like 'eissl-%';

Find the row for the problem domain and set its value to yes (update wp_options set option_value = 'yes' where option_id = <the id>;). Better still, import HTTPS image URLs in the first place. (No MySQL access? The free SQL Executioner plugin lets admins run ad-hoc SQL.)

Images load via 301 redirects and hammer the server

Three usual causes: (1) the Proxy All Images option is on, so images load through your server – disable it to serve them directly from the remote source; (2) HTTP images are being proxied through your server via a redirect – import HTTPS URLs instead; (3) a link-cloaking plugin (e.g. WP All Import’s Link Cloaking, or an affiliate cloaker) is rewriting your image URLs – disable it, or configure it to ignore image extensions (jpeg|jpg|gif|png|webp) and only touch anchor tags. A cloaker is also the usual reason Photon/Jetpack resizing or a CDN “isn’t taking effect” – the URLs are being masked before they reach the browser.

Your theme adds an extra “missing image” placeholder on archive pages

Some themes hook their own image HTML onto the WooCommerce product loop. Install the Simply Show Hooks plugin, visit the archive, and find the hook and function drawing the placeholder (e.g. woodmart_template_loop_product_thumbnail on woocommerce_before_shop_loop_item_title). Remove it in your theme’s functions.php:

remove_action('woocommerce_before_shop_loop_item_title', 'woodmart_template_loop_product_thumbnail', 10);

Change the function name and priority to whatever Simply Show Hooks reveals for your theme. If the theme adds the action dynamically part-way through the page, wrap the removal so it runs on the hook itself:

add_action('woocommerce_before_shop_loop_item_title', function() {
    remove_action('woocommerce_before_shop_loop_item_title', 'woodmart_template_loop_product_thumbnail', 10);
}, 1);

Clear your page cache and retest. Your product detail page may have equivalent theme actions (e.g. Woodmart’s woodmart_on_product_image galleries) to remove the same way.

If the featured image is missing on the product page but the gallery thumbnails show, disable any built-in carousel or product-gallery effects in your theme settings (for example the carousel toggle in Woodmart) – External Images ships its own gallery and the theme’s gallery JS conflicts with it. More generally, if a specific widget or shortcode (e.g. WooCommerce Product Carousel) doesn’t show external images, turn off its image resizing/cropping option: External Images can’t be resized by those custom services and crops with CSS instead.

Images are odd sizes, or don’t fill the box

To make archive images fill their container, open the External Images settings, click the Media options link, and set a width at least as large as your image container; leave height empty (or 0) unless you also enable cropping, or you’ll get odd ratios. If you enable image cropping, External Images resizes in the browser with CSS. The default crop CSS is:

.woocommerce .products .product img {
object-fit: cover!important;
max-width: 100%!important;
height: 300px!important;
}

That targets images inside .product inside .products inside .woocommerce, which also catches your related-products thumbnails. If your theme wraps related products in their own class (e.g. Rehub’s .related-woo-area), scope a smaller size to it:

.related-woo-area .woocommerce .products .product img {
object-fit: cover!important;
max-width: 100%!important;
height: 150px!important;
}

For PageSpeed “improperly sized images” warnings, use a CDN that resizes on the fly (it can add width/height), or the CSS Crop / Photon options – the plugin can’t set width/height itself without downloading images, which is the whole thing it avoids.

Thumbnails don’t appear on a property/product detail page

Rarely, a theme expects an image ID and uses it to fetch the thumbnail, instead of using the standard WordPress functions. Right-click the missing thumbnail and Inspect – if the src is empty, the theme found the thumbnail but couldn’t get its URL. Grep the theme for the container’s id/class to find the file, then copy that file into a child theme (same folder path) and change the thumbnail code to use the same variable the working full-size gallery uses. Editing in a child theme means theme updates won’t overwrite your fix. Tell us the theme on Discord and we’ll try to build the fix into the plugin.

Featured image or gallery broken with the Houzez theme

External Images works well with Houzez and massively cuts storage and import time, but a few display options need care. If the featured image doesn’t display, it’s usually because the source URL contains ) brackets and Houzez doesn’t wrap image URLs in quotes, breaking the CSS – this affects Houzez display options v1 and v6. The no-code fix is to choose display option v3, v4 or v5. If you need v1/v2/v6, add single quotes around the URL in themes/houzez/property-details/partials/media-tabs.php. If the property gallery shows only the first image, check for a PHP warning on the page (e.g. a missing latitude/longitude giving Undefined array key) – External Images’ JavaScript can mistake that warning text for a broken image and try to load the fallback. Add the missing property data, hide PHP warnings (see below), and try a different gallery display type. For heavy Houzez setups we have a dedicated Houzez add-on – ask on Discord.

Variation images don’t switch, or a variable product white-screens

First, it’s normal WooCommerce behaviour that selecting a variation swaps only the featured image while the main gallery thumbnails stay – we verified this across several themes with External Images switched off. For External Images’ own gallery switching to work, go to Settings > External Images and make sure its JavaScript is not disabled. Conversely, if a variation-swatch plugin’s own gallery conflicts (thumbnails vanish, or a variable product white-screens on some themes like Shoptimizer), disable External Images’ variation JS with a wp-config constant:

define('EI_DISABLE_VARIATION_JS', true);

or inline, which also lets you point at a custom gallery wrapper:

window.ei_js_data = window.ei_js_data || {};
ei_js_data.disable_variation_js = true;
ei_js_data.variation_gallery_wrapper_css = ".product .woocommerce-product-gallery";

If a variation shows a placeholder/empty image when selected, that’s the theme trying to show a variation image that doesn’t exist – switch off the theme’s variation-image option, or add external images to the variations themselves. For variation galleries, your theme (or a variation-gallery plugin such as woo-variation-gallery or woo-product-variation-gallery) must support them; External Images just fills in the images.

The featured image appears twice

Check wp-config.php for define('EI_ADD_FEATURED_IMAGE_TO_GALLERY', true); and remove it (or set it to false) – that constant deliberately adds the featured image into the gallery, which some themes then render twice, often only on mobile.

A gallery image is cut in half with lazy loading

Because external images have no local dimensions, a lazy loader has to guess the width and can get it wrong (seen with Flatsome). Set the image’s CSS width and height to the values you normally use, or disable lazy loading for those images – performance is unaffected either way, since the images never load from your server.

PHP warnings or deprecation notices show on the page

Messages like “Creation of dynamic property… is deprecated” are warnings, not fatal errors, and updating clears the underlying cause. To stop visitors seeing them, add to wp-config.php (a single file, even on multisite; place it above other edits, not at the very end):

define('WP_DEBUG_DISPLAY', false);

If warnings still show, check your .htaccess for php_flag display_errors On and set it to Off.

Cleaning up orphaned “fake” images after deleting products

External Images creates spoofed attachment posts (marked with the postmeta ei = 1) for theme/plugin compatibility – they take no real disk space, but deleting products can leave them orphaned. The settings page has a “clear orphaned attachments” button. If it doesn’t shift them (or your MySQL rejects the multi-table delete), back up and run SQL – delete the orphaned attachment posts, then their postmeta:

DELETE p FROM wp_posts p
LEFT JOIN wp_posts parent ON p.post_parent = parent.ID
WHERE p.post_type = 'attachment' AND parent.ID IS NULL
  AND EXISTS (SELECT 1 FROM wp_postmeta pm
    WHERE pm.post_id = p.ID AND pm.meta_key='ei' AND pm.meta_value='1');

If the postmeta delete errors with “Table ‘pm’ specified twice”, use a temp table:

CREATE TEMPORARY TABLE temp_post_ids_to_delete AS
  SELECT ei.post_id FROM wp_postmeta ei
  LEFT JOIN wp_posts p ON ei.post_id = p.ID
  WHERE ei.meta_key='ei' AND ei.meta_value='1' AND p.ID IS NULL;
DELETE pm FROM wp_postmeta pm
  INNER JOIN temp_post_ids_to_delete t ON pm.post_id = t.post_id;
DROP TEMPORARY TABLE IF EXISTS temp_post_ids_to_delete;

Flush your object cache afterwards or they’ll still show in Media. (One customer took a database from 2.7GB to 300MB this way.) There are roughly 6-7 postmeta rows per fake image.

An update won’t stick, or the plugin still shows the old version

Occasionally an update applied correctly but the version number in the header wasn’t bumped, so WordPress keeps offering the update – updating again to the current version resolves it. For a genuinely stuck install, capture the debug log, delete the plugin folder over SFTP and reinstall the latest zip. Very old installs may still be under the plugin’s former name “External WordPress Images” – deactivate and delete that before uploading the current External Images.

Still stuck? Post a screenshot on our Discord, or read the Frequently Asked Questions.

×
1/1