Load tinyMCE / wp_editor() via AJAX

There are several questions about this (like this, or that), but none of them provides a solution to me.

The situation:
I have a metabox. Inside this metabox I want to dynamically add tinyMCE editors.

Read More

The code:

PHP:

add_action('wp_ajax_insert_tinymce', 'insert_tinymce');
function insert_tinymce(){
    wp_editor('','editor-id');
    exit;
}

JS:

$.post(
    global.ajaxurl,
    {
        action : 'insert_tinymce'
    },
    function(response) {

        $(response).appendTo('#target-div');

        console.log(tinyMCE); // no instance of 'editor-id'
        console.log(tinyMCEPreInit.mceInit); // 'editor-id' not listed
        console.log(tinyMCE.activeEditor); // null
    }
);

The result is a editor window (with html and visual tabs), a upload button and a textarea but completly without buttons.

What I tried (as suggested in the other questions):

// In the response function
tinyMCE.init({
    skin : "wp_theme",
    mode : "exact",
    elements : "editor-id",
    theme: "advanced"
});


// In the response function
tinyMCE.init(tinyMCEPreInit.mceInit['editor-id']);


// in the PHP
ob_start();
wp_editor( '', 'editor-id' );
echo ob_get_clean();

This first one works, but I would have to set many settings manually, plus my custom buttons don’t show up.

The second one obviously doesn’t work, because there is no editor-id listed in tinyMCEPreInit.mceInit

The third one (output buffering) makes no difference.


I have noticed that wp_editor() adds the tinyMCE instances to tinyMCEPreInit and adds it via admin_print_footer_scripts hook. So I would have to dynamically update tinyMCEPreInit (without losing the instance of the main editor) and then fire tinyMCE.init(tinyMCEPreInit.mceInit['editor-id'])MAYBE

Any help highly appreciated 😉

Thanks!

Related posts

Leave a Reply

1 comment

  1. your post here helped me figure a solution. Along with the mceInit property, I also had to retrieve the qtInit that wp_editor generates as well.

    The following is the relevant code within my class. Basically I have wp_editor run so that the javascript is generated. I use hooks to retrieve the javascript, so that I can echo it out in the ajax response.

    // ajax call to get wp_editor
    add_action( 'wp_ajax_wp_editor_box_editor_html', 'wp_editor_box::editor_html' );
    add_action( 'wp_ajax_nopriv_wp_editor_box_editor_html', 'wp_editor_box::editor_html' );
    
    // used to capture javascript settings generated by the editor
    add_filter( 'tiny_mce_before_init', 'wp_editor_box::tiny_mce_before_init', 10, 2 );
    add_filter( 'quicktags_settings', 'wp_editor_box::quicktags_settings', 10, 2 );
    
    class wp_editor_box {
    
        /*
        * AJAX Call Used to Generate the WP Editor
        */
    
        public static function editor_html() {
            $content = stripslashes( $_POST['content'] );
            wp_editor($content, $_POST['id'], array(
                'textarea_name' => $_POST['textarea_name']
            ) );
            $mce_init = self::get_mce_init($_POST['id']);
            $qt_init = self::get_qt_init($_POST['id']); ?>
            <script type="text/javascript">
                tinyMCEPreInit.mceInit = jQuery.extend( tinyMCEPreInit.mceInit, <?php echo $mce_init ?>);
                tinyMCEPreInit.qtInit = jQuery.extend( tinyMCEPreInit.qtInit, <?php echo $qt_init ?>);
            </script>
            <?php
            die();
        }
    
        /*
        * Used to retrieve the javascript settings that the editor generates
        */
    
        private static $mce_settings = null;
        private static $qt_settings = null;
    
        public static function quicktags_settings( $qtInit, $editor_id ) {
            self::$qt_settings = $qtInit;
                        return $qtInit;
        }
    
        public static function tiny_mce_before_init( $mceInit, $editor_id ) {
            self::$mce_settings = $mceInit;
                        return $mceInit;
        }
    
        /*
        * Code coppied from _WP_Editors class (modified a little)
        */
        private function get_qt_init($editor_id) {
            if ( !empty(self::$qt_settings) ) {
                $options = self::_parse_init( self::$qt_settings );
                $qtInit .= "'$editor_id':{$options},";
                $qtInit = '{' . trim($qtInit, ',') . '}';
            } else {
                $qtInit = '{}';
            }
            return $qtInit;
        }
    
        private function get_mce_init($editor_id) {
            if ( !empty(self::$mce_settings) ) {
                $options = self::_parse_init( self::$mce_settings );
                $mceInit .= "'$editor_id':{$options},";
                $mceInit = '{' . trim($mceInit, ',') . '}';
            } else {
                $mceInit = '{}';
            }
            return $mceInit;
        }
    
        private static function _parse_init($init) {
            $options = '';
    
            foreach ( $init as $k => $v ) {
                if ( is_bool($v) ) {
                    $val = $v ? 'true' : 'false';
                    $options .= $k . ':' . $val . ',';
                    continue;
                } elseif ( !empty($v) && is_string($v) && ( ('{' == $v{0} && '}' == $v{strlen($v) - 1}) || ('[' == $v{0} && ']' == $v{strlen($v) - 1}) || preg_match('/^(?function ?(/', $v) ) ) {
                    $options .= $k . ':' . $v . ',';
                    continue;
                }
                $options .= $k . ':"' . $v . '",';
            }
    
            return '{' . trim( $options, ' ,' ) . '}';
        }
    
    }
    
    
    // the ajax respnose code
    success : function(response){
        textarea.replaceWith(response);
        tinyMCE.init(tinyMCEPreInit.mceInit[data.id]);
        try { quicktags( tinyMCEPreInit.qtInit[data.id] ); } catch(e){}
    }