Advanced WordPress Theme Customizer – Day 1 : How to Use Default Media Uploader

Since then theme customizer is being used by most of the premium developers added support for it. As an individual theme developer you should add support for theme customization API to your theme as well for better customer satisfaction. Although it is a great API but there are still some improvements to be done and I am sure awesome core team is working hard to make wordpress more awesome!

Most of my clients liked and thanked me for adding theme customization support, some never bother. But one of my clients bring my attention to problem he is having with image uploader.

Hey Sisir, The wordpress theme you made for me looks really great! I really like the skin customizer that you sent me link. It was buried deep and hard to find though. I am having problem with image uploader. When I upload image it works fine but if I remove the image and save, come back other day and want to add the same image wordpress forgets and Uploaded tab is empty. So, I had to upload same image multiple time. Is it possible to use default image uploader instead?

So, lets dive into the tutorial and see how you can integrate the default image uploader to the theme customizer.

This tutorial requires basic knowledge of of Theme Customization API. If you are very new to it consider reading this post by Otto before you dive into this tutorial.


  • Platform: WordPress 3.4+
  • Technology: PHP
  • Difficulty: Intermediate


1. Getting Started

Download and install the basic wordpress theme on your testing server. I prefer installing wordpress on your computer to make the workflow easier and faster. You will need to install server to do so you can try using XAMPP or WAMP. You will get tons of tutorial on the web how to install them.

2. The Basic Theme

This is something I made for you using After installing the theme check the site. Its a very basic theme with site name as text logo, menu items, content area, a sidebar and a footer area. Not the best theme in the world but It will serve our purpose.wp-customizer-tutorial---preview-1Inside functions.php file I added a option group where I would like to save my theme option as serialized data. I didn’t added any theme option page as it is not in the scope of this tutorial. You will find enough tutorial how to do it as well.

3. File Structure

Create a php file customizer.php inside includes directory and a js file customizer.js under js directory. Now require_once the customizer.php file from functions.php file. It will still work if you put your customizer code on functions.php but I like to keep the customizer code separated from other codes so I can find it quickly when needed.

Add this code on functions.php file

require_once( TEMPLATEPATH . '/includes/customizer.php' );

4. Start Coding

Okey, enough of boring stuff. Lets get to the point! Go to Appearance > Themes and you should see a Customize link under the active theme. Click it and you will be redirect to the theme customizer. It should look like this.

wp-customizer-tutorial---preview-2You should be able to type in site title and it will be automatically change and show on the right side preview area.

5. Create a Custom Control Class

We will be creating a Custom control class which extends WP_Customize_Control class.

