Skip to content

Instantly share code, notes, and snippets.

@RadGH
Last active March 27, 2024 23:30
Show Gist options
  • Star 31 You must be signed in to star a gist
  • Fork 12 You must be signed in to fork a gist
  • Save RadGH/966f8c756c5e142a5f489e86e751eacb to your computer and use it in GitHub Desktop.
Save RadGH/966f8c756c5e142a5f489e86e751eacb to your computer and use it in GitHub Desktop.
Upload a file from a URL to the WordPress media gallery. Supports images, PDFs, and other file types.
<?php
/**
* This function uploads a file from a URL to the media library, designed to be placed in your own theme or plugin.
* Metadata will be generated and images will generate thumbnails automatically.
*
* HOW TO USE:
* 1. Add the function below to your theme or plugin
* 2. Call the function and provide the URL to an image or other file.
* 3. If successful, the attachment ID will be returned.
*
* BASIC USAGE:
* $attachment_id = rs_upload_from_url( "https://www.gstatic.com/webp/gallery/1.jpg" );
* if ( $attachment_id ) echo wp_get_attachment_image( $attachment_id, 'large' );
*
* DOWNLOAD AS A PLUGIN (optional):
* Below is a link to a separate plugin you can upload to your site to help get started.
* It is a fully-functional example and demonstrates upload both JPG and WEBP image by using a "secret" url.
* It also provides an easy way to delete the test images that were created.
* @see https://gist.github.com/RadGH/be30af96617b13e7848a4626ef179bbd
*
* To upload from a *LOCAL FILE PATH* instead of a URL:
* @see: https://gist.github.com/RadGH/3b544c827193927d1772
*/
/**
* Upload a file to the media library using a URL.
*
* @version 1.3
* @author Radley Sustaire
* @see https://gist.github.com/RadGH/966f8c756c5e142a5f489e86e751eacb
*
* @param string $url URL to be uploaded
* @param null|string $title Override the default post_title
* @param null|string $content Override the default post_content (Added in 1.3)
* @param null|string $alt Override the default alt text (Added in 1.3)
*
* @return int|false
*/
function rs_upload_from_url( $url, $title = null, $content = null, $alt = null ) {
require_once( ABSPATH . "/wp-load.php");
require_once( ABSPATH . "/wp-admin/includes/image.php");
require_once( ABSPATH . "/wp-admin/includes/file.php");
require_once( ABSPATH . "/wp-admin/includes/media.php");
// Download url to a temp file
$tmp = download_url( $url );
if ( is_wp_error( $tmp ) ) return false;
// Get the filename and extension ("photo.png" => "photo", "png")
$filename = pathinfo($url, PATHINFO_FILENAME);
$extension = pathinfo($url, PATHINFO_EXTENSION);
// An extension is required or else WordPress will reject the upload
if ( ! $extension ) {
// Look up mime type, example: "/photo.png" -> "image/png"
$mime = mime_content_type( $tmp );
$mime = is_string($mime) ? sanitize_mime_type( $mime ) : false;
// Only allow certain mime types because mime types do not always end in a valid extension (see the .doc example below)
$mime_extensions = array(
// mime_type => extension (no period)
'text/plain' => 'txt',
'text/csv' => 'csv',
'application/msword' => 'doc',
'image/jpg' => 'jpg',
'image/jpeg' => 'jpeg',
'image/gif' => 'gif',
'image/png' => 'png',
'video/mp4' => 'mp4',
);
if ( isset( $mime_extensions[$mime] ) ) {
// Use the mapped extension
$extension = $mime_extensions[$mime];
}else{
// Could not identify extension. Clear temp file and abort.
wp_delete_file($tmp);
return false;
}
}
// Upload by "sideloading": "the same way as an uploaded file is handled by media_handle_upload"
$args = array(
'name' => "$filename.$extension",
'tmp_name' => $tmp,
);
// Post data to override the post title, content, and alt text
$post_data = array();
if ( $title ) $post_data['post_title'] = $title;
if ( $content ) $post_data['post_content'] = $content;
// Do the upload
$attachment_id = media_handle_sideload( $args, 0, null, $post_data );
// Clear temp file
wp_delete_file($tmp);
// Error uploading
if ( is_wp_error($attachment_id) ) return false;
// Save alt text as post meta if provided
if ( $alt ) {
update_post_meta( $attachment_id, '_wp_attachment_image_alt', $alt );
}
// Success, return attachment ID
return (int) $attachment_id;
}
@RadGH
Copy link
Author

RadGH commented Sep 15, 2022

I've updated this function to use media_handle_sideload and other things. It's almost entirely rewritten and much less complicated.

For uploading a local file path instead, consider my other function:

rs_upload_from_path( $path )
https://gist.github.com/RadGH/3b544c827193927d1772

@greenlevel
Copy link

Hi, I am testing this function and put rs_upload_from_url funtion in functions.php

