Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Open/Access WP Media library from tinymce plugin popup window

I'm building a tinymce button plugin for the Wordpress (4) editor. The popup window that my button opens displays a form with several fields. One of them is for selecting an image inside the WP media library. I can't figure how to achieve this. If that's not possible, what would be the best way to allow the user to select an image stored in the WP media library from a tinymce plugin popup window ?

FYI, the tinymce plugin inserts a shortcode with an image src as an attribute.

thanks !

like image 391
Maxime Freschard Avatar asked Oct 08 '14 18:10

Maxime Freschard


3 Answers

I had the same problem just now and found the solution so I'm sharing it here. I hope it's not too late.

First to be able to use WP Add Media button you would have to enqueue the needed script. This is easy, just call the wp_enqueue_media() function like so:

add_action('admin_enqueue_scripts', 'enqueue_scripts_styles_admin');
function enqueue_scripts_styles_admin(){
    wp_enqueue_media();
}

This call ensures you have the needed libraries to use the WP Media button.

Of course you should also have the HTML elements to hold the uploaded/selected media file URL, something like this:

<input type="text" class="selected_image" />
<input type="button" class="upload_image_button" value="Upload Image">

The first text field will hold the URL of the media file while the second is a button to open the media popup window itself.

Then in your jscript, you'd have something like this:

    var custom_uploader;

    $('.upload_image_button').click(function(e) {
        e.preventDefault();

        var $upload_button = $(this);

        //Extend the wp.media object
        custom_uploader = wp.media.frames.file_frame = wp.media({
            title: 'Choose Image',
            button: {
                text: 'Choose Image'
            },
            multiple: false
        });

        //When a file is selected, grab the URL and set it as the text field's value
        custom_uploader.on('select', function() {
            var attachment = custom_uploader.state().get('selection').first().toJSON();
            $upload_button.siblings('input[type="text"]').val(attachment.url);
        });

        //Open the uploader dialog
        custom_uploader.open();

    });

Now I'm not going to explain every line because it's not that hard to understand. The most important part is the one that uses the wp object to make all these to work.

The tricky part is making all these work on a TinyMCE popup(which is the problem I faced). I've searched hi and lo for the solution and here's what worked for me. But before that, I'll talk about what problem I encountered first. When I first tried to implement this, I encountered the "WP is undefined" problem on the popup itself. To solve this, you just have to pass the WP object to the script like so:

(function() {
tinymce.create('tinymce.plugins.someplugin', {
    init : function(ed, url) {
        // Register commands
        ed.addCommand('mcebutton', function() {
            ed.windowManager.open(
                {
                    file : url + '/editor_button.php', // file that contains HTML for our modal window
                    width : 800 + parseInt(ed.getLang('button.delta_width', 0)), // size of our window
                    height : 600 + parseInt(ed.getLang('button.delta_height', 0)), // size of our window
                    inline : 1
                },
                {
                    plugin_url : url,
                    wp: wp
                }
            );
        });

        // Register buttons
        ed.addButton('someplugin_button', {title : 'Insert Seomthing', cmd : 'mcebutton', image: url + '/images/some_button.gif' });
    }
});

// Register plugin
// first parameter is the button ID and must match ID elsewhere
// second parameter must match the first parameter of the tinymce.create() function above
tinymce.PluginManager.add('someplugin_button', tinymce.plugins.someplugin);

})();

What we're interested in is this line => "wp: wp" . This line ensures that we are passing the wp object to the popup window (an iframe really...) that is to be opened when we click the tinymce button. You can actually pass anything to the popup window via this object (the 2nd parameter of the ed.windowManager.open method)!

Last but not the least you'd have to reference that passed wp object on your javascript like so:

    var args = top.tinymce.activeEditor.windowManager.getParams();
    var wp = args.wp;

Make sure you do that before calling/using the WP object.

That's all you have to do to make this work. It worked for me, I hope it works for you :)

like image 167
Paolo Avatar answered Sep 25 '22 00:09

Paolo


I took the code of Paolo and simplified it in order not to have many files to manage. Also, I didn't manage to make it work like this.

So this solution has less code and uses only one single file.

Just put this in your tinyMCE plugins js file:

(function(){
    tinymce.PluginManager.add('myCustomButtons', function(editor, url){
        editor.addButton('btnMedia', {
            icon: 'image',
            tooltip: 'Add an image',
            onclick: function() {
                editor.windowManager.open({
                    title: 'Add an image',
                    body: [{
                        type: 'textbox',
                        subtype: 'hidden',
                        name: 'id',
                        id: 'hiddenID'
                    },
                    {
                        type: 'textbox',
                        name: 'text',
                        label: 'Text',
                        id: 'imageText'
                    },
                    {
                        type: 'button',
                        text: 'Choose an image',
                        onclick: function(e){
                            e.preventDefault();
                            var hidden = jQuery('#hiddenID');
                            var texte = jQuery('#imageText');
                            var custom_uploader = wp.media.frames.file_frame = wp.media({
                                title: 'Choose an image',
                                button: {text: 'Add an image'},
                                multiple: false
                            });
                            custom_uploader.on('select', function() {
                                var attachment = custom_uploader.state().get('selection').first().toJSON();
                                hidden.val(attachment.id);
                                if(!texte.val()){
                                    if(attachment.alt)
                                        texte.val(attachment.alt);
                                    else if(attachment.title)
                                        texte.val(attachment.title);
                                    else
                                        texte.val('See the image');
                                }
                            });
                            custom_uploader.open();
                        }
                    }],
                    onsubmit: function(e){
                        var image = '<button data-id="'+e.data.id+'">'+e.data.text+'</button>';
                        editor.insertContent(image);
                    }
                });
            }
        });
    });
})();

The result in the frontend html is a button which has the ID of the image in a data-id attribute, and a text to display (the alt of the image, by default, or its title or a text the user can write).

Then, with my frontend js, I will get the corresponding image with its ID and show it in an ajax popup.

With this solution, you have all of your js functions in one single file, and you don't need to enqueue any script nor to create a php file.

like image 22
Quentin D Avatar answered Sep 24 '22 00:09

Quentin D


I know it's old but in case anyone else facing the same situation, The Paolo's solution above is working fine but no need to enqueue wp_enqueue_media(); this will load a bunch of scripts, you can load only 2 scripts:

wp_enqueue_script( 'jquery' );
wp_enqueue_script( 'media-lib-uploader-js' ); 
like image 26
Abukwaik Avatar answered Sep 25 '22 00:09

Abukwaik