How to make programmatic image upload generate thumbnail and sizes?

I have written a function to add a remotely-hosted image to the Media Library. It does so.

However, it does not generate a thumbnail in the Media Library – and I believe standard practice should also be to make up a range of image dimensions, too (?), which it does not.

$source_url="https://res.cloudinary.com/braincloud/image/fetch/c_thumb,g_face,w_275,h_275/https://contexthq.com/wp-content/uploads/promo329755877.png"
$filename="jana-eisenstein";
$img_title="Jana Eisenstein avatar";

.

  // cf. https://wordpress.stackexchange.com/a/50666/39300
  function add_remote_image_to_library($source_url, $filename, $img_title) {

    include_once( ABSPATH . 'wp-admin/includes/image.php' );

    // ****** 1. Set folder and filename ****** //
    $uploaddir = wp_upload_dir();
    $uploadfile = $uploaddir['path'] . '/avatars/' . $filename.'.'.pathinfo($source_url)['extension'];

    // ****** 2. Get the image ****** //
    $contents= file_get_contents($source_url);

    // ****** 3. Upload the image ****** //
    $savefile = fopen($uploadfile, 'w');
    fwrite($savefile, $contents);
    fclose($savefile);

    // ****** 4. Insert to Media Library ****** //
    // Insert
    $wp_filetype = wp_check_filetype(basename($filename), null );
    $attachment = array(
        'post_mime_type' => $wp_filetype['type'],
        'post_title' => $img_title,
        'post_content' => '',
        'post_status' => 'inherit'
    );

    $attach_id = wp_insert_attachment( $attachment, $uploadfile);

    // Meta data
    $imagenew = get_post( $attach_id );
    $fullsizepath = get_attached_file( $imagenew->ID );
    $attach_data = wp_generate_attachment_metadata( $attach_id, $fullsizepath );

    wp_update_attachment_metadata( $attach_id, $attach_data );

  }

The file gets added to the correct directory. However, in the Media Library, there is only a blank image icon…

enter image description here

Something is going on (or not) in the section // Meta data, where I feel it needs to be generating a thumbnail.

Note, I am not attaching this image to a post.

1 Answer
1

In order for wp_generate_attachment_metadata() to work properly in that it creates a thumbnail and other intermediate/image sizes like medium and large, the image attachment/post data must have the proper MIME type (post_mime_type), and despite you did set it in your $attachment array (the post data), there’s a problem with this part in your code:

$wp_filetype = wp_check_filetype(basename($filename), null ); 

where $filename was defined as $filename="jana-eisenstein"; which is a file name without the extension (e.g. .png), and the value of that variable remained unchanged in your function, so with the above code, both ext and type in the $wp_filetype array are false.

Therefore, the 'post_mime_type' => $wp_filetype['type'] is equivalent to 'post_mime_type' => false, causing the image attachment to having invalid MIME type.

And to fix it, you can either pass the full file path to wp_check_filetype(), or use basename( $uploadfile ) and not basename( $filename ):

$wp_filetype = wp_check_filetype( $uploadfile, null ); // pass full path
$wp_filetype = wp_check_filetype( basename( $uploadfile ), null ); // OR this works, too

Alternate Option

This is based on this example which uses media_handle_sideload() and automatically calls wp_update_attachment_metadata(), so you would not need to manually call it. 🙂

function add_remote_image_to_library( $source_url, $filename, $img_title ) {
    require_once ABSPATH . 'wp-admin/includes/image.php';
    require_once ABSPATH . 'wp-admin/includes/media.php'; // load media_handle_sideload()
    require_once ABSPATH . 'wp-admin/includes/file.php';  // load download_url()

    // Download the file to a temporary (system) file.
    $tmp = download_url( $source_url );

    // Build an array like in the $_FILES superglobal.
    $wp_filetype = wp_check_filetype( basename( $source_url ) );
    $file_array = array(
        'name'     => $filename . '.' . $wp_filetype['ext'],
        'tmp_name' => $tmp,
    );

    // Must manually delete the file in case of download errors.
    if ( is_wp_error( $tmp ) ) {
        @unlink( $file_array[ 'tmp_name' ] );
        return $tmp;
    }

    // Now create the attachment plus thumbnails and other sizes.
    $post_id = 0; // the parent post ID, if applicable
    $id = media_handle_sideload( $file_array, $post_id, null, array(
        'post_title' => $img_title,
    ) );

    // You should delete the temporary file if the above resulted in a WP_Error.
    if ( is_wp_error( $id ) ) {
        @unlink( $file_array['tmp_name'] );
        return $id;
    }

    return $id; // return the attachment ID or whatever that you want to return..
}

Leave a Comment