and for now call directly in a page template like below
$url = "https://dummyimage.com/600x400/000/fff";
$result = rs_upload_from_url( $url );
But it's not uploading the dummy image. It calls the function, but it goes through ( is_wp_error($attachment_id) ) { }

Am I using it wrong? Thanks in advance

@RadGH
Copy link
Author

RadGH commented Sep 18, 2022

@greenlevel Thanks for catching that! It was because the URL did not have an extension. I updated the function to get the extension by mime type as a fallback. Now it should work with your URL and correctly identifies the image as a .png

@mendelsphotography
Copy link

@RadGH Thanks. After a lot of searching, I found a plugin that fits what I wanted.
https://wordpress.org/plugins/exmage-wp-image-links/ it allows you to upload images to WordPress media as links plus paste multiple links at once each on its own line. That's what I was looking for. Thanks so much again for your quick and prompt response.

@greenlevel
Copy link

@greenlevel Thanks for catching that! It was because the URL did not have an extension. I updated the function to get the extension by mime type as a fallback. Now it should work with your URL and correctly identifies the image as a .png

Haha, no problem :) Thanks for making this function and making the quick fix!

@kathrynherod
Copy link

Thanks for this! Just a minor note - I don't think the file cleanup was actually happening. I have this inside of a recursive API and kept running into critical errors. I removed the @ from line 78 @unlink($tmp); and changed it to unlink($tmp); and it stopped timing out.

@julian-stark
Copy link

Great, thank you

@bhavinp311
Copy link

Thank you so much @RadGH !
It's really really helpful!

@hassan-hossini
Copy link

Still working 2023! Thank you!

@RadGH
Copy link
Author

RadGH commented Jun 15, 2023

@aspnarola It's hard to say for sure but looking at that URL it doesn't have a filename and extension. The filename would probably be considered "image" because it ends in "/_next/image?url=".

You'll want to do some debugging and see what is happening with the variables $tmp, $filename, and $extension.

If the problem is with $tmp and it bails at line 31, you'll want to look at the documentation for download_url() here:
https://developer.wordpress.org/reference/functions/download_url/

If the problem is with the filename/extension and it bails at line 62, you'll want to modify the function to work for that URL. In your case there is a $_GET parameter in your link that is called "url" which points to a separate link. In that case you can parse the URL to get the link to sanity.io and then use the filename "7ef56859f0951a3d7382a37487aa80c8fba2ef0e-694x340.jpg" instead.

@LeninZapata
Copy link

It works!, but I would like to be able to convert a JPG image to WEBP with this same process, is it possible?

@RadGH
Copy link
Author

RadGH commented Aug 7, 2023

@LeninZapata You could look at using imagewebp() after you download the file. Some examples can be seen on Stack Overflow. When dealing with wp_handle_sideload(), you might need to fake the path in $_FILES['tmp_name'] to point to the converted file.

You might also want to use wp_generate_attachment_metadata() afterward so that the thumbnails are generated, assuming that works with webp images.

@LeninZapata
Copy link

@LeninZapata You could look at using imagewebp() after you download the file. Some examples can be seen on Stack Overflow. When dealing with wp_handle_sideload(), you might need to fake the path in $_FILES['tmp_name'] to point to the converted file.

You might also want to use wp_generate_attachment_metadata() afterward so that the thumbnails are generated, assuming that works with webp images.

Thank you so much!

@GalinaBublik
Copy link

ThankS!!!

@tuanbeplus
Copy link

Nice, thanks you!

@vdjaguar
Copy link

vdjaguar commented Dec 9, 2023

Yeh! Still working 09.12.2023 ;) Thanks a lot!

@gilangramadhan
Copy link

Hello, how can I use this snippet? I mean I have put the code in the functions.php and tried to upload the media by going to Media > Library page, where's the button to upload from a URL? Am I missing something... Sorry I'm no code developer. Thanks!

@RadGH
Copy link
Author

RadGH commented Dec 12, 2023

@gilangramadhan There is no interface. You'll need to do some coding to make use of this. I'm sure there is a plugin out there that will let you upload files by url using the media uploader. What would work best for what you are trying to do?

@philbirnie
Copy link

Thanks for this! This is great, @RadGH! -- one minor suggestion: switch the @unlink's with wp_delete_file; this will allow you to remove silence operators from your code (and, more importantly, allow the path to be filterable via the wp_delete_file filter)

@RadGH
Copy link
Author

RadGH commented Jan 29, 2024

@philbirnie Great suggestion, thanks! I updated the script to use wp_delete_file instead of @unlink.

@mdbadsha
Copy link

mdbadsha commented Feb 2, 2024

@RadGH
Copy link
Author

RadGH commented Feb 2, 2024

@mdbadsha Yep, I just tested and webp images work just fine.


To anyone else interested, I created a plugin to test this function which is available at another gist URL:

https://gist.github.com/RadGH/be30af96617b13e7848a4626ef179bbd

Instructions and a screenshot of the results are displayed on the first comment:

https://gist.github.com/RadGH/be30af96617b13e7848a4626ef179bbd#gistcomment-4870147

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment