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);

    // ****** 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..
  • Sally, this looks veryhelpful. However, I'm setting an extension on line 8, pathinfo($source_url)['extension']. wp_check_filetype() confirms I have ext string(3) "png" and type string(9) "image/png". Commented May 19, 2020 at 6:51
  • I'm actually saying you used basename($filename) which should be basename($uploadfile) or just pass $uploadfile alone as in the answer.
    – Sally CJ
    Commented May 19, 2020 at 7:40
  • I see! Okay, changing to basename( $uploadfile ) now results both in the Media Library thumbnail appearing and in two images being present - jana-eisenstein-170x150.png and jana-eisenstein.png. Double success, I think. Sally, this is a great answer and edit, possibly be the canonical answer on these questions - thanks. I will aim to try media_handle_sideload(), too. I don't see an 'alt' field amongst post_mime_type, post_title, post_content and post_status. Commented May 19, 2020 at 12:33
  • The alt text is saved as a private custom field named _wp_attachment_image_alt, so you can use update_post_meta() to update the alt text.
    – Sally CJ
    Commented May 20, 2020 at 2:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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