WordPress 3.4 added a great theme preview interface that allows us to easily customize theme options (colors, images, menus, and more), as well as quickly view those updates on a theme preview frame.
WordPress 3.5 added a new media manager interface that is fast, easy to use, and awesome to look at.
In this article, we consider how to bring those two interfaces together so that we can use images from our media library in the theme preview interface.
1. Create an Image Control
I start by creating an image control object. For more on how to create settings and controls for the theme preview interface, refer to the WordPress Theme Customization API.
function my_add_image_control( $slug, $label ) { global $wp_customize; static $count = 0; $id = "my_theme_settings[{$slug}]"; $wp_customize->add_setting( $id, array( 'type' => 'option', 'transport' => 'postMessage' ) ); $control = new WP_Customize_Image_Control( $wp_customize, $slug, array( 'label' => __( $label, 'my_theme' ), 'section' => 'my_image_section', 'priority' => $count, 'settings' => $id ) ); $wp_customize->add_control($control); $count++; return $control; }
I call this function from the customize_register action hook to create one or more image control objects.
// Add to customize_register action hook global $my_image_controls; $my_image_controls = array(); $my_image_controls['shiba_header_image'] = my_add_image_control('shiba_header_image', 'Header Image'); ...
2. Add Media Library Tab to Image Control
Once I finish creating all my image control objects, I add a Media Library tab to each of them.
The code below creates a Media Library tab for each image control object, with an Open Library button within it. An example image control with its Media Library tab is shown in the screenshot to the right.
global $my_image_controls; foreach ($my_image_controls as $id => $control) { $control->add_tab( 'library', __( 'Media Library' ), 'my_library_tab' ); } function my_library_tab() { global $my_image_controls; static $tab_num = 0; // Sync tab to each image control $control = array_slice($my_image_controls, $tab_num, 1); ?> <a class="choose-from-library-link button" data-controller = "<?php esc_attr_e( key($control) ); ?>"> <?php _e( 'Open Library' ); ?> </a> <?php $tab_num++; }
3. Tie the Open Library Button to the Media Manager Menu
Now, we are ready to tie the Open Library button to the media manager interface. To do this, we need to create our media manager menu using javascript, and then tie its click event to our Open Library button.
(function($) { // Object for creating WordPress 3.5 media upload menu // for selecting theme images. wp.media.shibaMediaManager = { init: function() { // Create the media frame. this.frame = wp.media.frames.shibaMediaManager = wp.media({ title: 'Choose Image', library: { type: 'image' }, button: { text: 'Insert into skin', } }); $('.choose-from-library-link').click( function( event ) { wp.media.shibaMediaManager.$el = $(this); var controllerName = $(this).data('controller'); event.preventDefault(); wp.media.shibaMediaManager.frame.open(); }); } // end init }; // end shibaMediaManager wp.media.shibaMediaManager.init(); }(jQuery));
Lines 9 to 17 – Create our media manager menu. This article goes into greater detail on the various wp.media options.
Line 20 – Tie the click event for our media manager menu to our ‘Open Library’ button created in the previous step. Note that choose-from-library-link is the same class that was used to encapsulate the ‘Open Library’ button(s) in step 2.
Line 23 – Prevent other actions from being tied to our Open Library button.
Line 25 – Open the media manager menu.
To enable the media library menu, I need to add the script above as well as other media manager relevant scripts. I put the script above into a file, e.g. shiba-media-manager.js, and include it using the wp_enqueue_script function.
add_action( 'customize_controls_enqueue_scripts', 'my_add_scripts' ); function my_add_scripts() { wp_enqueue_media(); wp_enqueue_script('shiba-media-manager', get_template_directory().'/js/shiba-media-manager.js', array( ), '1.0', true); }
With great anticipation, I include all the code above, then click on my ‘Open Library’ button … Nothing Happens!!
After some digging, it turns out that the menu is actually showing, it is just coming up below our page preview frame. To have the media manager menu show properly, we need to move the z-index value of our media manager menu up, or the z-index value of our page preview frame down. In the code below, I do the latter.
add_action( 'customize_controls_print_styles', 'my_customize_styles', 50); function my_customize_styles() { ?> <style> .wp-full-overlay { z-index: 150000 !important; } </style> <?php }
Now, when we click on the ‘Open Library’ button, the media manager menu appears!
Modify Image Control Based on Media Manager Selection
Fianlly, we need to connect our media manager image selection to our theme previewer image control. Since both objects are in javascript, all we need is a javascript function to modify the relevant objects (no AJAX calls are needed).
I add the code below into my shiba-media-manager.js file, right above the click event function.
// When an image is selected, run a callback. this.frame.on( 'select', function() { // Grab the selected attachment. var attachment = wp.media.shibaMediaManager.frame.state().get('selection').first(), controllerName = wp.media.shibaMediaManager.$el.data('controller'); controller = wp.customize.control.instance(controllerName); controller.thumbnailSrc(attachment.attributes.url); controller.setting.set(attachment.attributes.url); });
Line 4 – Get the image we selected in the media manager menu.
Line 5 – Get the image control name that triggered the selection (e.g. shiba_header_image).
Line 7 – Get the javascript image control object using the name retrieved in line 5.
Line 8 to 9 – Update the image control object with the image url we selected from the media manager menu.
This article has more on how to access javascript theme previewer controls and settings.
Success! Now when we select an image in the media manager menu, it updates the image control object and associated setting.
Agustin says
Hi, first i want to say thankyou for this great article.
I wan to ask you some help, i followed this tut as well, and get the media manager, but when i select an image and press “insert into skin” button i get this error:
TypeError: controller is undefined
controller.thumbnailSrc(attachment.attributes.url);
And i see the controllerName is empty, can you guide me a little.
Thanks for any help, by the way i’m with wp 3.8.1
Agustin says
Please forget i ask for this help, for some dumb reason I put this:
$my_image_controls[] = my_add_image_control('shiba_header_image', 'Header Image');
instead of:
$my_image_controls['shiba_header_image'] = my_add_image_control('shiba_header_image', 'Header Image');
now is obvious why the controllerName was empty, had 0 not empty…
san says
Hello, i am trying to make it working but i get error. can you tell me what i need to change to make it work with my theme.
thanks.
Sam says
I followed your tutorial which is impressively clean and object oriented
And found a problem that I was running into before
Uncaught TypeError: Cannot call method ‘replace’ of undefined
Now, this is happening in underscore.js and only inside of the Customizer
Not sure if this is just an issue with 3.5 but I greatly appreciated the help regardless
ShibaShake says
Sounds like there may be a missing file, some core file that needs to be included.
I use the code in my Genesis Skins and Shiba Skins themes, both of which run on 3.5. Feel free to have a look at the source. Shiba Skins is probably easier to look at since it is built on top of TwentyTwelve.
Neroth says
Hi you need the media templates 🙂 !
function add_media_manager_template_to_customizer() {
wp_print_media_templates();
}
add_action( ‘customize_controls_print_footer_scripts’, ‘add_media_manager_template_to_customizer’ );
nobug says
Man you saved my day! wp_print_media_templates was required indeed.