John Russell Blog

WordPress Editor Custom Buttons and Dialog Windows

When building a custom website on WordPress one goal is to ensure that it’s as easy as possible for the client to be able to create, update, and maintain their own content. Depending on the complexity of the site, or custom features that are added, there are times that the built-in editor doesn’t provide enough functionality. So, being able to add your own buttons or menus is critical. Thankfully, with the release of WordPress 3.9 which incorporated TinyMCE 4.0, customizing the WordPress editor is easier than ever. In this guide I’ll explain how to create custom buttons and dialog windows, packaged as a simple TinyMCE 4.x plugin, in order to customize the WordPress editor.

Getting Started

The first thing we need to do is add the necessary actions and filters to our WordPress plugin or theme to let it know that we’re wanting to customize the editor. The action we’ll be hooking into is “admin_head” and the filters are “mce_external_plugins”, and “mce_buttons”. Let’s go ahead and gets some code added.

function lb_add_tinymce() {
	global $typenow;
	if (empty($typenow)) return;
	    
	add_filter('mce_external_plugins', 'lb_mce_external_plugins_filter');
	add_filter('mce_buttons', 'lb_mce_buttons_filter');
}
add_action('admin_head', 'lb_add_tinymce');

The “admin_head” action hook is checking to see if the current admin screen being viewed represents a post type, whether it be “post”, “page”, or any other custom post type. Next it’s adding the necessary filter hooks needed in order to actually add the TinyMCE plugin and TinyMCE button. Next we’ll need to created the callback functions for each of the filters.

function lb_mce_external_plugins_filter($plugin_array) {
	$plugin_array['my_mce_plugin'] = get_template_directory_uri() . '/js/my-mce-plugin.js';
	    
	return $plugin_array;
}

This callback function is pushing our TinyMCE plugin into the $plugin_array variable so that WordPress is aware of its existence. In this case I’ve named the plugin “my_mce_plugin”, but you’ll want to change this to match the naming of your own plugin. I’m also assuming your plugin is being added to your WordPress theme within a “js” folder, so if this is not the case you’ll need to make necessary edits.

function lb_mce_buttons_filter($buttons) {
	array_push($buttons, 'my_mce_plugin');
	    
	return $buttons;
}

This callback function is pushing the “my_mce_plugin” into the $buttons array so that WordPress knows to add our plugin to the list of buttons in the editor. Note that this specific filter hook will add the button to the top, primary toolbar, row. If you’d like to add your button to the second, advanced toolbar, row you will need to use the “mce_buttons_2” filter instead. There are filters for the third and fourth toolbar rows, however WordPress disables these toolbars by default so in many cases they will not be used.

Creating the TinyMCE Plugin

Now that all of the necessary WordPress action and filter hooks are in place the only thing left to do is actually create the TinyMCE plugin. First, we’ll add the framework for the plugin. Note that this will go into a new JavaScript file.

(function() {
	tinymce.create('tinymce.plugins.my_mce_plugin', {
        init: function(editor, url) {
            editor.addButton('my_mce_plugin', {
            	type: 'menubutton',
            	text: 'My MCE Plugin',
                icon: false,
                menu: [
                	{
	                	text: 'Shortcode 1',
	                	onclick: function() { tinyMCE.activeEditor.execCommand('shortcode1'); }
                	},
                	{
	                	text: 'Shortcode 2',
	                	onclick: function() { tinyMCE.activeEditor.execCommand('shortcode2'); }
                	},
                	{
	                	text: 'Shortcode 3',
	                	onclick: function() { tinyMCE.activeEditor.execCommand('shortcode3'); }
                	}
                ]
            });

            data = {};

            editor.addCommand('shortcode1', function() {
                tinymce.execCommand('mceInsertContent', false, '[shortcode1]');
            });

            editor.addCommand('shortcode2', function() {
                tinymce.execCommand('mceInsertContent', false, '[shortcode2]');
            });

            editor.addCommand('shortcode3', function() {
                tinymce.execCommand('mceInsertContent', false, '[shortcode3]');
            });
        },
        createControl: function(n, cm) {
            return null;
        },
        getInfo: function() {
            return {
                longname : 'My MCE Plugin',
                author : 'laubsterboy',
                authorurl : 'http://laubsterboy.com',
                infourl : 'http://laubsterboy.com',
                version : "1.0"
            };
        }
    });

    tinymce.PluginManager.add('my_mce_plugin', tinymce.plugins.my_mce_plugin);
})();

