Yet another programmer blogging about code

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.