if (  class_exists( 'WP_Customize_Control' ) && !class_exists( 'Tut_Remix_Customized_Uploader' ) ) {
    class Tut_Remix_Customized_Uploader extends WP_Customize_Control{

        public function __construct ($manager, $id, $args){
            parent::__construct($manager, $id, $args);

        public function enqueue(){
            // enqueue scripts and styles for control

        public function render_content() {
            // html output for the control

Not that we have our class defined we can add the control to the UI. Add this code beginning of the customize.php.

add_action( 'customize_register', 'my_theme_customize_register', 11 );

function my_theme_customize_register($wp_customize){
    global $settings; // loads the option name for the theme

    $wp_customize->add_setting( $settings.'[logo]', array(
         'type'           => 'option',
         'capability'     => 'edit_theme_options'

    $wp_customize->add_control( new Tut_Remix_Customized_Uploader( $wp_customize, $settings.'[logo]', array(
         'label'      => 'Upload Logo',
         'section'    => "title_tagline",
         'priority' => 40
     ) ) );


It will add our new control just below the title and tagline text box. You will not see anything immediately because our render_content() method outputs nothing.

Enqueue Scripts and Styles:

Now that we have write our basic class. We start with enqueue some basic scripts that will be required for adding uploader. Lets create two new files customize-media-uploader.js under js folder and customize-media-uploader.css under css folder and register them inside enqueue() method.

public function enqueue() {
        // style sheets

        // javascripts
        wp_register_script( 'customize-media-uploader', get_template_directory_uri().'/js/customize-media-uploader.js', array('jquery', 'media-upload', 'thickbox', 'wp-plupload'), false, true);
        wp_register_style( 'customize-media-uploader', get_template_directory_uri().'/css/customize-media-uploader.css');
        wp_localize_script('customize-media-uploader', '_uploader', array('id' => $this->id) );
        wp_enqueue_script( 'customize-media-uploader' );
        wp_enqueue_style( 'customize-media-uploader' );

Pretty simple huh? We enqueue all scripts and styles needed along with our two new css and js files. Note that we used wp_localize_script() to pass the id of the settings field (this is the name of the option in the database). Also we don’t need to enqueue individual scripts using wp_enqueue_script() because we added them as dependency for the script customize-media-uploader.

Output HTML for The Control:

This part handles by the render_content() method. It will look like this.

public function render_content() {
    $src = $this->value();
    if( isset( $this->get_url ) )
        $src = call_user_func( $this->get_url, $src );
    <span><?php echo esc_html( $this->label ); ?></span>

    <a id="media-uploader" href="#">Select/Upload Image</a>
         <input data-customize-setting-link="<?php echo $this->id; ?>" type="hidden" value="<?php echo $src; ?>">
        <?php if ( empty( $src ) ):
             $style = "display:none;";
             $style = "display:inline-block;";
    <img src="<?php echo esc_url( set_url_scheme( $src ) ); ?>">
   <?php endif; ?>

<a href="#" style="<?php echo $style; ?>"><?php _e( 'Remove Image' ); ?></a>


Basically what it does is outputs the html required for the custom control. $this->value() returns the saved value for the option which we later used in the control to show it (as a src of img tag) as well as on the hidden input type.

It is very important to notice the data- attribute for the hidden field! data-customize-setting-link is the attribute which wordpress looks for the new value and saves not the name attribute.

At this point when you refresh the customizer UI you should see the upload button but it is not functional yet. Lets add some javascript code to make it work. Open up customize-media-uploader.js and add this piece of code.

jQuery(document).ready(function($) {

    $('.tut-customize-image-picker .tut-remove').click(function(e) {
    // functionality for remove image/logo button

    // remove the img tag

    // remove the hidden input filed

    // remove the remove button itself


$('.tut-customize-image-picker #media-uploader').click(function(e) {

    var current_item = $(this);
    tb_show('', 'media-upload.php?type=image&amp;TB_iframe=true');

    var original_send_to_editor = window.send_to_editor;
    window.send_to_editor = function(html) {
    var imgurl = jQuery('img',html).attr('src');
    var name =;
    // console.log(name);
    current_item.siblings('.current-image').children('div').html('<img src="'+imgurl+'">');
    window.send_to_editor = original_send_to_editor;

 return false;

Whenever you change the value for an input field you will need to call change(). Otherwise wordpress will not acknowledge the chanage and the Save & Publish button will remain inactive.

Put these css inside customize-media-uploader.css

#TB_overlay, #TB_window{

    margin: 5px 0;

.current-image img{
    max-width: 100%;

Tips: Notice z-index property for #TB_overlay, #TB_window. WordPress adds css class wp-full-overlay on the parent div which is z-index of 500000, so unless you set z-index for your thickbox larger then this number your thickbox won’t show up.

6. Integrating Logo Image to Theme

So you have it. Save and you will see the image shows up as preview on after the upload button. Now lets add the logo image to our theme itself. Open up index.php file and change logo container code to

<div id="logo">
    <?php if( theme_option('logo') ): ?>
    <a href="<?php echo home_url(); ?>"><img src="<?php echo theme_option('logo'); ?>" alt="<?php bloginfo('name'); ?>"></a>
    <?php else: ?>
    <h1><a href="<?php echo home_url(); ?>"><?php bloginfo('name'); ?></a></h1>
    <?php endif; ?>

And we are done! :) Using this handy uploader class you can add image which is more flexible then default image uploading class. If you have any questions please let me know comment section.

No TweetBacks yet. (Be the first to Tweet this post)

About Sisir

Hello! I am a freelance graphic designer, developer and engineer based on Bangladesh. I like my PC, my coffee cup and Internet.

3 Responses to Advanced WordPress Theme Customizer – Day 1 : How to Use Default Media Uploader

  1. Chelsy Brown August 12, 2013 at 10:59 am #

    Great work.. :) I can easily understand this tutorial.

  2. Tosca September 9, 2013 at 11:52 pm #

    This is great. Can you make these files available to download? This would help with understanding. For example – “We will be creating a Custom control class which extends WP_Customize_Control class” – I don’t think you say which file to add the code the code below this statement.
    Thanks again….Tosca

    • Tosca September 9, 2013 at 11:55 pm #

      sorry…just seen the download button!

Leave a Reply