33

I am trying to programmatically add multiple images to media library, I uploaded the images to wp-content/uploads, now I try to use wp_insert_attachement.

Here's the code, however it's not working as expected, I think metadata is not properly generated, I can see the files in media library, but without a thumbnail, also if I edit the image I get an error saying to re-upload the image.

$filename_array = array(
   'article1.jpg',
   'article2.jpg',
);

// The ID of the post this attachment is for.
$parent_post_id = 0;

// Get the path to the upload directory.
$wp_upload_dir = wp_upload_dir();

foreach ($filename_array as $filename) {

    // Check the type of file. We'll use this as the 'post_mime_type'.
    $filetype = wp_check_filetype( basename( $filename ), null );

    // Prepare an array of post data for the attachment.
    $attachment = array(
        'guid'           => $wp_upload_dir['url'] . '/' . basename( $filename ), 
        'post_mime_type' => $filetype['type'],
        'post_title'     => preg_replace( '/\.[^.]+$/', '', basename( $filename ) ),
        'post_content'   => '',
        'post_status'    => 'inherit'
    );

    // Insert the attachment.
    $attach_id = wp_insert_attachment( $attachment, $filename, $parent_post_id );

    // Make sure that this file is included, as   wp_generate_attachment_metadata() depends on it.
    require_once( ABSPATH . 'wp-admin/includes/image.php' );

    // Generate the metadata for the attachment, and update the database record.
    $attach_data = wp_generate_attachment_metadata( $attach_id, $filename );
    wp_update_attachment_metadata( $attach_id, $attach_data );

}

4 Answers 4

39
$image_url = 'adress img';

$upload_dir = wp_upload_dir();

$image_data = file_get_contents( $image_url );

$filename = basename( $image_url );

if ( wp_mkdir_p( $upload_dir['path'] ) ) {
  $file = $upload_dir['path'] . '/' . $filename;
}
else {
  $file = $upload_dir['basedir'] . '/' . $filename;
}

file_put_contents( $file, $image_data );

$wp_filetype = wp_check_filetype( $filename, null );

$attachment = array(
  'post_mime_type' => $wp_filetype['type'],
  'post_title' => sanitize_file_name( $filename ),
  'post_content' => '',
  'post_status' => 'inherit'
);

$attach_id = wp_insert_attachment( $attachment, $file );
require_once( ABSPATH . 'wp-admin/includes/image.php' );
$attach_data = wp_generate_attachment_metadata( $attach_id, $file );
wp_update_attachment_metadata( $attach_id, $attach_data );
8
  • 1
    where is $attach_id coming from? Commented Sep 27, 2017 at 14:23
  • it was missing... i added it
    – Omtara
    Commented Oct 30, 2017 at 16:30
  • 1
    File downloaded but no thumbnail available, attachment url also giving 404 Commented May 22, 2018 at 19:51
  • @UmairHamid Same here. This is because the second argument of wp_insert_attachment should be the file path (so $file in this example), not the file name. I edited the answer, waiting for approval.
    – philippe_b
    Commented Oct 22, 2018 at 21:24
  • and how can I get the new url ?
    – zEn feeLo
    Commented May 3, 2019 at 18:19
15

If you use WordPress' sideload feature, you can do this more easily (and have WordPress handle all of the sanitization for you).

<?php
// example:
//   $file = 'http://www.example.com/image.png';
//   $description = 'some description';

function my_upload_image( $file, $description ) {
   $file_array  = [ 'name' => wp_basename( $file ), 'tmp_name' => download_url( $file ) ];

   // If error storing temporarily, return the error.
   if ( is_wp_error( $file_array['tmp_name'] ) ) {
    return $file_array['tmp_name'];
   }

   // Do the validation and storage stuff.
   $id = media_handle_sideload( $file_array, 0, $description );

   // If error storing permanently, unlink.
   if ( is_wp_error( $id ) ) {
    @unlink( $file_array['tmp_name'] );
       return $id;
   }

   return true;
}
2
  • 4
    Keep in mind that this only works from within /wp-admin/. Outside it you need to make sure to require_once these three files: ABSPATH . 'wp-admin/includes/file.php', ABSPATH . 'wp-admin/includes/media.php', ABSPATH . 'wp-admin/includes/image.php'
    – KittMedia
    Commented Sep 7, 2021 at 9:58
  • 1
    This also works for images already stored on the server, you simply use the image path rather than download_url( $file ). But if you do this, please note that when using media_handle_sideload, it will automatically delete the image when processed. If you do not want this to happen, then simply copy the image to the tmp directory via $tmp_path = get_temp_dir() . basename( $file ); copy( $file, $tmp_path );, then you can use 'tmp_name' => $tmp_path instead.
    – Smithee
    Commented Jan 19, 2023 at 11:19
6

I had issues with @TrubinE's solution where image files were not getting loaded.

Here is a complete example that worked for me: https://gist.github.com/m1r0/f22d5237ee93bcccb0d9

This is a similar idea but use the WP HTTP library to fetch the content versus file_get_contents(). Here is the content of the github gist solution from m1r0:

    if ( ! class_exists( 'WP_Http' ) ) {
        include_once( ABSPATH . WPINC . '/class-http.php' );
    }

    $http = new WP_Http();
    $response = $http->request( $meta['image_url'] );
    if ( $response['response']['code'] !== 200 ) {
        return false;
    }

    $upload = wp_upload_bits( basename( $meta['image_url'] ), null, $response['body'] );
    if ( !empty( $upload['error'] ) ) {
        return false;
    }
    $file_path = $upload['file'];
    $file_name = basename( $file_path );
    $file_type = wp_check_filetype( $file_name, null );
    $attachment_title = sanitize_file_name( pathinfo( $file_name, PATHINFO_FILENAME ) );
    $wp_upload_dir = wp_upload_dir();
    
    $post_info = array(
        'guid'           => $wp_upload_dir['url'] . '/' . $file_name,
        'post_mime_type' => $file_type['type'],
        'post_title'     => $attachment_title,
        'post_content'   => '',
        'post_status'    => 'inherit',
    );
    
    $attach_id = wp_insert_attachment( $post_info, $file_path, $parent_post_id );
    require_once( ABSPATH . 'wp-admin/includes/image.php' );
    $attach_data = wp_generate_attachment_metadata( $attach_id, $file_path );
    wp_update_attachment_metadata( $attach_id,  $attach_data );
    return $attach_id; code here
0
0
`<?php  
// simplest method upload image  
$url_image = "http://example.com/any_image.jpg" ;  
$new_image_id = upload_image_by_url ( $url_image );  

function upload_image_by_url ($url) {
    $title = basename($url) ; 
    $image_for_post_id = 0 ; // 0 means the image is not associated with the post 
    $imgid = media_sideload_image( $url, $image_for_post_id, $title, 'id' );  
    if ( is_wp_error($imgid) ) {  
        echo "<br>Error upload_image_by_url($url): ";
        echo $imgid->get_error_message();
        return false;  
    }  
    else {  
        echo "<br>upload_image_by_url($url) = $imgid";
        return $imgid;
    }
}?>`
2
  • As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.
    – Community Bot
    Commented Feb 13 at 22:34
  • That looks like it's the same basic approach as Paul's answers. Do the comments there apply here too, e.g. about deleting failed uploads?
    – Rup
    Commented Feb 16 at 0:21

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.