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;
}
@heyjoecampbell
Copy link

Hi @RadGH - how does snippet work? Where is the field to add the url for the image?

@RadGH
Copy link
Author

RadGH commented Jul 29, 2022

@heyjoecampbell The URL goes in the first argument such as:

ksa_upload_from_url( "https://dummyimage.com/600x400/000/fff" );

An example I use is integrating with Gravity Forms. The image field in that plugin is stored as a url and is not uploaded to the media library. So I hook into a filter "gform_after_submission", grab the image url, upload to the media library, and do something with the attachment ID.

I often attach it to a post as the featured image using something like:

$image_url = gform_get_meta( $entry_id, $field_id );
$result = ksa_upload_from_url( $image_url );
if ( $result['attachment_id'] > 0 ) {
    set_post_thumbnail( $post_id, $result['attachment_id'] );
}

@heyjoecampbell
Copy link

Thanks @RadGH for the speedy response.

Would it be possible to also add the Alt Text during the upload process?

If so, how?

I would love to see "Upload from URL" and "Add Alt Text" integrated into the core Media Library upload process:
https://twitter.com/heyjoecampbell/status/1553103295455059968

@RadGH
Copy link
Author

RadGH commented Jul 29, 2022

@heyjoecampbell The alt text is stored as post meta with the key "_wp_attachment_image_alt". So you just need to add one more line like this:

$alt = "Dog playing fetch";
update_post_meta( $attachment_id, '_wp_attachment_image_alt', $alt );

The attachment ID is referring to this from the last comment: $result['attachment_id']

Hope that helps!

@heyjoecampbell
Copy link

Thank you @RadGH

I am not a proficient developer. I simply utilize and do basic modifications to code snippets I am able to find online.

I've been looking for a snippet to add the Alt Text field in the media upload, but have not been able to find such a snippet.

@mendelsphotography
Copy link

Hi there How do I use this PHP file? where does it go? I am looking to Import bulk URLs from a gallery service. Then take those images and use a plugin to make a gallery from them.

@RadGH
Copy link
Author

RadGH commented Sep 15, 2022

@mendelsphotography It can basically go anywhere, most people suggest functions.php. The rest is explained in the comments. The rest of your project you'll have to come up with on your own I'm afraid

@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