Skip to content

Instantly share code, notes, and snippets.

@RadGH
Last active November 2, 2023 17:52
Show Gist options
  • Star 11 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save RadGH/3b544c827193927d1772 to your computer and use it in GitHub Desktop.
Save RadGH/3b544c827193927d1772 to your computer and use it in GitHub Desktop.
Upload a local file as a WordPress attachment, placing it in the Media library. Supports images, PDFs, and other file types.
<?php
/**
* This function uploads from a local file path.
* To upload from a URL instead
* @see: https://gist.github.com/RadGH/966f8c756c5e142a5f489e86e751eacb
*
* Example usage: Upload photo from file, display the attachment as as html <img>
* $attachment_id = rs_upload_from_path( "/images/photo.png" );
* echo wp_get_attachment_image( $attachment_id, 'large' );
*
*/
/**
* Takes a local file path and uploads it to the WordPress media gallery.
*
* @version 1.2
*
* @param string $path File path to be uploaded
* @param null|string $title If set, used as the post_title
*
* @return int|false
*/
function rs_upload_from_path( $path, $title = null ) {
if ( !file_exists($path) ) return false;
// Include file and attachment utilities that are used below
require_once( ABSPATH . 'wp-admin/includes/file.php' );
require_once( ABSPATH . 'wp-admin/includes/image.php' );
// mynotes.txt -> mynotes, txt
$filename = basename($path);
$extension = strtolower(pathinfo($path, PATHINFO_EXTENSION));
// Pretend to upload a file using the traditional $_FILES global.
// We use a temporary file because uploading this way deletes the existing file in order to put it in the uploads folder.
// We do not want the original to be deleted, so the temporary file we use gets deleted instead
$tmp = tmpfile();
$tmp_path = stream_get_meta_data($tmp)['uri'];
$tmp_filename = basename($tmp_path);
fwrite($tmp, file_get_contents( $path ));
fseek($tmp, 0); // If we don't do this, WordPress thinks the file is empty
// Get mime type from file
$mime = mime_content_type( $tmp_path );
$mime = is_string($mime) ? sanitize_mime_type( $mime ) : false;
// Mime type must be present or else it would fail the "upload"
if ( !$mime ) {
fclose($tmp);
@unlink($tmp_path);
return false;
}
// Array structure designed to mimic $_FILES, like if you submitted a form with an <input type="file">
$_FILES[$tmp_filename] = array(
'name' => $filename,
'type' => $mime,
'tmp_name' => $tmp_path,
'error' => UPLOAD_ERR_OK,
'size' => filesize($path),
);
// Do the upload, this moves the file to the uploads folder
$upload = wp_handle_upload( $_FILES[$tmp_filename], array( 'test_form' => false, 'action' => 'local' ) );
// Clean up after upload
fclose($tmp);
@unlink($tmp_path);
unset($_FILES[basename($tmp_path)]);
// Abort if error occurred
if ( !empty($upload['error']) ) return false;
// Generate a title if needed
if ( empty($title) ) $title = pathinfo($path, PATHINFO_FILENAME);
// Create the "attachment" post, as seen on the media page
$args = array(
'post_title' => $title,
'post_content' => '',
'post_status' => 'publish',
'post_mime_type' => $upload['type'],
);
$attachment_id = wp_insert_attachment( $args, $upload['file'] );
// Abort if we could not insert the attachment
// Also when aborted, delete the unattached file since it would not show up in the media gallery
if ( is_wp_error( $attachment_id ) ) {
@unlink($upload['file']);
return false;
}
// Upload was successful, generate and save the image metadata
$data = wp_generate_attachment_metadata( $attachment_id, $upload['file'] );
wp_update_attachment_metadata( $attachment_id, $data );
// All successful, return the attachment ID
return $attachment_id;
}
@CookiesForDevo
Copy link

Adding wp_update_attachment_metadata( $result['attachment_id'], wp_generate_attachment_metadata( $result['attachment_id'], $result['file'] ) ); after line 60 will give WordPress all the little bits of image data it needs.

@RadGH
Copy link
Author

RadGH commented Feb 2, 2016

Thanks for the tip, added that in. I put it behind the if statement so it doesn't run if the upload fails for some reason.

@rainb3rry
Copy link

Thank for the share

@patrickgilmour
Copy link

Works perfectly to import PDFs into Media Library in WP 5.8.2 - thanks for sharing.

@RadGH
Copy link
Author

RadGH commented Sep 15, 2022

I've updated this function for consistency. Also improved mime type detection.

For uploading a URL instead, consider my other function:

rs_upload_from_url( $url )
https://gist.github.com/RadGH/966f8c756c5e142a5f489e86e751eacb

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