5

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:

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

7
  • 1
    Get it per Ajax … where you can use wp_editor()?
    – fuxia
    Commented Jul 26, 2012 at 18:25
  • wp_editor returns all the html needed but it doesn't return the JS needed to instantiate the TinyMCE instance
    – Tom J Nowell
    Commented Mar 27, 2013 at 13:57
  • 1
    Sure you got the right files included?
    – kaiser
    Commented Mar 27, 2013 at 14:04
  • yes, I can instantiate a wp_editor on the same page, and I get improvements but the problem is not solved. I create 2 editors in my first AJAX and they sort of work, one has a full working editor, the second is a bit weird and shows no buttons on the text view. Second AJAX request however gives 2 nonfuncitoning editors, plain markup, and JS errors "Uncaught TypeError: Cannot read property 'click' of undefined"
    – Tom J Nowell
    Commented Mar 27, 2013 at 14:31
  • 1
    Add one hidden "dummy" wp_editor() by PHP with tinymce arg set to true to load tinymce scripts .......... then tinymce.execCommand( 'mceAddEditor', true, 'TEXT_AREA_ID' );
    – jave.web
    Commented Apr 20, 2016 at 20:31

1 Answer 1

3

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
5
  • 1
    For a realworld example, look at the Bulk Edit plugin on wordpress.org, which is directly based on the above answer
    – Tom J Nowell
    Commented Jan 31, 2014 at 15:04
  • I am trying something same. Wondering if you got it done? Can you share your final solution? Commented Aug 6, 2014 at 6:44
  • This answer is my final solution
    – Tom J Nowell
    Commented Aug 6, 2014 at 10:58
  • I Need wp_editor in customizer with add to more button with clone . can you help me.Please share the code
    – user25225
    Commented Jun 15, 2018 at 13:45
  • @user25225 you should ask that as a new question, comments aren't the place to ask
    – Tom J Nowell
    Commented Jun 15, 2018 at 16:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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