How to upload images to WordPress programmatically

By , last updated October 18, 2019

I was programming a clothes search engine and ran into many difficulties. In this article I’ll explain what I have done and what problems I had to solve step by step.

Step by step guide

I was making a PHP script that would run inside WordPress theme on an hourly basis (like a crawl). The script would be able to take the URL of the image from the Internet and insert it into “posts” table as an attachment automatically. So I needed to code the functionality to upload images programmatically into WordPress from URLs.

There are 3 simple steps:

  1. Download URL into a file. Do this by using WordPress builtin function download_url() and pass a URL to your image.
  2. Load media into posts table. This is done with the help of media_handle_sideload() function that takes an array of files and a post_id to attach the media.

    Here is how I used media_handle_sideload function:

    $file = array();
    $file['name'] = $url;
    $file['tmp_name'] = download_url($url);
    
    $attachmentId = media_handle_sideload($file, $post_id);
    

    It is also necessary to implement exception handling.

  3. Get an image URL from attachment id. This is done by using wp_get_attachment_url() function.

Fatal error: Call to undefined function media_handle_sideload()

The reason for the error was that although my script file was placed inside the theme, the file itself was not “fully” part of my WordPress admin installation. I needed to include admin.php at the top of the script.

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

Sorry, this file type is not permitted for security reasons

I was trying to upload a PNG image from URL when media_handle_sideload function throws an exception.

$attachmentId = media_handle_sideload($file, $post_id);
			
if ( is_wp_error($attachmentId) ) {
	@unlink($file['tmp_name']);
	echo "Could not do media_handle_sideload";
} 

In order to see the exception, we need to print it out not with echo, but using var_dump:

		
if ( is_wp_error($attachmentId) ) {
	@unlink($file['tmp_name']);
	var_dump( $attachmentId->get_error_messages( ) );
} 

Now, I was able to see the exception:

array(1) { [0]=> string(60) “Sorry, this file type is not permitted for security reasons.” }

This was a misleading exception as I was uploading a PNG file. PNG files are not considered dangerous and are permitted by default. There was some other strange thing giving the exception. To go forward and find out what it was, I temporarily fixed the issue by adding the following line at the top of my script:

define('ALLOW_UNFILTERED_UPLOADS', true);

Note, that is NOT a fix for the error itself, but just a bypass in order to get to the root of the problem.

Now, I was able to see the real issue:

Undefined index: type in …/wp-admin/includes/file.php

Undefined index: type in file.php

Undefined index errors appear when the array you are sending to the function does not exist anymore. Look at your code and analyze why did it disappear? Was it there in the first place?

In my case it was a sloppy typo error. I had some test code that I forgot to delete (note lines 1-3 and 5-7):

$file = array();
$file['name'] = $url;
$file['tmp_name'] = download_url($url);

$file = array();
$file['name'] = "test";
$file['tmp_name'] = download_url($url);

if (is_wp_error($file['tmp_name'])) {
	@unlink($file['tmp_name']);
}

Final solution

The final function for uploading images programmatically looks like this:

function upload_image($url, $post_id) {
	$image = "";
	if($url != "") {
	
		$file = array();
		$file['name'] = $url;
		$file['tmp_name'] = download_url($url);

		if (is_wp_error($file['tmp_name'])) {
			@unlink($file['tmp_name']);
			var_dump( $file['tmp_name']->get_error_messages( ) );
		} else {
			$attachmentId = media_handle_sideload($file, $post_id);
			
			if ( is_wp_error($attachmentId) ) {
				@unlink($file['tmp_name']);
				var_dump( $attachmentId->get_error_messages( ) );
			} else {				
				$image = wp_get_attachment_url( $attachmentId );
			}
		}
	}
	return $image;
}

Senior Software Engineer developing all kinds of stuff.