Repair WordPress image meta

There are times when things just go wrong. I had one of those times the other day. The pressure was on to deliver a project, and there were bits of PHP and CSS and JavaScript flying everywhere here at WebAware Central. And so it happened: I wiped the image attachment meta data in the WordPress database.

I’m still not quite sure how I did it, but I think it was a filter hook to a non-existent function in the middle of thumbnail regeneration. WordPress relies on a postmeta field called ‘_wp_attachment_metadata’ for information like the image height and width, and the different thumbnail sizes and filenames. Without it, WordPress isn’t able to serve up thumbnails, or size medium, or any custom image sizes defined by plugins.

Backups! Yes. Great, except we loaded a bunch of new images during the day and the backup was basically the next thing that was going to happen. Too late.

Simply running Regenerate Thumbnails, or my custom bottle size regeneration tool, didn’t work either; they both need the width and height of the full-sized image, and WordPress gets that from… the image attachment meta. The thumbnails themselves are actually regenerated, if you look in the uploads folder; but without the meta, WordPress just doesn’t see them.

So: the fix. It’s surprisingly easy to regenerate image attachment meta from the full-sized images. The process is essentially this:

  • get a list of images from WordPress
  • get the filename of each image, usingĀ get_attached_file()
  • get the width and height of each image, usingĀ getimagesize()
  • create the image attachment meta array for each image
  • update in the database

Easy. I just hooked up the code below to an admin menu item, and ran it. Bob is, apparently, a close relation on my mother’s side. And then, Regenerate Thumbnails fixed all the thumbnail sizes. Yay!

/**
* fix broken image metadata so that thumbs can be regenerated
*/
function fixImageMeta() {
    global $wpdb;

    $sql = "
        select ID from {$wpdb->posts}
        where post_type = 'attachment'
        and post_mime_type like 'image/%'
    ";
    $images = $wpdb->get_col($sql);

    foreach ($images as $id) {
        $meta = wp_get_attachment_metadata($id);
        if (!$meta) {
            $file = get_attached_file($id);
            if (!empty($file)) {
                $info = getimagesize($file);
                $meta = array (
                    'width' => $info[0],
                    'height' => $info[1],
                    'hwstring_small' => "height='{$info[1]}' width='{$info[0]}'",
                    'file' => basename($file),
                    'sizes' => array(),         // thumbnails etc.
                    'image_meta' => array(),    // EXIF data
                );
                update_post_meta($id, '_wp_attachment_metadata', $meta);
            }
        }
    }
}

Job is done, taking me to about 2:30am and bed. I reckon I’ll wrap this up in a plugin sometime, with EXIF metadata as well, “just in case”. Unless someone beats me to it… :)

Update: someone has beaten me to it (see what happens when you wait long enough?) with the plugin Fix my posts. Thanks Philipp! Note also that Philipp uses the WordPress function wp_generate_attachment_metadata() to create the meta array, and generate a thumbnail. Easier than cobbling that together yourself.

