The wp_editor() function renders a full WordPress TinyMCE rich-text editor at any point in a PHP template — admin pages, custom meta boxes, plugin settings screens, or even front-end forms. It initialises TinyMCE with WordPress’s default configuration (media buttons, kitchen-sink toolbar, autosave) and handles all the necessary JavaScript loading automatically. This is the correct tool when you need a content editor outside of the standard post editing screen: a plugin options page where admins write formatted HTML email templates, a meta box for a custom “sidebar content” field on a page, or a front-end form where logged-in users submit rich-text content. The function accepts an extensive configuration array to control toolbar buttons, media upload capability, textarea dimensions, and TinyMCE plugins.
Problem: Your plugin settings page needs a WYSIWYG editor for a custom email template — administrators should be able to format text, add links, and see a live preview without writing HTML manually.
Solution: Call wp_editor() inside the settings form, configure the toolbar and media options via the $settings array, and save the output with wp_kses_post() for security.
<?php
// ── Basic wp_editor() usage ────────────────────────────────────────────
function render_email_template_setting() {
$content = get_option( 'my_plugin_email_template', '' );
wp_editor(
$content, // initial content (string)
'my_email_template', // unique ID — used for the textarea id and JS init
[
'textarea_name' => 'my_plugin_email_template', // form field name for $_POST
'textarea_rows' => 15,
'media_buttons' => false, // hide "Add Media" button
'tinymce' => [
'toolbar1' => 'bold,italic,underline,separator,link,unlink,separator,undo,redo',
'toolbar2' => '', // hide second toolbar row
],
'quicktags' => true, // show HTML tab
'editor_class' => 'my-editor-css-class',
]
);
}
// ── In a meta box ────────────────────────────────────────────────────────
function render_sidebar_content_meta_box( WP_Post $post ) {
wp_nonce_field( 'sidebar_content_nonce', 'sidebar_content_nonce' );
$value = get_post_meta( $post->ID, '_sidebar_content', true );
wp_editor( $value, 'sidebar_content_editor', [
'textarea_name' => 'sidebar_content',
'textarea_rows' => 10,
'teeny' => true, // minimal toolbar
] );
}
// ── Save the value ────────────────────────────────────────────────────────
add_action( 'save_post', 'save_sidebar_content' );
function save_sidebar_content( $post_id ) {
if ( ! isset( $_POST['sidebar_content_nonce'] )
|| ! wp_verify_nonce( $_POST['sidebar_content_nonce'], 'sidebar_content_nonce' )
|| defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE
|| ! current_user_can( 'edit_post', $post_id ) ) {
return;
}
update_post_meta(
$post_id,
'_sidebar_content',
wp_kses_post( $_POST['sidebar_content'] ?? '' )
);
}
NOTE: wp_editor() must be called before wp_footer() fires — the function outputs both the HTML markup and a JavaScript initialisation call. If you call it inside an AJAX response or after the footer has already been sent, TinyMCE will not initialise. For dynamically inserted editors (e.g. in a JavaScript-triggered modal), you need to manually call tinymce.init() or use wp.oldEditor.initialize() after the DOM element is inserted. Also, each editor on the same page must have a unique ID string — duplicate IDs cause only the first editor to initialise.