// ✅ Enable a fully functional Rich Text Editor field in Gravity Forms // Works on frontend + shows formatted output (not HTML tags) //Enqueue editor scripts (TinyMCE + Media) add_action('gform_enqueue_scripts', function() { wp_enqueue_editor(); wp_enqueue_media(); }); // 1. Add “Rich Text Editor” button to Form Builder add_filter('gform_add_field_buttons', function($field_groups){ $field_groups[] = array( 'name' => 'custom_fields', 'label' => __('Custom Fields', 'gravityforms'), 'fields' => array( array( 'class' => 'button', 'value' => __('Rich Text Editor', 'gravityforms'), 'data-type' => 'editor', ), ), ); return $field_groups; }); // 2. Register field type name add_filter('gform_field_type_title', function($type){ return $type === 'editor' ? __('Rich Text Editor', 'gravityforms') : $type; }); // 3. Add standard settings (optional) add_action('gform_field_standard_settings', function($position, $form_id){ if($position == 25){ ?>
  • type !== 'editor') return $input; ob_start(); wp_editor( $value, 'input_' . $form_id . '_' . $field->id, array( 'textarea_name' => 'input_' . $field->id, 'media_buttons' => true, 'quicktags' => true, 'tinymce' => array( 'height' => 300, 'toolbar1' => 'formatselect bold italic underline | bullist numlist blockquote | alignleft aligncenter alignright link unlink | removeformat', ), ) ); $editor_html = ob_get_clean(); return sprintf( '
    %s
    ', $editor_html ); }, 10, 5); // Safe rendering — decode and render formatted HTML (not tags) if ( ! function_exists( 'gf_rich_allowed_tags' ) ) { function gf_rich_allowed_tags() { return array( 'p' => array(), 'br' => array(), 'strong' => array(), 'b' => array(), 'em' => array(), 'i' => array(), 'u' => array(), 'span' => array( 'style' => true, 'class' => true ), 'div' => array( 'style' => true, 'class' => true ), 'a' => array( 'href' => true, 'title' => true, 'target' => true, 'rel' => true ), 'h1' => array(), 'h2' => array(), 'h3' => array(), 'h4' => array(), 'h5' => array(), 'h6' => array(), 'ul' => array(), 'ol' => array(), 'li' => array(), 'blockquote' => array(), 'img' => array( 'src' => true, 'alt' => true, 'width' => true, 'height' => true ), 'strong' => array(), 'em' => array() ); } } /* ---------- Allow safe inline CSS properties ---------- */ add_filter( 'safe_style_css', function( $styles ) { $custom = array( 'text-decoration', 'color', 'background-color', 'font-size', 'font-weight', 'font-style', 'text-align', 'line-height', 'font-family', ); return array_unique( array_merge( $styles, $custom ) ); }); /* ---------- Helper to decode + sanitize editor HTML ---------- */ if ( ! function_exists( 'gf_render_editor_html_safe' ) ) { function gf_render_editor_html_safe( $raw ) { if ( $raw === null || $raw === '' ) { return ''; } // 1) Decode HTML entities (handles encoded "<" as <) $decoded = html_entity_decode( (string) $raw, ENT_QUOTES | ENT_HTML5, 'UTF-8' ); // 2) Fix possible double-encoding like &lt; if ( strpos( $decoded, '&lt;' ) !== false || strpos( $decoded, '&gt;' ) !== false ) { $decoded = str_ireplace( array( '&lt;', '&gt;' ), array( '<', '>' ), $decoded ); $decoded = html_entity_decode( $decoded, ENT_QUOTES | ENT_HTML5, 'UTF-8' ); } // 3) Sanitize with allowed tags (keeps , , etc.) return wp_kses( $decoded, gf_rich_allowed_tags() ); } } /* ---------- Merge-tag replacement: decode + render editor fields (priority 5) ---------- */ add_filter( 'gform_replace_merge_tags', function( $text, $form, $entry, $url_encode, $esc_html, $nl2br ) { if ( empty( $form ) || empty( $entry ) ) { return $text; } // decode the container text early (handles already-encoded merge outputs) $text = html_entity_decode( (string) $text, ENT_QUOTES | ENT_HTML5, 'UTF-8' ); foreach ( $form['fields'] as $field ) { if ( isset( $field->type ) && $field->type === 'editor' ) { $id = $field->id; $raw = rgar( $entry, $id ); // render the raw field value safely (allows links, styles) $rendered = gf_render_editor_html_safe( $raw ); // Replace merge tags: {ID} and {Label:ID} and {Label:ID:modifier} $text = str_replace( '{' . $id . '}', $rendered, $text ); $pattern = '/\{[^}]*:' . preg_quote( $id, '/' ) . '(?::[^}]*)?\}/'; $text = preg_replace( $pattern, $rendered, $text ); } } // Final pass: ensure we haven't left encoded common tags; decode conservative patterns if ( strpos( $text, '<' ) !== false || strpos( $text, '&lt;' ) !== false ) { $search = array( '<br />','<br>','<br/>', '<p>','</p>', '<h1>','</h1>','<h2>','</h2>','<h3>','</h3>', '<h4>','</h4>','<h5>','</h5>','<h6>','</h6>', '<strong>','</strong>','<b>','</b>', '<em>','</em>','<i>','</i>','<u>','</u>', '<span>','</span>','<div>','</div>', '<a href="','</a>', '&lt;','&gt;' ); $replace = array( '
    ','
    ','
    ', '

    ','

    ', '

    ','

    ','

    ','

    ','

    ','

    ', '

    ','

    ','
    ','
    ','
    ','
    ', '','','','', '','','','','','', '','','
    ','
    ', '
    '', 'field' => '', ), $atts, 'gf_editor' ); $entry_id = intval( $atts['entry'] ); $field_id = intval( $atts['field'] ); if ( $entry_id <= 0 || $field_id <= 0 ) return ''; $entry = GFAPI::get_entry( $entry_id ); if ( is_wp_error( $entry ) ) return ''; $raw = rgar( $entry, $field_id ); return gf_render_editor_html_safe( $raw ); } ); }