Using WordPress Media Library in Widgets options

So how to add WordPress media uploader popup to our custom widget?

That’s not so hard, hovewer there are a few caveats.

Let’s start from our simple widget class, I’d recommend to get example from https://codex.wordpress.org/Widgets_API#Example. Then we will need to add our new option, it will be called “image”. Just copy and paste fields in the “form” function, to render widget form and “update” function, to save this option.

I would recommend to catch php output buffer, it may be helpful if you will want to cache widget output. So our “widget” function will look like this:


	public function widget( $args, $instance ) {
		// Our variables from the widget settings
		$title = apply_filters( 'widget_title', empty( $instance['title'] ) ? __( 'Default title', 'text_domain' ) : $instance['title'] );
		$image = ! empty( $instance['image'] ) ? $instance['image'] : '';

		ob_start();
		echo $args['before_widget'];
		if ( ! empty( $instance['title'] ) ) {
			echo $args['before_title'] . $title . $args['after_title'];
		}
		?>

		<?php if($image): ?>
			<img src="<?php echo esc_url($image); ?>" alt="">
		<?php endif; ?>

		<?php
		echo $args['after_widget'];
		ob_end_flush();
	}

Our “form” function will be:


	public function form( $instance ) {
		$title = ! empty( $instance['title'] ) ? $instance['title'] : __( 'New title', 'text_domain' );
		$image = ! empty( $instance['image'] ) ? $instance['image'] : '';
		?>
		<p>
			<label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php _e( 'Title:' ); ?></label>
			<input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo esc_attr( $title ); ?>">
		</p>
		<p>
			<label for="<?php echo $this->get_field_id( 'image' ); ?>"><?php _e( 'Image:' ); ?></label>
			<input class="widefat" id="<?php echo $this->get_field_id( 'image' ); ?>" name="<?php echo $this->get_field_name( 'image' ); ?>" type="text" value="<?php echo esc_url( $image ); ?>" />
			<button class="upload_image_button button button-primary">Upload Image</button>
		</p>
		<?php
	}

And our update function:


	public function update( $new_instance, $old_instance ) {
		$instance = array();
		$instance['title'] = ( ! empty( $new_instance['title'] ) ) ? strip_tags( $new_instance['title'] ) : '';
		$instance['image'] = ( ! empty( $new_instance['image'] ) ) ? $new_instance['image'] : '';

		return $instance;
	}

As you can see, I’ve added a button underneath image input field with class “.upload_image_button”, but it will not work for now and to make it work we will need to add our custom admin javascript.

First what we need is to create our javascript file and put it into our theme, let’s create a file, called our_admin.js in assets/js under our theme folder.

Next we will need to register and enqueue our script to make it load in the admin panel, so lets add few lines to our widget class constructor function:


	function __construct() {

		// Add Widget scripts
		add_action('admin_enqueue_scripts', array($this, 'scripts'));

		parent::__construct(
			'our_widget', // Base ID
			__( 'Our Widget Title', 'text_domain' ), // Name
			array( 'description' => __( 'Our Widget with media files', 'text_domain' ), ) // Args
		);
	}

And we will need then “scripts” function in our widget class:


	public function scripts()
	{
		wp_enqueue_script( 'media-upload' );
		wp_enqueue_media();
		wp_enqueue_script('our_admin', get_template_directory_uri() . '/assets/js/our_admin.js', array('jquery'));
	}

As you can notice, we also added wp_enqueue_script( ‘media-upload’ ); and wp_enqueue_media(); to enqueue media library popup scripts.

And finally, here is our script, that will call WordPress media library popup and put selected image into the input field:


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

	$(document).on("click", ".upload_image_button", function (e) {
		e.preventDefault();
		var $button = $(this);


		// Create the media frame.
		var file_frame = wp.media.frames.file_frame = wp.media({
			title: 'Select or upload image',
			library: { // remove these to show all
				type: 'image' // specific mime
			},
			button: {
				text: 'Select'
			},
			multiple: false  // Set to true to allow multiple files to be selected
		});

		// When an image is selected, run a callback.
		file_frame.on('select', function () {
			// We set multiple to false so only get one image from the uploader

			var attachment = file_frame.state().get('selection').first().toJSON();

			$button.siblings('input').val(attachment.url);

		});

		// Finally, open the modal
		file_frame.open();
	});
});

So thats it, now, when you click on “Upload Image” button, WordPress media library popup will open and you will be able easily upload or select already uploaded image for widget options form.