How to recover old images in WordPress

Ciprian on Monday, June 13, 2022 in WordPress

NEW! Learn JavaScript by example. Code snippets, how-to's and tutorials. Try now!

This article is about how to recover old images in WordPress that are still using obsolete or missing sizes.

Let’s take, for example, an image that has been uploaded years ago, and is now referenced in countless posts as my-awesome-image-1920x1080.jpg. As you know, WordPress creates multiple image sizes based on what the theme requires. In some cases, plugins might add additional image sizes.

Table of Contents

Disclaimer: This depends on how your theme is structured, and it’s a very specific use-case. In my case, it is a front-end block-based page builder which saved images and content in a blob of text.

BLOB is a binary large object that can hold a variable amount of data. The four BLOB types are TINYBLOBBLOBMEDIUMBLOB, and LONGBLOB. These differ only in the maximum length of the values they can hold.

Why is WordPress generating multiple image sizes?

Whenever you upload an image, WordPress automatically creates 4 different image sizes:

  • Thumbnail size: 150×150 pixels
  • Medium size: maximum 300×300 pixels
  • Large size: maximum 1024×1024 pixels
  • Full size: the original size of the uploaded image

WordPress does this, so you don’t have to keep resizing images manually and to ensure the best image size is selected for different locations on your website. This is set in Settings → Media.

Additional images are created using the add_image_size() function.

WordPress missing images

How to remove old image sizes?

Over time, your theme might change or might get refactored, in order to keep up with the web industry or with design trends. As a result, image sizes might change or get removed altogether. Resizing featured images is easy, as you can install a thumbnail regeneration plugin and let it run overnight. What do you do if you have hardcoded images, using either the classic editor or a deprecated page builder?

Here’s what happened to one of my client websites:

Thousands of posts contain references to old image sizes. Running through all these posts in the database and changing the image sizes would be overkill. So, my solution was to keep the images in the post and replace them on demand, on display.

Get all images in the content and remove the -1920x1080. string from all content

I have included the dot (.) to make sure the image size is the last part of the image URL.

// $content is a blob of text containing the actual post content, HTML and text
$content = preg_replace( '/-\d+x\d+\./i', '.', $content );

return $content;

Remove size using a regular expression and return the content

This is enough to keep everything working and not delete any content. Regular expressions are very expensive (slow) and prone to errors. Running a database replace loop would be a high-risk operation.

Next steps

Next, in order to make the process more robust, I decided to extract the original images (using the steps above) and get their IDs. Using these IDs, I would next attach the original images to the current post, making it easier in the future to display the posts and their attached images.

$content = preg_replace( '/-\d+x\d+\./i', '.', $content );

// Strip all tags except for images
$content = strip_tags( $content, '<img>' );

$dom = new \DOMDocument();
$dom->loadHTML( $content );

$dom->preserveWhiteSpace = false;

$images    = [];
$image_ids = [];

// Extract the src attribute (the original, full size image)
foreach ( $dom->getElementsByTagName( 'img' ) as $image ) {
    $images[]    = $image->getAttribute( 'src' );
    $image_ids[] = wpps_get_image_id_by_url( $image->getAttribute( 'src' ) );
}

// Attach all images to the post
foreach ( $image_ids as $key => $id ) {
    $attachment = [
        'ID'          => $id,
        'post_parent' => $post_id, // declared above
        'menu_order'  => 1,
];

// Insert the attachment (returns the attachment ID)
$attachment_id = wp_update_post( $attachment, $filename, $post_id );

clean_attachment_cache( $id );

There, now I have all original images attached to the post. When I refactor my single post template, I can display the attached images programmatically, by running a loop over all attachments and delete the old images from the post content.

Related posts

Leave a Reply