Quantcast
Viewing latest article 3
Browse Latest Browse All 77

Adding your own buttons in TinyMCE 4.* editor

Image may be NSFW.
Clik here to view.
Adding your own buttons in TinyMCE 4.* editor

WordPress 3.9 includes the TinyMCE editor 4.* version update. It marks big changes in the API editor - do we’ve decided to describe the process of adding your own buttons using the new API to help you on your way.

Table of contents

The code from the following examples may be also found on Github.

Declaring a new TinyMCE button

Let’s start with the basics – in order to make our buttons appear in the editor, we have to hook under the admin_head action:

add_action('admin_head', 'gavickpro_add_my_tc_button');

gavickpro_add_my_tc_button function should be as follows:

function gavickpro_add_my_tc_button() {
    global $typenow;
    // check user permissions
    if ( !current_user_can('edit_posts') && !current_user_can('edit_pages') ) {
   	return;
    }
    // verify the post type
    if( ! in_array( $typenow, array( 'post', 'page' ) ) )
        return;
	// check if WYSIWYG is enabled
	if ( get_user_option('rich_editing') == 'true') {
		add_filter("mce_external_plugins", "gavickpro_add_tinymce_plugin");
		add_filter('mce_buttons', 'gavickpro_register_my_tc_button');
	}
}

As you can see, the above function performs several important operations; it mainly checks user permissions and settings. If all conditions are met, then two filters are added: gavickpro_add_tinymce_plugin and gavickpro_register_my_tc_button.

The first of them is used to specify the path to the script with our plugin for TinyMCE:

function gavickpro_add_tinymce_plugin($plugin_array) {
   	$plugin_array['gavickpro_tc_button'] = plugins_url( '/text-button.js', __FILE__ ); // CHANGE THE BUTTON SCRIPT HERE
   	return $plugin_array;
}

The second, on the other hand, is used to add buttons in the editor – in this case we will add one button:

function gavickpro_register_my_tc_button($buttons) {
   array_push($buttons, "gavickpro_tc_button");
   return $buttons;
}

Button with text label

Now we may look at creating the code which is responsible for adding a button to the editor – we place the following code in the *.js file specified in the gavickpro_add_tinymce_plugin filter. This code adds a button, which when clicked will insert Hello World! text into the editor:

(function() {
    tinymce.PluginManager.add('gavickpro_tc_button', function( editor, url ) {
        editor.addButton( 'gavickpro_tc_button', {
            text: 'My test button',
            icon: false,
            onclick: function() {
                editor.insertContent('Hello World!');
            }
        });
    });
})();

This isn’t the most spectacular effect, but nevertheless, the first button that we’ve added to the TinyMCE editor works as expected:

Image may be NSFW.
Clik here to view.
TinyMCE 4 - text button

Button with standard icon

It’s time to change the look of our button and adjust it to match the appearance of the dashboard. For this purpose we use Dashicons - a set of icons in the form of the font used in the dashboard.

Simply change your code to:

(function() {
    tinymce.PluginManager.add('gavickpro_tc_button', function( editor, url ) {
        editor.addButton( 'gavickpro_tc_button', {
            title: 'My test button',
            icon: 'wp_code',
            onclick: function() {
                editor.insertContent('Hello World!');
            }
        });
    });
})();

Two things have changed:

  • The text property was replaced by the title property, so that the text disappears from the button and will now appear in the tooltip when you hover over it.
  • We defined the name of the icon used. Unfortunately, at least to my current understanding, without additional CSS you are limited to certain icons.

The effect in action:

Image may be NSFW.
Clik here to view.
TinyMCE 4 - button with standard icon

Button with custom icon from Dashicons

Let's assume that we are stubborn and want an icon from the Dashicons set which is not defined in the code editor - for example, the WordPress logo icon.

Fortunately, the solution is quite simple - we need to attach some additional CSS code, which has the following structure:

i.mce-i-icon {
	font: 400 20px/1 dashicons;
	padding: 0;
	vertical-align: top;
	speak: none;
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
	margin-left: -2px;
	padding-right: 2px
}

We may do it easily, like this:

function gavickpro_tc_css() {
	wp_enqueue_style('gavickpro-tc', plugins_url('/style.css', __FILE__));
}

add_action('admin_enqueue_scripts', 'gavickpro_tc_css');

The above code will allow us to use any character class of dashicons-*. For those of you who are curious - we had to specify the mce-i-icon class, because the value of the icon is automatically appended to the mce-i- prefix. Now, we should change the JavaScript code to the following:

(function() {
    tinymce.PluginManager.add('gavickpro_tc_button', function( editor, url ) {
        editor.addButton( 'gavickpro_tc_button', {
            title: 'My test button',
            icon: 'icon dashicons-wordpress-alt',
            onclick: function() {
                editor.insertContent('Hello World!');
            }
        });
    });
})();

As you can see, we added icon as the first class (in order to get the mce-i-icon class), and then we add a dashicons-wordpress-alt class.

Our button now looks as follows:

Image may be NSFW.
Clik here to view.
TinyMCE 4 - button with Dashicons

The list of classes from the Dashicons set is available on the icon list page – All you need to do is click on the chosen icon, so that the CSS class associated with this icon will appear at the top.

Button with your own graphics for the icon

It may be the case that even Dashicons do not meet our specific needs in regards to the appearance of the icon. We would thus need to create our own graphics - preferably 2-3 times larger than the size of the button (I created a graphic of size 64x64px, which looks nice on a retina display) and define it as a background button in our CSS file:

