Uploading Images to Media Library via wp_handle_sideload() fails

My basic scenario is the following:

I have a directory on my server that gets filled with images via ftp every once in a while. I would want to move these images to the wp upload directory and then add them to the media library with wp_insert_attachment(). I thought wp_handle_sideload() to be the correct function for this but if fed with an absolute path to one of the images it returns an error.

Read More

Heres my code so far:

function oo_attach_images($images, $id){   

 //$images is an array of anbsolute image paths, $id is the id of a post I want the images to be attached to.

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

    foreach($images as $image){

        $override = array('test_form' => FALSE);

        $file = wp_handle_sideload($image, $override);

        print_r($file); //returns: Array ( [error] => )

        $attachment = array(
            'post_mime_type' => $file['type'],
            'post_title' => basename($image),
            'post_content' => ' ',
            'post_status' => 'inherit'
        );

        $attach_id = wp_insert_attachment( $attachment, $file['file'], $id );

        $attach_data = wp_generate_attachment_metadata( $attach_id, $file['file'] );
        wp_update_attachment_metadata( $attach_id,  $attach_data );


    }
}

I looked into similar questions, but none of the solutions outlined there seemed to have anything to do with the sideload itself failing.
Frankly, I believe that I do not pass the right kind of file path to wp_handle_sideload(), but since its undocumented in codex I have no idea what kind of input it might expect. Does anyone know what I need to change to make this work?

Related posts

Leave a Reply

4 comments

  1. Your files array needs to mimic the $_FILES global so you need to make a dummy page with some file inputs that prints or dumps the contents of $_FILES to see how it is structured. Make a variable that looks like that with your data and pass that wp_handle_sideload().

    EDIT:

    This answer was correct at the time of writing and is if you wish to use wp_handle_sideload(). media_handle_sideload() allow you to attach the media to a post at the same time.

    See @anatol’s own answer for a full solution.

  2. This is the surprisingly simple code that ultimately worked out to do what it’s supposed to:

    function oo_attach_images($images, $id){ //$images is an array of image urls, $id is the ID of the post I want the images to be attached to
    
        require_once(ABSPATH . '/wp-admin/includes/file.php');
        require_once(ABSPATH . '/wp-admin/includes/media.php');
        require_once(ABSPATH . '/wp-admin/includes/image.php');
    
        foreach($images as $image){
    
            $array = array( //array to mimic $_FILES
                'name' => basename($image), //isolates and outputs the file name from its absolute path
                'type' => wp_check_filetype($image), // get mime type of image file
                'tmp_name' => $image, //this field passes the actual path to the image
                'error' => 0, //normally, this is used to store an error, should the upload fail. but since this isnt actually an instance of $_FILES we can default it to zero here
                'size' => filesize($image) //returns image filesize in bytes
            );
    
            media_handle_sideload($array, $id); //the actual image processing, that is, move to upload directory, generate thumbnails and image sizes and writing into the database happens here
        }
    }
    
  3. I used Anatol’s code but ran into trouble when pulling images using HTTP. To fix this, use download_url first to get a local copy of the image.

    It’s also useful to know that media_handle_sideload returns the attachment_id number which you can use to display the image after you’ve uploaded it.

    foreach($images as $image){
      $tmp_name = download_url( $image ); // get the image and save it locally temporarily
      $array = array(
        'name' => basename( $image ),
        'type' => 'image/jpeg',
        'tmp_name' => $tmp_name,
        'error' => 0,
        'size' => filesize( $tmp_name )
      );
      $_image_id = media_handle_sideload($array, $id);
      $_src = wp_get_attachment_url( $_image_id );
      echo '<img src="' . $_src . '" />';
    }
    
  4. try

        { // only need these if performing outside of admin environment
        require_once(ABSPATH . 'wp-admin/includes/media.php');
        require_once(ABSPATH . 'wp-admin/includes/file.php');
        require_once(ABSPATH . 'wp-admin/includes/image.php');
    
        // example image
        $image = $review['image'];
        // magic sideload image returns an HTML image, not an ID
        $media = media_sideload_image($image, $new_post_id);
    
        // therefore we must find it so we can set it as featured ID
        if(!empty($media) && !is_wp_error($media)){
            $args = array(
                'post_type' => 'attachment',
                'posts_per_page' => -1,
                'post_status' => 'any',
                'post_parent' => $new_post_id
            );
    
            // reference new image to set as featured
            $attachments = get_posts($args);
    
            if(isset($attachments) && is_array($attachments)){
                foreach($attachments as $attachment){
                    // grab source of full size images (so no 300x150 nonsense in path)
                    $image = wp_get_attachment_image_src($attachment->ID, 'full');
                    // determine if in the $media image we created, the string of the URL exists
                    if(strpos($media, $image[0]) !== false){
                        // if so, we found our image. set it as thumbnail
                        set_post_thumbnail($new_post_id, $attachment->ID);
                        // only want one image
                        break;
                    }
                }
            }
        }
          } catch (Exception $e) {
              echo 'Caught exception: ',  $e->getMessage(), "n";
          }