Add WYSIWYG (TinyMCE) field type to Elementor forms

Despite all the power and rich options available with the standard Elementor Pro form fields, sometimes a TinyMCE WYSIWYG editor field is exactly the right tool for the job. Here’s how you can add that as a field type so users can input rich text into an Elementor form. Although there is a lot of code involved, it’s all copy-n-paste…you don’t have to understand the whole thing. That said, you should be comfortable making edits to either a custom plugin or theme functions.php file. Here goes!

A little history…in November 2018 I needed a WYSIWYG field for a social media feature I was adding to a site. I was too much of a tightwad to buy an add-on, so I asked the folks at the Elementor Github site to add this as a feature request in issue #6139. They declined, but at least provided the code I could use to do it myself.

It all starts with this big blob of code. Put it into a file that you can include from either a plugin or theme. To save you the trouble of an awkward copy-n-paste, you can download mine: class_Elementor_Form_Field_Type_Wysiwyg.php. Note that for security reasons, I had to change the .php filename extension to .txt.

<?php

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly
}

class Wysiwyg extends ElementorPro\Modules\Forms\Fields\Field_Base {

	public $depended_scripts = [
		'tinymce-cdn',
	];

	public function get_type() {
		return 'wysiwyg';
	}

	public function get_name() {
		return __( 'Wysiwyg', 'elementor-pro' );
	}

	/**
	 * @param      $item
	 * @param      $item_index
	 * @param Form $form
	 */
	public function render( $item, $item_index, $form ) {

		$form->add_render_attribute( 'textarea' . $item_index, 'class', 'elementor-tinymce' );

		echo '<textarea ' . $form->get_render_attribute_string( 'input' . $item_index ) . '></textarea>';
	}

	public function register_field_type( $fields ) {
		ElementorPro\Plugin::instance()->modules_manager->get_modules( 'forms' )->add_form_field_type( self::get_type(), $this );
		$fields[ self::get_type() ] = self::get_name();
		return $fields;
	}

	public function front_end_inline_JS() {
		?>
		<script>
			var ElementorFormWysiwyg = ElementorFormWysiwyg || {};
			jQuery( document ).ready( function( $ ) {
				ElementorFormWysiwyg = {
					onReady: function( callback ) {
						if ( window.tinymce ) {
							callback();
						} else {
							// If not ready check again by timeout..
							setTimeout( function() {
								ElementorFormWysiwyg.onReady( callback );
							}, 350 );
						}
					},
					init: function() {
						self = this;
						this.onReady( function() {
							tinymce.init({
								selector: 'textarea[type="wysiwyg"]',
								setup: function (editor) {
									editor.on('change', function () {
										editor.save();
									});
								},
								menubar: true,
								// plugins: 'preview searchreplace autolink directionality visualblocks visualchars image link media template codesample table charmap hr pagebreak nonbreaking anchor toc insertdatetime advlist lists textcolor wordcount imagetools contextmenu colorpicker textpattern help',
                                plugins: 'autolink charmap colorpicker contextmenu help hr image imagetools link lists media nonbreaking searchreplace table textcolor wordcount',
								toolbar: 'formatselect | bold italic strikethrough forecolor backcolor | link | alignleft aligncenter alignright alignjustify | numlist bullist outdent indent | removeformat | image table media'
							});
						} );
					}
				};
				ElementorFormWysiwyg.init();
			} );
		</script>
		<?php
	}

	public function editor_inline_JS() {
		add_action( 'wp_footer', function() {
		?>
		<script>
			var ElementorFormWysiwygField = ElementorFormWysiwygField || {};
			jQuery( document ).ready( function( $ ) {
				ElementorFormWysiwygField = {
					onReady: function( callback ) {
						if ( window.tinymce ) {
							callback();
						} else {
							// If not ready check again by timeout..
							setTimeout( function() {
								ElementorFormWysiwygField.onReady( callback );
							}, 350 );
						}
					},
					renderField: function( inputField, item, i, settings ) {
						var itemClasses = item.css_classes,
							required = '',
							fieldName = 'form_field_';

						if ( item.required ) {
							required = 'required';
						}
						return '<textarea type="wysiwyg" class="elementor-wysiwyg elementor-field ' + itemClasses + '" name="' + fieldName + '" id="form_field_' + i + '" ' + required + '></textarea>';
					},
					initTinyMce: function() {
						tinymce.remove();
						tinymce.init({
							selector: 'textarea[type="wysiwyg"]',
							setup: function (editor) {
								editor.on('change', function () {
									editor.save();
								});
							},
							menubar: false,
							plugins: 'preview searchreplace autolink directionality visualblocks visualchars image link media template codesample table charmap hr pagebreak nonbreaking anchor toc insertdatetime advlist lists textcolor wordcount imagetools contextmenu colorpicker textpattern help',
							toolbar: 'formatselect | bold italic strikethrough forecolor backcolor | link | alignleft aligncenter alignright alignjustify  | numlist bullist outdent indent  | removeformat | image table media'
						});
					},
					init: function() {
						self = this;
						this.onReady( function() {
							elementorFrontend.hooks.addAction( 'frontend/element_ready/form.default', ElementorFormWysiwygField.initTinyMce );
							elementor.hooks.addFilter( 'elementor_pro/forms/content_template/field/wysiwyg', ElementorFormWysiwygField.renderField, 10, 4 );
						} );
					}
				};
				ElementorFormWysiwygField.init();
			} );
		</script>
		<?php
		} );
	}

	public function sanitize_field( $value, $field ) {
		return wp_kses_post( $field['raw_value'] );
	}

	public function __construct() {
		parent::__construct();
		add_filter( 'elementor_pro/forms/field_types', [ $this, 'register_field_type' ] );
		add_action( 'wp_footer', [ $this, 'front_end_inline_JS' ] );
		add_action( 'elementor/preview/init', [ $this, 'editor_inline_JS' ] );
		wp_register_script( 'tinymce-cdn', 'https://cdnjs.cloudflare.com/ajax/libs/tinymce/4.8.5/tinymce.min.js' );
	}
}

?>

Once that file is tucked away, you need to pull it from your plugin or theme like this:

add_action( 'elementor_pro/init', function() {
    require_once( __DIR__ . '/inc/class_Elementor_Form_Field_Type_Wysiwyg.php' );
    new Wysiwyg();
} );

Now, when you edit a form, you should see the Wysiwyg field type at the bottom of the field type dropdown, like so:

Add WYSIWYG (TinyMCE) field type to Elementor forms | Elementor forms, php, wysiwyg-field-type

Hope you enjoy this new feature. If there’s enough demand, maybe I’ll set it up as a standalone plugin.

2 Responses

  1. Hey Scott

    Thanks for sharing!

    I tried creating a plugin called elementor-rich-text with an inc folder where I dropped the code you gracious provided and then used a code snippet for the add_action bit. Obviously I’m missing a step here but I don’t know enough here to see what it is! Any suggestions you might have would be greatly appreciated.

  2. I still can’t believe Elementor doesn’t include this, especially when the actual work has been done and the feature is just sitting there waiting to be included… Anyway…

    So there’s really two chunks of code there. The first is the big chunk that defines the class, the second chunk uses an Elementor hook to include the first chunk and create an object of that class type.

    All you need to do is create a tiny plugin. In the plugin directory, make a subdirectory called /inc, and download file class_Elementor_Form_Field_Type_Wysiwyg.php into it (don’t forget to change the file extension from .txt to .php). Then back in the plugin directory, edit your main plugin file and paste in the second chunk, all four lines of it. Install, activate, and you should be good to go.

Leave a Reply

Your email address will not be published. Required fields are marked *