I spent a lot of time looking for how to modify the buttons of a TinyMCE editor for a Visual Composer plugin that I'm developing. My requirement was to modify which buttons are shown, but only in the Visual Composer TinyMCE instance, and only in the editor that corresponds to my shortcode, so as not to interfere with any other plugins.

I decided to share the solution here because it's somewhat non-obvious.


There are a number of problems:

  1. The tiny_mce_before_init filter does not affect the TinyMCE editor that VC instantiates for parameters with name == 'content' and type == 'content_html'. VC gets the TinyMCE HTML markup in a separate AJAX request. The editor's instantiation does not benefit from the tinyMCEPreInit inline JavaScript array that the filter affects. The solution is to introduce a TinyMCE plugin that modifies the editor's settings on the client side.
  2. Any TinyMCE plugin must be loaded after the editor itself (see here). Even though according to the wp_enqueue_script() documentation you would expect to be able to enqueue your plugin by setting a dependency to the built-in tiny_mce script, this does not work because TinyMCE is loaded differently. See here for a discussion of the problem and a solution.

I first bind to tiny_mce_before_init, but not to modify the buttons. I only add a plugin which all editors will run.

add_filter( 'tiny_mce_before_init', array( &$this, 'filter_tiny_mce_before_init' ) );

    public function filter_tiny_mce_before_init( $mceInit ) {
        $mceInit['plugins'] .= ',myplugin';
        return $mceInit;

Then I created the following short TinyMCE plugin. It first checks to see if the current TinyMCE editor is a Visual Composer editor, and then uses jQuery to determine if the shortcode to which it corresponds starts with my plugin's name.

'use strict';
            .add( 'myplugin',
                function(editor, url) {

                    // skip editors that don't belong to VC
                    if ( editor.id != 'wpb_tinymce_content' )

                    // skip editors that don't belong to my shortcode
                    if ( !jQuery( '#wpb_tinymce_content' ).parents(
                        '[data-vc-shortcode^="myplugin"]' ).length )

                    // these are the only buttons I want
                    editor.settings.toolbar1 = 'bold,italic,underline,strikethrough,link,unlink,spellchecker,wp_fullscreen';
                    editor.settings.toolbar2 = 'pastetext,removeformat,charmap,undo,redo,wp_help';

                } );

Finally I make sure this plugin is loaded after TinyMCE. It is ugly but again see here for why this is done.

add_action( 'after_wp_tiny_mce', array( &$this, 'action_after_wp_tiny_mce' ) );

public function action_after_wp_tiny_mce() {
        '<script type="text/javascript" src="%s"></script>', 
        plugins_url( 'assets/scripts/myplugin-tinymce.js', __FILE__ ) );

It works :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.