There are a couple of things to point out in the above code. First, what we’re doing is creating a plugin using the tinymce API and then registering it with the tinymce plugin manager. Next, within the plugin creation code, you can see that we’re adding a button to the editor. This button happens to be a menu (menubutton) with three menu items. Each menu item has an onclick event listener that then executes a tinymce command. The commands are registered just below the menu code. Right now the commands are simply inserting text into the WordPress editor as shortcodes. However, wouldn’t it be nice to allow your client to be able to visually select options for the shortcode and then have the corresponding shortcode text insert into the WordPress editor? This is where the TinyMCE Dialog box (windowManager) comes into play.

To illustrate this we’ll customize the “shortcode3” command to open a dialog box, allow for user input, and then output the shortcode text. To do this we will completely rewrite the shortcode3 command. For now, we’ll create two inputs within the dialog box. One will allow the client to enter a title shortcode attribute and the other will allow them to enter a limit shortcode attribute. Note that these attributes will not do anything, since the shortcode does not exist, but are used to illustrate how you could accomplish this and adapt it to your own project.

editor.addCommand('shortcode3', function() {
    var data = {
        title: 'Default Title',
        limit: 10
    }
    editor.windowManager.open({
        title: 'Insert Shortcode 3',
        data: data,
        body: [
            {
                name: 'title',
                type: 'textbox',
                label: 'Title',
                value: data.title
                onchange: function() { data.title = this.value(); }
            },
            {
                name: 'limit',
                type: 'listbox',
                label: 'Limit',
                values: [
                    {
                        value: 10,
                        text: '10'
                    },
                    {
                        value: 9,
                        text: '9'
                    },
                    {
                        value: 8,
                        text: '8'
                    },
                    {
                        value: 7,
                        text: '7'
                    },
                    {
                        value: 6,
                        text: '6'
                    },
                    {
                        value: 5,
                        text: '5'
                    },
                ],
                onchange: function() { data.title = this.value(); }
            }
        ],
        onSubmit: function(e) {
            var shortcode = '[shortcode3';
            data = tinymce.extend(data, e.data);

            shortcode += ' title="' + data.title + '"';
            shortcode += ' limit="' + data.limit + '"';

            shortcode += ']';

            tinymce.execCommand('mceInsertContent', false, shortcode);
        }
    });
});

Going through the above code, line by line, the first thing we did was create a data object to store the default values that we’d like to use for title and limit. Next we tell the window manager to open a new window with the settings we’ve specified. Within the new window we specify a title, data, body, and onSubmit object properties. The body takes in an array of tinymce input objects. I’ve given an example of two different types, textbox and listbox, but more information about these can be found in the TinyMCE 4.x API documentation and by looking through the TinyMCE source. The onSubmit property takes a function and is called when the OK button is clicked on the dialog box. Lastly, we’re using the same command to actually insert the shortcode text, mceInsertContent.

There are other things that you can do with TinyMCE such as getting the current selected text and modifying it (similar to how you add a link in the WordPress editor) or use AJAX to pull information from WordPress to allow for dynamic user input, but those are things to be covered in a follow-up guide. At this point, you should have a fully functioning custom button in the WordPress editor that can easily be adapted to what ever project you may be working on.

As always, I hope this has been an insightful guide, but let me know if you have any questions or comments.

Update – March 30, 2016

The TinyMCE api documentation has been updated and doesn’t include as detailed of information as it previously did, so it may be useful to look through the TinyMCE source. Specifically, the UI Classes will be helpful if you’re wanting to use different TinyMCE widgets than what was used in this article.

Comments

2 responses to “WordPress Editor Custom Buttons and Dialog Windows”

  1. Gagaro Avatar

    Hi,

    The TinyMCE documentation isn’t actually very helpful. So I went ahead and wrote an article listing the different widgets and containers layout available: http://makina-corpus.com/blog/metier/2016/how-to-create-a-custom-dialog-in-tinymce-4

    Hope it will helps

  2. laubsterboy Avatar
    laubsterboy

    Thanks for sharing, Gagaro! Unfortunately, the TinyMCE documentation has been revamped since I wrote this article and it lacks a lot of useful information that it used to have.

Leave a Reply

Your email address will not be published. Required fields are marked *