Facebooktwittergoogle_plusredditlinkedinmailFacebooktwittergoogle_plusredditlinkedinmail
  • yasir

    You are awesome! It helps me so much since all of my images lost their size caused by failed upload. Thanks so much :)
    I have one question, after i get back all my image size, should I delete that codes or i can let them there in case I get another fail?

    thanks

    • G’day Yasir, you might as well delete the code — but maybe bookmark this post in case it happens again. I hope to make this a plugin sometime this year, unless someone beats me to it. In which case, it’ll probable be improved a bit (e.g. grab the EXIF metadata too) and will be easy to set up and run.

      cheers,
      Ross

  • Hi Ross, thank you for sharing this, specifically the code. You saved me lots of time.

  • josh

    Where do I add this code? I’m wanting to bulk create posts 20K plus and I would love to be able to do this without having to go through some black magic excel concatination structure to re-create this mish mosh field.

    I REALLYYYYYYY hope you find this note. I’m just confused on where to put this code to test this.

    Please help!

    • G’day Josh,

      If you’re importing a bunch of external data as posts and want to import images for them, you should look at using the WordPress functions media_sideload_image or media_handle_sideload to do the work for you. The snippet above is for repairing metadata about images already loaded.

      cheers,
      Ross

      • josh

        I looked at the referenced links you sent me, I’m not to sure how to implement this type of code. I’ve worked a lot with creating custom functions but this looks you create a new php page all together, am I following that correctly and this type of function would be added to the admin side?

        I’ve never really messed around with admin side PHP code because to be quite honest, i’ve never had a need nor have I understood it :(

        The situation I have is I’m creating custom post types equivalent to an album in a photo gallery. and when I look at the code generated in the database under the _post table I see something like the following as headings
        ID post_author post_date post_date_gmt post_content post_title post_excerpt post_status comment_status ping_status post_password post_name to_ping pinged post_modified post_modified_gmt post_content_filtered post_parent guid menu_order post_type post_mime_type comment_count

        All of that is groovy and I could see how to manipulate all of that data but where I’m getting lost on the process is the _postmetaData particularly the “_wp_attachment_metadata” That is like a bunch of garbledy gook
        a:5:{s:5:width";i:215;s:6:"height";i:250;s:4:"file";s:21:"2013/12/9th_ARS_7.jpg";s:5:"sizes";a:1:{s:9:"thumbnail";a:4:{s:4:"file";s:21:"9th_ARS_7-150x150.jpg";s:5:"width";i:150;s:6:"height";i:150;s:9:"mime-type";s:10:"image/jpeg";}}s:10:"image_meta";a:10:{s:8:"aperture";i:0;s:6:"credit";s:0:"";s:6:"camera";s:9:"HP oj5600";s:7:"caption";s:0:"";s:17:"created_timestamp";i:0;s:9:"copyright";s:0:"";s:12:"focal_length";i:0;s:3:"iso";i:0;s:13:"shutter_speed";i:0;s:5:"title";s:0:"";}}"

        I could in theory do some behind the scenes excel magic but I want to avoid that at all costs. I think I’m like 90% of the way there to create custom posts via the database just need to fine tune these last few bits. :( This might be the wrong avenue to go down

        • You’re best off using an importer plugin that handles all of that for you, like Import External Images or Image Gallery Import. Alternatively, you could write code using the functions I mentioned above and hook that off an admin menu item to run it by using add_management_page — this means writing PHP code for a simple plugin.

          If you need further help on this, I suggest you start a question on WordPress Answers — and be detailed about what you are trying to do. There’s a bunch of WordPress developers there waiting to help you (including me).

          cheers,
          Ross

  • Hi Ross,

    I was importing 3000 images from another CMS to WordPress recently and needed to create metadata + thumbnails for all of them. So your post was VERY helpful for that!

    So finally I bundled my code into an officiall plugin that you can use: You’ll find it at http://wordpress.org/plugins/fix-my-posts/

    BTW, a small hint: WordPress offers the core-function wp_generate_attachment_metadata($post_id, $imagepath) that will create the complete metadata array PLUS create all thumbnails.

    • G’day Philipp, excellent work! I’ve updated the post above to let people know they can use your plugin, and also about that function. Well done!

      cheers,
      Ross

  • arkid77

    This didn’t work for me. I had absolutely no meta data for each image inside of wp_postmeta and in the current 3.8 wordpress at least it wasn’t enough to add only a _wp_attachment_metadata entry. I had to add a _wp_attached_file one as well.

    I have made large modifications to your code and won’t post here as its a bit of a mess and long but you can find here: http://www.adam-makes-websites.com/discoveries/fixing_messed_up_image_attachments_in_wordpress_that_have_no_postmeta_values

  • Gru

    Just THANKS !

  • function fixFeatureImageAttached() {

    global $wpdb;

    $sql = ”

    select ID, guid, post_parent from {$wpdb->posts}

    where post_type = ‘attachment’

    and post_mime_type like ‘image/%’

    “;

    $images = $wpdb->get_results($sql);

    foreach ($images as $id_guid) {

    $id = $id_guid->ID;

    $guid = $id_guid->guid;

    $post_parent = $id_guid->post_parent;

    $meta = wp_get_attachment_metadata($id);

    if (!$meta) {

    $file = get_attached_file($id);

    // create attached_file

    if(empty($file)){

    $meta = preg_replace(‘/http://YOURDOMAIN.COM//’,”,$guid);

    update_post_meta($id, ‘_wp_attached_file’, $meta);

    $file = get_attached_file($id);

    }

    $info = getimagesize($file);

    $meta = array (

    ‘width’ => $info[0],

    ‘height’ => $info[1],

    ‘hwstring_small’ => “height='{$info[1]}’ width='{$info[0]}'”,

    ‘file’ => basename($file),

    ‘sizes’ => array(), // thumbnails etc.

    ‘image_meta’ => array(), // EXIF data

    );

    update_post_meta($id, ‘_wp_attachment_metadata’, $meta);

    update_post_meta($post_parent, ‘_thumbnail_id’, $id);

    }

    }

    }

    fixImageMeta();