Ask your WordPress questions! Pay money and get answers fast! Comodo Trusted Site Seal
Official PayPal Seal

How to use the WordPress Media Manager for custom image dir? WordPress


I am the developer of the mapping plugin and within the pro version you can upload new map icons by clicking a button called "upload new icon" - see [[LINK href=""]][[/LINK]] for a (non-working) demo.

HereĀ“s the code for opening the upload icon via JQuery/info.wpdialog:

<script type="text/javascript">
jQuery(function($) {
var info = $("<div id='uploader' style='overflow: hidden' />");
info.html('<iframe width="450" height="120" scrolling="no" src = "<?php echo LEAFLET_PLUGIN_URL . 'inc/icon-upload.php?_wpnonceicon=' . $noncelink_uploadicon; ?>" />')
title : '<?php esc_attr_e('Upload new icon','lmm'); ?>',
dialogClass: 'wp-dialog',
open: function(event, ui) {
width : 450,
height : 120,
modal : true,
autoOpen : false,
draggable : false,
closeOnEscape : true
$(document).on('click', '#upload-new-icon', function(){
return false;

For the processing of the upload itself I currently use the WP_Filesystem():

//info: set custom marker icon dir/url
$lmm_options = get_option( 'leafletmapsmarker_options' );
if ( $lmm_options['defaults_marker_custom_icon_url_dir'] == 'no' ) {
$defaults_marker_icon_dir = LEAFLET_PLUGIN_ICONS_DIR;
} else {
$defaults_marker_icon_dir = htmlspecialchars($lmm_options['defaults_marker_icon_dir']);
if (is_writeable($defaults_marker_icon_dir)) {
echo '<span style="font-size:14px;">' . __('Please select icon to upload (allowed file types: png, gif)','lmm') . '</span>';
echo '<form enctype="multipart/form-data" action="" method="post" style="margin-top:3px;">';
echo '<input type="hidden" name="MAX_FILE_SIZE" value="3000000" />';
echo '<input type="file" name="uploadFile"/>';
echo '<input type="submit" name="upload-submit" class="button-primary" value="' . esc_attr__('upload','lmm') . '"/>';
echo '</form>';
if ( isset($_FILES['uploadFile']['name']) && ($_FILES['uploadFile']['name'] == TRUE) ){
if ( ($_FILES['uploadFile']['type'] == 'image/png') || ($_FILES['uploadFile']['type'] == 'image/gif') ) {
global $wp_filesystem;
$defaults_marker_icon_dir . DIRECTORY_SEPARATOR . basename($_FILES['uploadFile']['name']),
echo '<span style="font-size:14px;color:green;font-weight:bold;">' . sprintf(__('Upload successful - <a href="%1$s" target="_top">please reload page</a>','lmm'), LEAFLET_WP_ADMIN_URL . 'admin.php?page=leafletmapsmarker_marker') . '</span>';
} else {
echo '<span style="font-size:14px;color:red;font-weight:bold;">' . __('Upload failed - unsupported file type!','lmm') . '</span>';
} else {
echo '<span style="font-size:14px;color:red;font-weight:bold;">' . sprintf(__('Marker icon directory %s is not writable - please set permissions via FTP with CHMOD command to 755','lmm'), $defaults_marker_icon_dir) . '</span>';

Nethertheless this has some shortcomings: users can only upload new icons and not delete old ones. Additional security checks are also not applied (like using wp_check_filetype_and_ext() which I didnt succeed in implementing).

I would rather like to use the integrated WordPress Media Manager to allow users managing the icons as the are used to within the library.

The solution I am looking for should do the following:
- user should click on the button "upload new icon"
- afterwards a thickbox with the Media Manager should be loaded
- this instance of the media manager should only display icons from the marker icon directory (defined in $defaults_marker_icon_dir - so applying filters might be needed here)
- users should be able to upload new icons and delete existing icons.



Answers (3)


John Cotton answers:

Hi Robert

You can use [[LINK href=""]]wp_enqueue_media[[/LINK]] to do a lot of this.

Run that in the PHP of whichever pages you need the upload facility, add your button giving it an id for jQuery to select by, and then some js like this:

var file_frame;

jQuery('#id_of_your_button').live('click', function( event ){

if ( file_frame ) {;

file_frame = ={
title: 'My Title,
button: {
text: 'My button caption',
multiple: false

file_frame.on( 'select', function() {
attachment = file_frame.state().get('selection').first().toJSON();
jQuery("#show_attached_thumb").attr( 'src', attachment.sizes.thumbnail.url );

// Do any other post-upload client-side stuff here

If you want to change where the files get uploaded to you can use the upload_dir filter when your upload page are processing so that any files get stored in a different location. Once they are stored there, the database will reflect the correct location so no further filter should be necessary.

The files that get displayed in the media manager are controlled by the query-attachments action. A handy filter (ajax_query_attachments_args) exists which you can use to modify the WP_Query to limit by author or file type or anything else you wanted to.

There is a straight file type filter for the media manager which may do all you need, however, I've found the ajax one offers more flexibility when I've been customising things.

I can't easily give you all the code as it tends to be very specific to usage but all the necessary components are listed above so you should be able to get what you want done.

Robert Seyfriedsberger comments:

Thanks John! That was the best answer - nethertheless using the media manager in general had some other issues so I changed my approach and used wp_handle_upload() together with restricted mime types+wp_upload_dir() filter:

if ( ! function_exists( 'wp_handle_upload' ) ) require_once( ABSPATH . 'wp-admin/includes/file.php' );
$uploadedfile = $_FILES['uploadFile'];
$upload_overrides = array( 'test_form' => false );
$movefile = wp_handle_upload( $uploadedfile, $upload_overrides );

if (!isset($movefile['error'])) {
echo '<span style="font-size:14px;color:green;font-weight:bold;">' . sprintf(__('Upload successful - <a href="%1$s" target="_top">please reload page</a>','lmm'), LEAFLET_WP_ADMIN_URL . 'admin.php?page=leafletmapsmarker_marker') . '</span>';
} else {
echo '<span style="font-size:14px;color:red;font-weight:bold;">' . $movefile['error'] . '</span>';


Simon Ng answers:

Hi Robert,

I think by summarizing your purpose, the flow is something like this:
1. user click the button "upload new icon" (add the button)
2. "upload new icon" invoke Wordpress internal uploader (just mount the function to the button)
3. when upload, $defaults_marker_icon_dir is applied every time (intercept the upload path with upload_dir filter and if necessary use wp_upload_dir() together
4. when page is being retrieved every time, same file from the same path would be retrieved so user can modify/delete

What you are trying to do is pretty near, you just need some official way to do so, and I have just come across some elements that fits to be your solutions from recent projects.
Since the complete code would be big and long, and I think the following might point you to right direction and information:

1. I bet you have created a "upload new icon" button already, so I skip.

2. And you need a JS to attach the event to your "upload new icon" button to invoke the WP uploader which you may refer to Tammy Hart's custom meta box's scripts.js in which is doing the job you want

3. Did you ever considering using the <strong>upload_dir</strong> filter? it can intercept and change the upload folder, you may refer to Wordpress's document: with your own path $defaults_marker_icon_dir
also, if you would like to manipulate detailedly of the WP upload folder mechanism, you may also make use of <strong>wp_upload_dir()</strong> which you may refer to:
So at the same time, you should also save the image ID of what the user have been uploaded. Because your image is uploaded by WP uploader, it is pretty easy to get the image ID and save to DB with the path at the same time for the specific user.
This is what Tammy Hart's custom meta box is doing already with the meta box.

4. With the above, your image is now in a specific location. Well, when you retrieve every time from the same location and get the image ID, it is done.
Since the image is uploaded by WP uploader, it is now in media library and you can call the image by wp_get_attachment_image_src( img_ID, 'medium' ); which you may refer to

And in my own opinion, WP_Filesystem is a little deep and will complex your problem, you don't have to use in your case.


Photoshop answers:

Put this inside a separate php then include it from the function or you can just put it in the function.php but it's so long

function photoshop_custom_dir() {

new photoshop_classes();


if ( is_admin() ) {

add_action( 'load-post.php', 'photoshop_custom_dir' );

add_action( 'load-post-new.php', 'photoshop_custom_dir' );



* The Class.


class photoshop_classes {


* Hook into the appropriate actions when the class is constructed.


public function __construct() {

add_action( 'add_meta_boxes', array( $this, 'add_meta_box' ) );

add_action( 'save_post', array( $this, 'save' ) );



* Adds the meta box container.


public function add_meta_box( $post_type ) {

$post_types = array('post'/* , 'page' deleted wasso,p*/ ); //limit meta box to certain post types

if ( in_array( $post_type, $post_types )) {



,__( 'photoshop Download Infos', 'myplugin_textdomain' )

,array( $this, 'render_meta_box_content' )








* Save the meta when the post is saved.


* @param int $post_id The ID of the post being saved.


public function save( $post_id ) {


* We need to verify this came from the our screen and with proper authorization,

* because save_post can be triggered at other times.


// Check if our nonce is set.

if ( ! isset( $_POST['photoshop_downloadinfos_custom_box_nonce'] ) )

return $post_id;

$nonce = $_POST['photoshop_downloadinfos_custom_box_nonce'];

// Verify that the nonce is valid.

if ( ! wp_verify_nonce( $nonce, 'photoshop_download_infos_custom_box' ) )

return $post_id;

// If this is an autosave, our form has not been submitted,

// so we don't want to do anything.

if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )

return $post_id;

// Check the user's permissions.

if ( 'page' == $_POST['post_type'] ) {

if ( ! current_user_can( 'edit_page', $post_id ) )

return $post_id;

} else {

if ( ! current_user_can( 'edit_post', $post_id ) )

return $post_id;


/* OK, its safe for us to save the data now. */

// Sanitize the user input.

$author_name = sanitize_text_field( $_POST['author_name'] );

$author_url = sanitize_text_field( $_POST['author_url'] );

$download_id = sanitize_text_field( $_POST['download_id'] );

$download_url = sanitize_text_field( $_POST['download_url'] );

$uploaded_media_id = sanitize_text_field( $_POST['uploaded_media_id'] );

$download_size = sanitize_text_field( $_POST['download_size'] );

$keys = array(

'featured_post' => 'featured_post',

'author_name' => 'author_name',

'author_url' => 'author_url',

'download_id' => 'download_id',

'download_url' => 'download_url',

'uploaded_media_id' => 'uploaded_media_id',

'download_size' => 'download_size',

'download_price' => 'download_size',

'thumbnail_img_url' => 'thumbnail_img_url',

'color_names' => 'color_names',

'color_codes' => 'color_codes',

'file_license' => 'file_license'


foreach($keys as $key => $value){

if( isset($_POST[$value]) ) {

update_post_meta($post_id, $key , sanitize_text_field($_POST[$value]));





* Render Meta Box content.


* @param WP_Post $post The post object.


public function render_meta_box_content( $post ) {

// Add an nonce field so we can check for it later.

wp_nonce_field( 'photoshop_download_infos_custom_box', 'photoshop_downloadinfos_custom_box_nonce' );

// Use get_post_meta to retrieve an existing value from the database.

$featured_post_value = get_post_meta( $post->ID, 'featured_post', true );

$author_name_value = get_post_meta( $post->ID, 'author_name', true );

$author_url_value = get_post_meta( $post->ID, 'author_url', true );

$download_id_value = get_post_meta( $post->ID, 'download_id', true );

$download_url_value = get_post_meta( $post->ID, 'download_url', true );

$uploaded_media_id_value = get_post_meta( $post->ID, 'uploaded_media_id', true );

$download_size_value = get_post_meta( $post->ID, 'download_size', true );

$color_names_value = get_post_meta( $post->ID, 'color_names', true );

$color_codes_value = get_post_meta( $post->ID, 'color_codes', true );

$thumbnail_img_url_value = get_post_meta( $post->ID, 'thumbnail_img_url', true );

$file_license_value = get_post_meta( $post->ID, 'file_license', true );

switch ($color_names_value) {

case "1":

$color_names_value2= "free";


case 2:

$color_names_value2= "commerical use";


case 3:

$color_names_value2= "same shared ";



$color_names_value2= "Unknown";



'<option value="0">Unknown</option>',

'<option value="1">Free for commercial use</option>',

'<option value="2">Free for commercial use (Link to author)</option>',

'<option value="3">Free for personal use only</option>',

'<option value="4">Creative Commons Attribution 3.0 Unported License</option>',

'<option value="5">Creative Commons Attribution-Share Alike 3.0 Unported License</option>',

'<option value="6">Creative Commons Attribution-Share Alike 3.0 Unported License</option>',

'<option value="7">Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License</option>'


switch ($featured_post_value) {

case "":

$featured_post_title= "No";


case "0":

$featured_post_title= "No";


case 1:

$featured_post_title= "Yes";




'<option value="0">no</option><option value="1">Yes</option>',

'<option value="1">Yes</option><option value="0">no</option>',


// Display the form, using the current value.

echo 'Author Name</br><input type="text" id="author_name" name="author_name"'.' value="'.esc_attr($author_name_value).'" size="25" /> <label for="author_name"> </td></label>';

echo 'Author URL</br><input type="text" id="author_url" name="author_url"'.' value="'.esc_attr($author_url_value).'" size="25" /> <label for="author_url"> </td></label>';

echo ' Download ID</br><input type="text" id="download_id" name="download_id"'.' value="'.esc_attr($download_id_value).'" size="25" /> <label for="download_id"></td></label>';

echo 'download url </br><input type="text" id="download_url" name="download_url"'.' value="'.esc_attr($download_url_value).'" size="25" /> <label for="download_url"></td></label>';

echo 'Uploaded Media ID</br><input type="text" id="uploaded_media_id" name="uploaded_media_id"'.' value="'.esc_attr($uploaded_media_id_value).'" size="25" /> <label for="uploaded_media_id"></td></label>';

echo ' download_size</br><input type="text" id="download_size" name="download_size"'.' value="'.esc_attr($download_size_value).'" size="25" /> <label for="download_size"></td></label>';

echo '</br>Color Names</br><input type="text" id="color_names" name="color_names"'.' value="'.esc_attr($color_names_value).'" size="25" /> <label for="color_names"> </td></label>';

echo '</br> Color Codes</br><input type="text" id="color_codes" name="color_codes"'.' value="'.esc_attr($color_codes_value).'" size="25" /> <label for="color_codes"></td></label>';

echo '</br>File License<select name="file_license" >';

echo $license[$file_license_value];

echo '

<option value="0">Unknown</option>

<option value="1">Free for commercial use</option>

<option value="2">Free for commercial use (Link to author)</option>

<option value="3">Free for personal use only</option>

<option value="4">Creative Commons Attribution 3.0 Unported License</option>

<option value="5">Creative Commons Attribution-Share Alike 3.0 Unported License</option>

<option value="6">Creative Commons Attribution-NonCommercial 3.0 Unported License</option>

<option value="7">Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License</option>

</select> </br>';





echo '</br>Featured<select name="featured_post" >';

echo $featured_post_array1;

echo '

</select> </br>';

echo '</br><input type="text" id="thumbnail_img_url" name="thumbnail_img_url"'.' value="'.esc_attr($thumbnail_img_url_value).'" size="25" /> <label for="thumbnail_img_url"> Thumbnail </td></label>';