preloader

WordPress Images Not Showing After Migration: How to Fix

Images break after migration because WordPress stores full URLs in the database, not relative paths. When the domain changes, those stored URLs still point to the old domain. The files exist on the new server. The browser requests them from the old one. Right-click a broken image in your browser and check the src attribute – if it shows your old domain, the database needs a search-replace. If it shows the new domain with a 404, the file is actually missing.

Understanding Why Images Break After Migration

WordPress stores image URLs in the database, not relative paths. When you upload an image, WordPress saves the full URL: https://oldsite.com/wp-content/uploads/2024/01/photo.jpg. After migration to a new domain or host, the image file exists at https://newsite.com/wp-content/uploads/2024/01/photo.jpg but the database still contains the old URL. WordPress renders the old URL in the HTML, the browser requests it from the old domain, and the image fails to load.

Step 1: Confirm the Cause

Right-click a broken image in your browser and select “Inspect”. Look at the src attribute of the img tag. If it shows your old domain (oldsite.com) instead of your new domain, the database URL issue is confirmed. If it shows the correct new domain, the file is missing or in the wrong location.

Problem not solved? Describe the issue and get a free estimate.

Step 2: Run a Search-Replace on the Database

Install the Better Search Replace plugin (free). Go to Tools -> Better Search Replace. Configure:

  • Search for: your old domain (https://oldsite.com)
  • Replace with: your new domain (https://newsite.com)
  • Select Tables: select all tables
  • Run as dry run: check this first to preview changes without applying them

Run the dry run first. It shows how many replacements would be made across which tables. If the numbers look reasonable (hundreds to thousands depending on site size), run it again with “Run as dry run” unchecked to apply the changes. Clear all caches after running the replacement.

Step 3: Fix Hardcoded URLs in Theme Files

If images in posts and pages are fixed but images in the header, footer, or background are still broken, those URLs are hardcoded in theme files rather than stored in the database. Search your theme files (in wp-content/themes/your-theme/) for the old domain. Edit the affected files and replace the old URL with the new one. This is most common in child themes where images were added directly to CSS or PHP files.

Step 4: Check SSL Protocol Mismatch

If you migrated from HTTP to HTTPS (or vice versa), images stored with the old protocol fail to load. The browser blocks HTTP images on HTTPS pages (mixed content security policy). The Better Search Replace approach handles this – search for http://yoursite.com and replace with https://yoursite.com. Run it as a separate pass from the domain change if you changed both domain and protocol.

Step 5: Regenerate Thumbnails

If the original image files are present and correctly referenced but thumbnails (smaller sized versions WordPress creates) are not displaying, regenerate them. Install the Regenerate Thumbnails plugin. Go to Tools -> Regenerate Thumbnails and run the regeneration. This creates all required thumbnail sizes from the original uploaded images.

Thumbnail regeneration is needed when: migrating to a site with different image size settings, changing themes (new theme may require different thumbnail dimensions), or when thumbnail files were not included in the migration.

Manual Database Search-Replace via SQL

If you cannot install the Better Search Replace plugin (the site may be too broken to access admin), run the search-replace directly in phpMyAdmin. Log into phpMyAdmin, select your database, and go to the SQL tab. Run this query:

UPDATE wp_posts
SET post_content = REPLACE(post_content,
    'https://oldsite.com',
    'https://newsite.com');

UPDATE wp_postmeta
SET meta_value = REPLACE(meta_value,
    'https://oldsite.com',
    'https://newsite.com');

UPDATE wp_options
SET option_value = REPLACE(option_value,
    'https://oldsite.com',
    'https://newsite.com')
WHERE option_name NOT IN ('active_plugins', 'cron');

Do not run this on wp_options without the WHERE clause – the active_plugins and cron values are serialised PHP arrays where a simple string replace corrupts the data structure. The Better Search Replace plugin handles serialised data correctly; raw SQL does not. For a quick targeted fix this SQL works on text content. For serialised meta values, use the plugin.

Keep Reading

Previous Post WooCommerce Checkout Not Working: Causes and Fixes Next Post WordPress Updates Failing: How to Fix Update Errors

Need Help With Your WordPress Site?

If you need help with WordPress fixes, plugin issues, theme customization, or development work, feel free to get in touch.

Get a Free Estimate