Instantiate TinyMCE via JS ( rather than PHP/wp_editor )

Once a page has loaded, how do I create a TinyMCE editor?

Putting a wp_editor call in an AJAX request then displaying it gives this:

Read More

enter image description here

Visual and text tabs are nonfunctional, no toolbar, no active TinyMCE instance, just the html markup. I need to instantiate the JS component of TinyMCE, but how?

I’ve also tried making a call in my AJAX response PHP to _WP_Editors::editor_js();, and I can see the response in the console using console.log and I see the JS script there, but it is not inserted into the DOM and it is never executed

Related posts

Leave a Reply

1 comment

  1. Updated for TinyMCE 4

    I’ve made some progress

    Load a wp_editor in the initial page load in a hidden div, then do the AJAX call to grab the editor markup.

    While in PHP, you will need to retrieve the IDs of the editors created via wp_editor calls. Unfortunately, the variables on the _WP_Editors class are private, but wecan get around this by using filters. To do this we start by calling the editor_js hook inside an output buffer. It will attempt to generate the needed settings and output the required JS, although this JS will not work when sent back via AJAX and inserted.

    At the end of this call, the _WP_Editors class pases the mcesettings array through a filter, which we will use to make a copy that we can pull the editor IDs out of:

    add_action( 'after_wp_tiny_mce', array( $this, 'steal_away_mcesettings' ) );
    
    function steal_away_mcesettings( $mcesettings ) {
        $this->mcesettings = $mcesettings;
    }
    

    So after we’ve added this filter, we call out editor_js function:

    ob_start();
    _WP_Editors::editor_js();
    ob_end_clean(); 
    

    We can now use our $mcesettings copy to fill in a list of IDs:

    $ids = array();
    
    foreach ( $this->mcesettings as $editor_id => $init ) {
        $ids[] = $editor_id;
    }
    

    The ids array can now be sent back in the AJAX response along with the html.

    Once in the browser, we can insert the html into the page, and then using our editor_ids, we can instantiate the TinyMCE instances like this:

    function tinyMCE_bulk_init( editor_ids ) {
        var init, ed, qt, first_init, DOM, el, i;
    
        if ( typeof(tinymce) == 'object' ) {
    
            var editor;
            for ( e in tinyMCEPreInit.mceInit ) {
                editor = e;
                break;
            }
            for ( i in editor_ids ) {
                var ed_id = editor_ids[i];
                tinyMCEPreInit.mceInit[ed_id] = tinyMCEPreInit.mceInit[editor];
                tinyMCEPreInit.mceInit[ed_id]['elements'] = ed_id;
                tinyMCEPreInit.mceInit[ed_id]['body_class'] = ed_id;
                tinyMCEPreInit.mceInit[ed_id]['succesful'] =  false;
            }
    
            for ( ed in tinyMCEPreInit.mceInit ) {
                // check if there is an adjacent span with the class mceEditor
                if ( ! jQuery('#'+ed).next().hasClass('mceEditor') ) {
                    init = tinyMCEPreInit.mceInit[ed];
                    try {
                        tinymce.init(init);
                        tinymce.execCommand( 'mceAddEditor', true, ed_id );
                    } catch(e){
                        console.log('failed');
                        console.log( e );
                    }
                }
            }
    
        }
    }
    

    Because we don’t have the ability to generate the necessary TinyMCE settings ourselves to match the WordPress style, we instead steal them from the instance we created in the initial page load, and make copies. We then modify the copies to use the correct element IDs and proceed as usual, checking that the elements dont already have an instance.

    enter image description here

    Issues

    • The tabs for plain text vs visual content do not work
    • No quick tags on the plaintext view
    • The extra weight of the initial TinyMCE instance
    • No Media uploader button
    • Adding 2 TinyMCE instances or more in an AJAX request leads to one working instance, and the others being broken. I’m not sure why this is the case, yet 2 AJAX requests with 1 instance each, gives you 2 working instances.
    • The JS could be modified to not modify the TinyMCEPreInit structure, and pass the copy straight into the initialiser, removing a DOM traversal in the process