Using the WordPress WYSIWYG editor within custom Widgets
Sometimes you want to create a custom widget for your WordPress theme or plugin. And sometimes, you might want to include the tiny WYSIWYG editor like the one that is within the Text widget WordPress offers out of the box.
Now, you might think this is easy to do. But it turns out, it's not. The interwebs is full of threads and articles of using the editor within widgets, with all kinds of trickery and workarounds.
One might think, why not just use the wp_editor
function. And this will indeed work fine for things like settings pages. But for widgets, you'd be running into issues mostly because widgets are handled through AJAX-requests. And all workarounds you'll find online don't seem to be working anymore.
Going the JavaScript route
Now instead of using the wp_editor
function, I tried getting it to work with the wp.editor
JavaScript object. And I seem to have a working solution now. Maybe not perfect, but at least it works.
First, to be able to use this function, we need to include the necessary editor scripts. Also, to be able to add our own JavaScript, will add a file wp-editor-widgets.js
(but you can call it differently if you want of course).
function custom_widgets_widget_editor_script() { global $pagenow; if ( 'widgets.php' === $pagenow || 'customize.php' === $pagenow ) { wp_enqueue_editor(); wp_enqueue_script( 'wp-editor-widgets', get_stylesheet_directory_uri() . '/js/wp-editor-widgets.js', array( 'jquery' ), false, false ); } } add_action( 'admin_enqueue_scripts', 'custom_widgets_widget_editor_script' );
Initializing multiple wp.editor instances
In our custom widget, we'll just add a textarea. To identify the editors in our script, we'll add a CSS-class to the textarea called custom-widget-wp-editor
.
So within your widget a textarea that needs to become an editor, can look something like this:
<textarea id="<?php echo $this->get_field_id( 'example' ); ?>" name="<?php echo $this->get_field_name( 'example' ); ?>" class="custom-widget-wp-editor"><?php echo $instance['example'] ?? null; ?></textarea>
Let's get started with the script. Be sure to wrap your script within document ready function.
jQuery(document).ready(function ($) { // Our script. });
In our script, we'll make a function to collect all textarea's that we need to convert to editors.
function custom_widgets_get_editors() { let editors = []; $(document).find("#customize-theme-controls .custom-widget-wp-editor, #widgets-right .custom-widget-wp-editor").each(function () { editors.push($(this).attr('id')); }); return editors; }
We target the widget areas both in the Customizer view and the regular widgets view.
Next, we'll initialize our editors.
function custom_widgets_init_editors() { custom_widgets_get_editors().forEach(function (id) { wp.editor.initialize($('#' + id).attr('id'), { tinymce: { wpautop: true }, quicktags: true, mediaButtons: true }); }); } // Init the function. custom_widgets_init_editors();
Now this will already display our editors, but it will result in the values not being submitted. We can solve this by triggering a click
on the HTML-tab. Let's add it to our custom_widgets_init_editors
function.
function custom_widgets_init_editors() { custom_widgets_get_editors().forEach(function (id) { wp.editor.initialize($('#' + id).attr('id'), { tinymce: { wpautop: true }, quicktags: true, mediaButtons: true }); }); // To prevent the editor from not submitting the value, we click the switch html tab. $(document).contents().find('.widget-control-save').off().on('click', function (e) { custom_widgets_get_editors().forEach(function (editor) { let form = $('#' + editor).closest('form'); form.find('.switch-html').click(); }); });
Now if we add or update our widget, we'll have to re-initialize our editors. Otherwise, since widgets are handled through AJAX-requests, our editors will break. But before we can re-initialize them, we'll need to remove the current instances.
function custom_widgets_remove_editors() { custom_widgets_get_editors().forEach(function (id) { wp.editor.remove(id); }); }
Finally, we listen to the widget events and trigger the necessary functions.
$(document).on('widget-updated widget-added', function () { custom_widgets_remove_editors(); custom_widgets_init_editors(); });
Just want a gist? Here it is.