Creating Custom WordPress Media Frame

WordPress has a neat and fluent media manager, that is possibly one of the biggest strength of the CMS. Let’s see, how to make a custom implementation of the media frame, that we can integrate into a theme of plugin easily.

Getting Started

The media frame is based on the Backbone framework. Also, it depends quite much on jQuery as well. But good news, since these are placed in WP by default, we can easily pull them in where we want.

So, wherever we want, we can create a new frame and bind the open action to any element we wish. For example, a basic frame’s initialization would look like this:

(function () {
    window.addEventListener('DOMContentLoaded', function () {
        var frame;

        // Open or create the the media frame
        document.querySelector('#media-handler').addEventListener('click', function (event) {
            event.preventDefault();

            if (frame) {
                frame.open();
                return;
	    }

            frame = wp.media({
                title: 'Your title',
                button: { text: 'Insert' },
                multiple: false,
            }).on('select', function () {
                var attachment = frame.state('insert').get('selection').first().toJSON();
                $('#frontend-image').attr('src', attachment.url);
            });

            frame.open();
        });
    });
})();

It’s easy and neat, but it’s possible, that we need a bit customized frame, with custom tabs and query parameters. Let’s see!

Creating a Custom Media Frame

There are different types of media frames defined by default. In this case, we will extend the Post media frame and customize the menu by adding only custom tabs to the media handler.

So, basically, we need to define states, that will handle the options and the queries for the different views. When we extend the Post media frame, we can hook in the createStates method, and override the default states:

wp.media.view.MediaFrame.CustomFrame = wp.media.view.MediaFrame.Post.extend({
	createStates: function () {
		var options = this.options;

		this.states.add([
			// The base insert state
			new wp.media.controller.Library({
				id: 'insert',
				title: 'Insert Media',
				priority: 20,
				toolbar: 'main-insert',
				filterable: 'all',
				library: wp.media.query(options.library),
				multiple: false,
				editable: false,
				allowLocalEdits: false,
				displaySettings: false,
				displayUserSettings: false,
			}),

			// The christmas category state
			new wp.media.controller.Library({
				id: 'christmas',
				title: 'Christmas',
				priority:  30,
				toolbar: 'main-insert',
				filterable: 'all',
				multiple: false,
				library: wp.media.query(_.defaults({
					category: 'christmas',
				}, options.library)),
				editable: false,
				allowLocalEdits: false,
				displaySettings: false,
				displayUserSettings: false,
			}),
		]);
	},
});
For the Christmas state, in the library property, we defined an extra parameter called category. This parameter will be passed with the AJAX request when requesting the attachments. By the help of the extra parameter, we can filter the attachments based on the states. For example, we can list only the attachments which have a “christmas” value in a meta field.

So, from here we have a custom media frame that we can initialize and open like in the first section.

...

frame = new wp.media.view.MediaFrame.CustomFrame({
    // Some options
}).on('select', function () {
    var attachment = frame.state('insert').get('selection').first().toJSON();
    $('#frontend-image').attr('src', attachment.url);
});

...

Summary

There are tons of options that you may apply for your own media frame. But this post can give a basic indication of how to customize your own frame. If you wish to use it on front-end, you need to take care of the protected AJAX actions for unauthenticated users.

Special thanks for the following recource(s): Icon made by Freepik from www.flaticon.com
Need a web developer? Maybe we can help, get in touch!