i.gavickpro-own-icon {
	background-image: url('custom-icon.png');
}

We replace the JavaScript code to the following one in order to use a new class:

(function() {
    tinymce.PluginManager.add('gavickpro_tc_button', function( editor, url ) {
        editor.addButton( 'gavickpro_tc_button', {
            title: 'My test button',
            icon: 'icon gavickpro-own-icon',
            onclick: function() {
                editor.insertContent('Hello World!');
            }
        });
    });
})();

Thanks to this code, our button now uses our desired, nonstandard icon:

Image may be NSFW.
Clik here to view.
TinyMCE 4 - button with custom icon

Adding submenu to button

Our button already looks nice; however, it is still restricted to a single functionality. Fortunately, we may easily change that – we just need to make the following changes to our code:

(function() {
    tinymce.PluginManager.add('gavickpro_tc_button', function( editor, url ) {
        editor.addButton( 'gavickpro_tc_button', {
            title: 'My test button',
            type: 'menubutton',
            icon: 'icon gavickpro-own-icon',
            menu: [
            	{
            		text: 'Menu item I',
            		value: 'Text from menu item I',
            		onclick: function() {
            			editor.insertContent(this.value());
            		}
           		}
           ]
        });
    });
})();

First of all, we changed the type of button to menubutton; thanks to this, we may use the menu property, which includes the table for a submenu item. As you can see the submenu position includes text and the value is inserted by clicking (thanks to the function defined in the onclick feature).

Our button has changed its size as well:

Image may be NSFW.
Clik here to view.
TinyMCE 4 - button with submenu

Adding sub-submenu to button

The structure defined in the menu properties may be nested; just specify the menu property in the correct position:

(function() {
    tinymce.PluginManager.add('gavickpro_tc_button', function( editor, url ) {
        editor.addButton( 'gavickpro_tc_button', {
            title: 'My test button',
            type: 'menubutton',
            icon: 'icon gavickpro-own-icon',
            menu: [
                {
                    text: 'Menu item I',
                    value: 'Text from menu item I',
                    onclick: function() {
                        editor.insertContent(this.value());
                    }
                },
                {
                    text: 'Menu item II',
                    value: 'Text from menu item II',
                    onclick: function() {
                        editor.insertContent(this.value());
                    },
                    menu: [
                        {
                            text: 'First submenu item',
                            value: 'Text from sub sub menu',
                            onclick: function(e) {
                                e.stopPropagation();
                                editor.insertContent(this.value());
                            }       
                        },
                        {
                            text: 'Second submenu item',
                            value: 'Text from sub sub menu',
                            onclick: function(e) {
                                e.stopPropagation();
                                editor.insertContent(this.value());
                            }       
                        }
                    ]
                },
                {
                    text: 'Menu item III',
                    value: 'Text from menu item III',
                    onclick: function() {
                        editor.insertContent(this.value());
                    }
                }
           ]
        });
    });
})();

Our button already has quite an enhanced menu:

Image may be NSFW.
Clik here to view.
TinyMCE 4 - button with sub-submenu

Unfortunately, we quickly noticed a small problem – if we click on, for example, “First submenu item”, then in our editor we will see:

Image may be NSFW.
Clik here to view.
TinyMCE 4 - event propagation problem

In short – clicking the sub-submenu item brings up the onclick action also used in the parent menu item. Fortunately, you can easily eliminate this issue - just use the stopPropagation method, which means that the event is not passed up the DOM tree:

onclick: function(e) {
    e.stopPropagation();
    editor.insertContent(this.value());
}

After this change, our sub-submenu items should correctly react when clicked.

Adding popup after clicking

So far, we have been limiting ourselves to inserting specific text values to the editor, but this will not always be a sufficient solution. Let's do something that will enable the user to identify some of the added text - let's use the popup that appears when you click on the button:

onclick: function() {
    editor.windowManager.open( {
        title: 'Insert h3 tag',
        body: [{
            type: 'textbox',
            name: 'title',
            label: 'Your title'
        }],
        onsubmit: function( e ) {
            editor.insertContent( '<h3>' + e.data.title + '</h3>');
        }
    });
}

The above code will cause a popup to display with an instruction to insert the content of the h3 index:

Image may be NSFW.
Clik here to view.
TinyMCE 4 - button with popup

As we can see the onsubmit property results in text being added to the editor after changes made by the user are accepted.

Popup enhancing

We may certainly create more enhanced popups:

Image may be NSFW.
Clik here to view.
TinyMCE 4 - button with complex popup

The above popup uses two fields of the textbox type and one of the listbox type:

onclick: function() {
    editor.windowManager.open( {
        title: 'Insert header tag',
        body: [{
            type: 'textbox',
            name: 'title',
            label: 'Your title'
        },
        {
            type: 'textbox',
            name: 'id',
            label: 'Header anchor'
        },
        {
            type: 'listbox', 
            name: 'level', 
            label: 'Header level', 
            'values': [
                {text: '<h3>', value: '3'},
                {text: '<h4>', value: '4'},
                {text: '<h5>', value: '5'},
                {text: '<h6>', value: '6'}
            ]
        }],
        onsubmit: function( e ) {
            editor.insertContent( '<h' + e.data.level + ' id="' + e.data.id + '">' + e.data.title + '</h' + e.data.level + '>');
        }
    });
}

The code from the following examples may be also found on Github.


Viewing latest article 3
Browse Latest Browse All 77

Trending Articles