6

I have image resizing disabled in media settings by setting thumbnail, medium and large size dimensions all to 0.

For every photo on my blog, I upload the same photo in three sizes:

  1. large/full-size watermarked image for use in FancyBox, with all metadata intact
    • filename_large.jpg (1200x800)
  2. thumbnail image, no watermark, all metadata stripped using ImageOptim
    • filename.jpg (180x120)
  3. retina-thumbnail, no watermark, all metadata stripped using ImageOptim
    • filename_x2.jpg (360x240)
  4. maybe more sizes later...

Currently, each one of these take up separate entries in the wp_posts and wp_postmeta table. I've hooked into the media uploader to add a "Title Thumbnails" button which takes the title from the large photo and adds it to the two thumbnails with " – Thumbnail" appended.

What I would like is to have only one entry in the database for all of these images – it's the same photo after all, just in different sizes.

As it is, I'm already hooking into the add_attachment action to move the IPTC caption to the proper field as follows:

// fix our uploads by moving the caption to the proper field
add_action('add_attachment', function ($post_ID) {
    // this is triggered after an attachment is uploaded and before the attachment form gets displayed
    $post = get_post($post_ID);
    $post->post_excerpt = $post->post_content;
    $post->post_content = NULL;

    wp_update_post($post);
});

My question is, how do I hook into WordPress so that when I upload a photo, (say foo.jpg, or foo_x2.jpg) it checks if foo_large.jpg already exists and if so, just adds a new size to that photo's '_wp_attachment_metadata' key in the wp_postmeta table instead of creating a new entry in the library/database?

For what it's worth, I can see from the wp_posts table in the database that the _large.jpg file is always uploaded first, followed by the thumbnails. (Keep in mind, the large photo is the one with all the metadata (caption, title, exif info, IPTC, etc.) I'm also not concerned about making this retroactive, just a solution that will apply to all uploads going forward.

Thanks!

migrated from stackoverflow.com Nov 12 '13 at 0:33

This question came from our site for professional and enthusiast programmers.

3

This can be done by using:

wp_get_attachment_metadata();

wp_update_attachment_metadata();

You'd get the meta data for it and change it around then save it. The $data array you get contains another array named sizes, this array contains all the different size images connected to the attachment.

You want this to update automatically when you upload images that are conveniently named. I don't quite see why it would be worth it but lets take a look.

This takes a little doing and this is probably not the optimal way to do it but it works and will give you an idea of how it can be done.

// hooking in to the add_attachment action just like you did
add_action('add_attachment', function ( $post_ID ) {
    // we need to work with the database
    global $wpdb;

    // get the attachment
    $post = get_post( $post_ID );

    // remove the _x2 suffix to help find the original
    $attachment_name = str_replace( '_x2', '', $post->post_title );

    // did this file have an _x2 suffix?
    $is_x2 = ( $attachment_name == $post->post_title ) ? FALSE : TRUE;

    // get the attachments extension
    $extension = pathinfo( $post->guid, PATHINFO_EXTENSION );

    // if there is a large file, it would be called:
    $large_file = $attachment_name . '_large.' . $extension;

    // time to see if we have a large file saved
    // wordpress stores the relative path from the uploads directory
    // we use a like query to find the file in any year/month subdir
    $result = $wpdb->get_row($wpdb->prepare(
        "SELECT * FROM $wpdb->postmeta
            WHERE meta_value LIKE %s",
        '%' . $wpdb->esc_like($large_file)
    ));

    // did we find a file?
    if( !empty( $result ) ) {
        // yep we found a file, get its meta
        $attachment_meta = wp_get_attachment_metadata( $result->post_id );

        // get meta data on the new file
        $meta = get_post_meta( $post->ID, '_wp_attached_file', TRUE );

        // manually read the size of the new image
        $upl = wp_upload_dir();
        $new_file = $upl['basedir'] . '/' . $meta;
        $sizes = getimagesize( $new_file );

        // what should the thumbnail be called?
        // remember we checked if the file had the _x2 suffix before?
        $thumb_name = ( $is_x2 ) ? 'x2' : 'thumb';

        // time to add the new size to the meta data of the large file
        $attachment_meta['sizes'][$thumb_name] = array(
            'file' => basename($post->guid),
            'width' => $sizes[0],
            'height' => $sizes[1],
            'mime-type' => $sizes['mime']
        );

        // save the new meta data to the large file
        wp_update_attachment_metadata( $result->post_id, $attachment_meta );

        // now we delete all references to the new file that was uploaded
        // by manually deleting it from the database the file will be kept on disk
        // this step is optional, Wordpress will behave a bit funny when uploading if used
        $wpdb->query($wpdb->prepare(
            "DELETE FROM $wpdb->posts
                WHERE $wpdb->posts.ID = %d", 
            $post->ID
        ));

        $wpdb->query($wpdb->prepare(
            "DELETE FROM $wpdb->postmeta 
                WHERE $wpdb->postmeta.post_id = %d", 
            $post->ID
        ));        
    }
});

The last 2 delete queries are optional, you said you didn't want new entries in the database for the new image and those will delete the new entries. Wordpress won't like that thoose references are removed though, it will act a bit funny when uploading but it won't break anything.

Now you can easily fetch your thumbnails like you would with any other. Assuming you have attached the large file as a featured image to a post:

global $post;

// the filename_large.jpg file
echo get_the_post_thumbnail($post->ID);

// the filename.jpg file
echo get_the_post_thumbnail($post->ID, 'thumb');

// the filename_x2.jpg file
echo get_the_post_thumbnail($post->ID, 'x2');

You can change what the thumbnails are called with the $thumb_name variable where we saved the new attachment meta data.

This will work regardless of wheter you use the optional delete queries or not, if you only wanted to do this for the convenience then I say don't use the queries. If you really don't want the thumbnails to show up as individual images then use them.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.