I have been working on a WordPress site that parses remote news API’s and requires not only parsing the news format JSON but getting any associated media and downloading them.
Herein lies the problem: the download_url function that WordPress provides does not support passing in headers. If you are working with a remote API that requires passing an authorization header, then this function won’t work.
Unbbeknownst to some, the underlying download_url
function uses WordPress request methods to make the request for the file. Taking the original function from the codebase and making some simple tweaks, we end up with something like this.
function download_url_with_headers($url, $headers = []) { // WARNING: The file is not automatically deleted, the script must unlink() the file. if ( ! $url ) { return new WP_Error( 'http_no_url', __( 'Invalid URL Provided.' ) ); } $url_filename = basename( parse_url( $url, PHP_URL_PATH ) ); $tmpfname = wp_tempnam( $url_filename ); if ( ! $tmpfname ) { return new WP_Error( 'http_no_file', __( 'Could not create Temporary file.' ) ); } $response = wp_safe_remote_get( $url, array( 'timeout' => 600, 'stream' => true, 'filename' => $tmpfname, 'headers' => $headers ) ); if ( is_wp_error( $response ) ) { unlink( $tmpfname ); return $response; } $response_code = wp_remote_retrieve_response_code( $response ); if ( 200 != $response_code ) { $data = array( 'code' => $response_code, ); $tmpf = fopen( $tmpfname, 'rb' ); if ( $tmpf ) { $response_size = apply_filters( 'download_url_error_max_body_size', KB_IN_BYTES ); $data['body'] = fread( $tmpf, $response_size ); fclose( $tmpf ); } unlink( $tmpfname ); return new WP_Error( 'http_404', trim( wp_remote_retrieve_response_message( $response ) ), $data ); } return $tmpfname; }
You can then call it like this:
$temp_file = download_url_with_headers($image_url, $headers); $filepath = ABSPATH . 'wp-content/uploads/' . $image_filename; copy($temp_file, $filepath); @unlink($temp_file);
This is a little more simplified than the original method, as WordPress does some other stuff involving md5 hashes and whatnot you might want to add in, but I had no use for given I am working with private API’s and files.