WordPress already has a nice media uploader built in, so there is no reason to build another one into your theme or plugin. Pulling it into your project is also pretty simple if you know how to do it. Finding the elusive code is not as simple as you would think, though, as you probably know by now too.
After hours and hours of searching through code examples that were either outdated or simply did not work, I finally found some code that did half the job. Then, after searching some more and almost giving up, I found the last piece that made the uploader script complete and work properly.
This version uses the WordPress media modal and works with multiple upload fields on the same admin page.
1. Enqueue The Media Uploader
First, enqueue the WordPress media scripts and your own admin JavaScript file. Add this to your plugin file or to your theme’s functions.php.
add_action('admin_enqueue_scripts', 'twd_enqueue_media_uploader');
function twd_enqueue_media_uploader($hook) {
// Optional: limit this to your own settings page.
// if ($hook !== 'settings_page_your_settings_page') {
// return;
// }
wp_enqueue_media();
wp_enqueue_script(
'twd-media-uploader',
plugin_dir_url(__FILE__) . 'admin-media-uploader.js',
array('jquery'),
'1.0.0',
true
);
}
If you are using this in a theme instead of a plugin, change the script URL to something like this:
wp_enqueue_script(
'twd-media-uploader',
get_template_directory_uri() . '/js/admin-media-uploader.js',
array('jquery'),
'1.0.0',
true
);
2. Add The Upload Field Markup
Next, add a text field, upload button, remove button, and optional preview image wherever your option field belongs.
<div class="twd-media-field">
<input
type="text"
class="regular-text twd-media-url"
name="my_theme_options[logo_url]"
value="<?php echo esc_attr($logo_url); ?>"
/>
<button type="button" class="button twd-media-upload">
Upload Image
</button>
<button type="button" class="button twd-media-remove">
Remove
</button>
<div class="twd-media-preview">
<?php if (!empty($logo_url)) : ?>
<img src="<?php echo esc_url($logo_url); ?>" alt="" style="max-width:200px;height:auto;" />
<?php endif; ?>
</div>
</div>
You can repeat this markup multiple times on the same page. The JavaScript below scopes itself to the field group that was clicked, so each upload button updates the correct input and preview.
3. Add The JavaScript
Create a file named admin-media-uploader.js and add this code:
(function ($) {
let mediaFrame;
$(document).on('click', '.twd-media-upload', function (event) {
event.preventDefault();
const button = $(this);
const field = button.closest('.twd-media-field');
const input = field.find('.twd-media-url');
const preview = field.find('.twd-media-preview');
mediaFrame = wp.media({
title: 'Select or Upload Image',
button: {
text: 'Use this image'
},
multiple: false
});
mediaFrame.on('select', function () {
const attachment = mediaFrame.state().get('selection').first().toJSON();
input.val(attachment.url).trigger('change');
preview.html(
'<img src="' + attachment.url + '" alt="" style="max-width:200px;height:auto;" />'
);
});
mediaFrame.open();
});
$(document).on('click', '.twd-media-remove', function (event) {
event.preventDefault();
const field = $(this).closest('.twd-media-field');
field.find('.twd-media-url').val('').trigger('change');
field.find('.twd-media-preview').empty();
});
})(jQuery);
4. Saving The Value
The upload field stores the image URL in a normal input, so you can save it the same way you save the rest of your plugin or theme options.
If you are using the WordPress Settings API, make sure your sanitization callback allows a URL and escapes it when outputting it later.
function twd_sanitize_options($input) {
$output = array();
if (!empty($input['logo_url'])) {
$output['logo_url'] = esc_url_raw($input['logo_url']);
}
return $output;
}
That is it. So simple.
I wanted to use this feature for a long time but had not had the chance until recently. I will also be using it in a new related posts plugin I am working on that will be available soon. It should be a good one, so keep an eye out for it.
If this becomes stale like other uploader scripts out there, and I have not updated it yet, please let me know and I will update it.