Skip to content

Instantly share code, notes, and snippets.

@gmazzap
Created April 17, 2014 03:37
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save gmazzap/10951232 to your computer and use it in GitHub Desktop.
Save gmazzap/10951232 to your computer and use it in GitHub Desktop.
Attach My Upload is a WordPress plugin that allow to create an attachment post from a file already uploaded to uploads folder. Was wrote to answer a WPSE question here: http://wordpress.stackexchange.com/questions/141509/
<?php
/**
* Plugin Name: Attach My Upload
* Description: Allow to create an attachment post from a file already uploaded to uploads folder.
* Plugin URI: http://wordpress.stackexchange.com/questions/141509/
* Author: G. M.
* Author URI: http://wordpress.stackexchange.com/users/35541/g-m
*
*/
/*
Copyright (C) 2014 Giuseppe Mazzapica
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
namespace GM;
/**
* Only in admin and only if not ajax
*/
if ( ! is_admin() || ( defined( 'DOING_AJAX' ) && DOING_AJAX ) ) {
return;
}
/**
* Require the class file, instantiate it and attach calss methods to proper hooks
*/
function initAMU() {
require_once plugin_dir_path( __FILE__ ) . 'class_amu.php';
$method = filter_input( INPUT_SERVER, 'REQUEST_METHOD', FILTER_SANITIZE_STRING );
$amu = new AMU;
if ( strtoupper( $method ) === 'POST' ) {
$amu->save();
}
add_action( 'all_admin_notices', array ( $amu, 'form' ), PHP_INT_MAX );
}
/**
* Let the game starts
*/
add_action( 'load-upload.php', 'GM\initAMU' );
<?php
namespace GM;
class AMU {
private $info = array ();
/**
* Run when upload.php is load from a POST method (i.e. a fome sumbit to upload.php)
* After same checks (file existence, capability, nonce..) done by AMU::shouldSave() method
* try to save the file sent via form as an attachment post, set AMU::$info property
* according to results and finally attach to hook 'admin_notices' the method AMU::admin_notices()
* that print a feedback to users
*
* @return void
* @access public
* @uses shouldSave() Check data sent via form
* @uses GM\AMU\create() Create the attachment post
*/
function save() {
if ( ! $this->shouldSave() ) {
return;
}
$file = filter_input( INPUT_POST, 'file_in_server', FILTER_SANITIZE_STRING );
if ( ! empty( $file ) ) {
remove_action( current_filter(), array ( $this, __FUNCTION__ ) );
$id = $this->create( $file );
if ( is_wp_error( $id ) ) {
$this->info = array ( 'type' => 'error', 'msg' => $id->get_error_message() );
} elseif ( is_numeric( $id ) ) {
$url = self_admin_url( "post.php?post={$id}&action=edit" );
$msg = sprintf( 'Attachment saved! <a href="%s">See it</a>.', esc_url( $url ) );
$this->info = array ( 'type' => 'updated', 'msg' => $msg );
}
if ( ! empty( $this->info ) ) {
add_action( 'admin_notices', array ( $this, 'admin_notices' ) );
}
}
}
/**
* Print the form inside upload.php including file in plugin folder file that contain the markup
*
* @return void
* @access public
*/
function form() {
if ( get_current_screen()->id !== 'upload' ) {
return;
}
remove_action( current_filter(), array ( $this, __FUNCTION__ ) );
$wp_upload_dir = wp_upload_dir();
$base = trailingslashit( $wp_upload_dir['basedir'] );
require plugin_dir_path( __FILE__ ) . 'form.php';
}
/**
* Print admin notices when form is submitted giving feedback to users
*
* @return void
*/
function admin_notices() {
if ( current_filter() !== 'admin_notices' ) {
return;
}
remove_action( current_filter(), array ( $this, __FUNCTION__ ) );
$format = '<div class="%s"><p>%s</p></div>';
if ( empty( $this->info ) ) {
return;
}
if ( ! isset( $this->info['type'] ) ) {
$this->info['type'] = 'error';
}
if ( ! isset( $this->info['msg'] ) ) {
$this->info['msg'] = 'Unknown';
}
printf( $format, $this->info['type'], $this->info['msg'] );
$this->info = array ();
}
/**
* Get a relative path to a file and create an attachment post
*
* @param string $file Relative path to 'uploads folder' for the file
* @return int The attachment ID, 0 on failure
* @access private
* @uses shouldCreate
*/
private function create( $file = '' ) {
$wp_upload_dir = wp_upload_dir();
$fullpath = $this->shouldCreate( $file, $wp_upload_dir );
if ( is_wp_error( $fullpath ) ) {
return $fullpath;
}
$filetype = wp_check_filetype( basename( $fullpath ), NULL );
$attachment = array (
'guid' => $wp_upload_dir['url'] . '/' . basename( $fullpath ),
'post_mime_type' => $filetype['type'],
'post_title' => preg_replace( '/\.[^.]+$/', '', basename( $fullpath ) ),
'post_content' => '',
'post_status' => 'inherit'
);
$attach_id = wp_insert_attachment( $attachment, $fullpath, 0 );
require_once( ABSPATH . 'wp-admin/includes/image.php' );
$attach_data = wp_generate_attachment_metadata( $attach_id, $fullpath );
wp_update_attachment_metadata( $attach_id, $attach_data );
return $attach_id;
}
/**
* Check current user and nonce to see if to going on saving the file sent via form
* @return boolean
*/
private function shouldSave() {
if ( ! current_user_can( 'upload_files' ) ) {
return FALSE;
}
if ( ! check_admin_referer( 'file_in_server', '_n' ) ) {
return FALSE;
}
return TRUE;
}
/**
* Check existence of the file and using AMU::isAttached() check if it is already attached to
* an existend attachemnt post. Return fullpath of the file if both check are passed.
*
* @param string $file Relative path to 'uploads folder' for the file
* @param array $wp_upload_dir Whatever returned by wp_upload_dir()
* @return string|\WP_Error Full path of the fail or WP_Error on failure
*/
private function shouldCreate( $file, $wp_upload_dir ) {
if ( ! is_string( $file ) || empty( $file ) ) {
$msg = sprintf( "Please use valid file relative path with %s", __FUNCTION__ );
return new \WP_Error( 'bad_file_arg', $msg );
}
$base = $wp_upload_dir['basedir'];
$fullpath = trailingslashit( $base ) . $file;
if ( ! file_exists( $fullpath ) ) {
$msg = sprintf( "The file %s does not exists", $fullpath );
return new \WP_Error( 'file_not_exists', $msg );
}
$already = $this->isAttached( $file );
if ( $already > 0 ) {
$url = get_edit_post_link( $already, '' );
$link = sprintf( '<a href="%s">(ID: %d)</a>', $url, $already );
$msg = sprintf( "The file %s is already connected to an attachment %s", $file, $link );
return new \WP_Error( 'file_attached', $msg );
}
return $fullpath;
}
/**
* Query database to see if a file is already attached to an attachement post
*
* @global wpdb $wpdb
* @param string $file Relative path to 'uploads folder' for the file
* @return int Attachement post id if found, 0 otherwise
*/
private function isAttached( $file ) {
global $wpdb;
$query = "SELECT p.ID FROM {$wpdb->posts} p "
. "INNER JOIN {$wpdb->postmeta} m ON p.ID = m.post_id "
. "WHERE p.post_type = 'attachment' "
. "AND m.meta_key = '_wp_attached_file' "
. "AND m.meta_value = %s GROUP BY p.ID LIMIT 1";
return (int) $wpdb->get_var( $wpdb->prepare( $query, $file ) );
}
}
<?php if ( ! defined( 'ABSPATH' ) || ! isset( $base ) ) exit(); ?>
<div class="wrap">
<h3>Convert an uploaded file to a media post
<a href="#" id="hide-attachment_from_server" class="add-new-h2">+</a>
</h3>
<form method="post" style="display:none;">
<?php wp_nonce_field( 'file_in_server', '_n' ); ?>
<table class="form-table">
<tbody>
<tr>
<td>
<label for="attachment_from_server">
<strong>File path:</strong>
</label><br>
<?php echo $base ?>
<input name="file_in_server" value="" class="regular-text code" type="text">
</td>
</tr>
</tbody>
</table>
<p class="submit">
<input name="submit" class="button button-primary" value="Create Attachment" type="submit">
</p>
</form>
<hr>
</div>
<script>
jQuery(document).on('click', '#hide-attachment_from_server', function(e) {
e.preventDefault();
var $btn = jQuery(this);
var $form = jQuery(this).closest('div.wrap').find('form');
if ($form.is(':visible')) {
$form.hide();
$btn.text('+');
} else {
$form.show();
$btn.html('&times;');
}
});
</script>
@mikaeldui
Copy link

Thank you! :)

@gemzid
Copy link

gemzid commented May 3, 2014

How to upload all file from a directory? I have hundred of images to import. Please, help me.

@Elbatron
Copy link

It seems that WP 3.9.1 has a problem with line 28 on amu.php.

@gmazzap
Copy link
Author

gmazzap commented Aug 17, 2014

@Elbatron I guess problem with that line is you version of PHP. Namespaces are supported in PHP 5.3+

@tarunmahashwari
Copy link

thanks

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