Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

load wordpress wp_editor dynamically (ajax)

This is an answer/solution rather than a question, still there maybe some bugs, even I tried on my dev env.

I recently try to use wp_editor in widget/menu, after some search, I did not find a complete solution as I want.

I would share my solution in below after I dig into wp's code by hours:

like image 406
Zac Avatar asked Dec 16 '22 01:12

Zac


2 Answers

There maybe hacking involved, however, I tried to minimize them.

To make wp_editor can work in dynamic html (which means without reload page, js changes the page structure), there are two major issues need to take care:

  1. tinymce
  2. qucik-tags

For [tinymce]:

a. need reset UI properly

  • solution is [remove mce instance] -> [get proper mce settings] -> [re-init a new mce instance]

  • in js code (id means textarea id):

    tinymce.execCommand('mceRemoveEditor', true, id);
    var init = tinymce.extend( {}, tinyMCEPreInit.mceInit[ id ] );
    try { tinymce.init( init ); } catch(e){}
    

b. need data write back to textarea before submit

  • solution is [bind click to button] -> on submt :: [turn off mce] -> [turn on submit]
  • in js code:

    jq('textarea[id="' + id + '"]').closest('form').find('input[type="submit"]').click(function(){
        if( getUserSetting( 'editor' ) == 'tmce' ){
            var id = mce.find( 'textarea' ).attr( 'id' );
            tinymce.execCommand( 'mceRemoveEditor', false, id );
            tinymce.execCommand( 'mceAddEditor', false, id );
        }
        return true;
    });
    

For [Quick Tags]:

a. Re-init tags

  • [Get settings] -> [setup mouse event] -> [re-init QTags]

b. Switch to proper tab (mce tab or quick tag tab)

  • [switch to current tab mode]

  • both above in js code:

    if ( typeof(QTags) == 'function' ) {
        jq( '[id="wp-' + id + '-wrap"]' ).unbind( 'onmousedown' );
        jq( '[id="wp-' + id + '-wrap"]' ).bind( 'onmousedown', function(){
            wpActiveEditor = id;
        });
        QTags( tinyMCEPreInit.qtInit[ id ] );
        QTags._buttonsInit();
        switchEditors.switchto( jq( 'textarea[id="' + id + '"]' ).closest( '.widget-mce' ).find( '.wp-switch-editor.switch-' + ( getUserSetting( 'editor' ) == 'html' ? 'html' : 'tmce' ) )[0] );
    }
    

Also, please remember if you use ajax, every time post back mce UI, you need re-do [reset mce UI] and [Qtags] in you js. A easy solution is using js code in you post back html, and detect in php of:

$isAjax = defined( 'DOING_AJAX' ) && DOING_AJAX == true );

About default settings in js value:

  1. mce : tinyMCEPreInit.mceInit

  2. qtags : tinyMCEPreInit.qtInit

If you try to use default setting for widget mode, you need locate default settings.

To get widget template id, in js code:

function getTemplateWidgetId( id ){
        var form = jQuery( 'textarea[id="' + id + '"]' ).closest( 'form' );
        var id_base = form.find( 'input[name="id_base"]' ).val();
        var widget_id = form.find( 'input[name="widget-id"]' ).val();
        return id.replace( widget_id, id_base + '-__i__' );
}

So you can get settings by:

  1. for mce:

    var init;
    if( typeof tinyMCEPreInit.mceInit[ id ] == 'undefined' ){
        init = tinyMCEPreInit.mceInit[ id ] = tinymce.extend( {}, tinyMCEPreInit.mceInit[ getTemplateWidgetId( id ) ] );
    }else{
        init = tinyMCEPreInit.mceInit[ id ];
    }
    
  2. For Qtags:

    var qInit;
    if( typeof tinyMCEPreInit.qtInit[ id ] == 'undefined' ){
        qInit = tinyMCEPreInit.qtInit[ id ] = jq.extend( {}, tinyMCEPreInit.qtInit[ getTemplateWidgetId( id ) ] );
        qInit['id'] = id;
    }else{
        qInit = tinyMCEPreInit.qtInit[ id ];
    }
    

For the complete code sample, please check : https://github.com/hezachary/wordpress-wysiwyg-widget/blob/master/widget_wp_editor.class.php

If anyone want use wp_editor in menu walk for admin, the principle should be the same.

If you have any question or better solut please comment, thanks.

like image 56
Zac Avatar answered Dec 28 '22 07:12

Zac


Working solution:

p.s. you'd have asked at WP.SE: https://wordpress.stackexchange.com/a/192132/33667


add action in wordpress, lets say My_Action_Name (also note, textarea ID My_TextAreaID_22 ):

add_action('wp_ajax_My_Action_Name', function(){
    wp_editor( $_POST['default_text'], 'My_TextAreaID_22',      $settings = array( 'tinymce'=>true, 'textarea_name'=>'name77', 'wpautop' =>false,   'media_buttons' => true ,   'teeny' => false, 'quicktags'=>true, )   );    exit;
});

now, in Dashboard, execute this function (note, using of My_TextAreaID_22 and My_Action_Name):

function start_Ajax_request() { 
    Alert("I have started");
    My_New_Global_Settings =  tinyMCEPreInit.mceInit.content;       // Get default Wordpress SETTINGS  ( I cant confirm, but if you will need to change target ID, then add this line:  My_New_Global_Settings.selector = "My_TextAreaID_22";   )
    jQuery.post(ajaxurl,
        { action: "My_Action_Name",     default_text: "Hello World"}, 
        function(response,status){ 
            Alert("I have Finished");
            tinymce.init(My_New_Global_Settings); 
            tinyMCE.execCommand('mceAddEditor', false, "My_TextAreaID_22"); 
            quicktags({id : "My_TextAreaID_22"});
        }
    );

}   
start_Ajax_request();     // < ---- EXECUTE
like image 22
T.Todua Avatar answered Dec 28 '22 08:12

T.Todua