Loading the native WordPress image uploader in custom widget

All you have to do is to load a couple of scripts, four, to be precise.

  1. Register your widget class first
  2. Load the media library
  3. Pass some variables to translate things properly (please see translation standards of WordPress for more info about this.)
  4. Add your own script on top to trigger the modal window and handle the file upload

First register your widget as a class, then drop in the scripts:

<?php

    // We register our widget 
    function wpse_register_my_custom_widget(){
        register_widget('The_Custom_Image_Upload_Widget');
    }
    add_action('widgets_init', 'wpse_register_my_custom_widget');

    // in your plugin main file or functions.php when in a theme ..
    function wpse_load_media_library(){
        // Set $pagenow to global to check, where to load the scripts..
        global $pagenow;

        // make a variable for the path in case you don't have it
        $dir = plugins_url('/my-plugin-folder');

       // register your own script first
       wp_register_script(
           // WP internal name (so called "handle") this is important as you need to relate to this name later on
           'my-js-file-with-code',
            $dir . '/components/js/the-custom-image-upload-actions.js',
            array('jquery'),
            false,
            true
        );

        // Now let's kick in our scripts
        if($pagenow === 'widgets.php'){

            // Load/enqueue the media library, this is what you didn't find and struggled with..
            wp_enqueue_media();

            // load your own script with the trigger of the modal
            wp_enqueue_script('my-js-file-with-code');

            // Then pass some variables to wordpress in order to translate things in Javascript
            wp_localize_script(
                // WP Handle/ID of the script to translate
                'my-js-file-with-code',
                // random varname (array) which holds the strings
                'scripttext',
                    array(          // array with strings
                        'title' => __('Logo upload', 'textdomain'),
                        'button' => __('use this logo', 'textdomain'),
                        'multiple' => __('use these images', 'textdomain')
                    )
            );

     }
     add_action('admin_enqueque_scripts', 'wpse_load_media_library');
?>

// My JS file with code
<script>
   // image Upload
   $('#trigger_to_open_the_modal').click(function(e){
       var single_image_frame;
       e.preventDefault();
       if ( single_image_frame ) {
            single_image_frame.open();
            return;
        }
        single_image_frame = wp.media.frames.single_image_frame = wp.media({
            title: scripttext.title,
            button: { text:  scripttext.button },
            library: { type: 'image' }
        });
        single_image_frame.on('select', function(){
            var media_attachment = single_image_frame.state().get('selection').first().toJSON();
            // Adjust this to your needs, pops in the url to the img tag
            $('#custom-upload-logo').attr('src', media_attachment.url);
            $('#logo_url').val(media_attachment.url);
        });
        single_image_frame.open();
    });
   </script>

Since I don’t know your markup, I did not write any example HTML of your widget. This took me about an hour to write so I hope you don’t mind.