How to Create a Custom Rich Text Editor in Gravity Forms for Better Formatting and User Experience

December 1, 2025 - TechnoCrackers
Blog Icon
How to Create a Custom Rich Text Editor in Gravity Forms for Better Formatting and User Experience

Gravity Forms is one of the most powerful form builders available for WordPress — but it has one limitation:

It does not offer a built-in Rich Text Editor (WYSIWYG) field.

For websites that rely on user-generated content—such as blogs, directories, reviews, job listings, or frontend post submissions—a basic textarea simply isn’t enough.

A proper Rich Text Editor allows users to format text with:

  • Headings (H1–H6)
  • Links & Media
  • Bold, Italic, Underline
  • Bullet and Numbered Lists
  • Images
  • Blockquotes
  • Inline styles like alignment, colors, and spacing

So in this tutorial, you’ll learn how to add a fully functional Rich Text Editor field inside Gravity Forms using custom code — without installing an extra plugin.

What This Solution Supports

  • Works on frontend
  • Uses TinyMCE (WordPress default editor)
  • Supports media uploads
  • Outputs clean formatted HTML
  • Works with Gravity Forms Post Creation Add-On
  • Prevents raw HTML from showing in visual mode

Why You Need a Custom Rich Text Editor in Gravity Forms

A normal textarea field cannot store or render formatted content like:

  • Titles and headings
  • Styled paragraphs
  • Embedded media or images
  • Links and structured lists

If you’re building forms like:

  • Blog submission form
  • Directory or listing submission
  • User reviews
  • Job listing submission
  • Knowledgebase article submission
  • Community-generated content

…then users need a proper editor — not a plain text field.

Step-by-Step Guide

Step 1 — Add This Code to Your functions.php

Copy and paste the following entire code block into your theme’s functions.php or a custom plugin:

( Code already formatted, so no changes needed — paste exactly as provided.)

// 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){ ?>
        <li class="field_setting">
            <label for="field_placeholder">
                <?php esc_html_e("Placeholder", "gravityforms"); ?>
                <?php gform_tooltip("form_field_placeholder"); ?>
            </label>
            <input type="text" id="field_placeholder" class="fieldwidth-3" size="35"
                onkeyup="SetFieldProperty('placeholder', this.value);" />
        </li>
    <?php }
}, 10, 2);

// 4. Editor JS for Gravity Form Builder
add_action('gform_editor_js', function(){ ?>
<script type='text/javascript'>
    fieldSettings.editor = '.label_setting, .description_setting, .css_class_setting, .placeholder_setting, .visibility_setting, .required_setting';
</script>
<?php });

// 5. Render the TinyMCE editor on frontend

add_filter('gform_field_input', function($input, $field, $value, $lead_id, $form_id){
    if($field->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(
        '<div class="ginput_container ginput_container_editor">%s</div>',
        $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 &lt;)
        $decoded = html_entity_decode( (string) $raw, ENT_QUOTES | ENT_HTML5, 'UTF-8' );

        // 2) Fix possible double-encoding like &amp;lt;
        if ( strpos( $decoded, '&amp;lt;' ) !== false || strpos( $decoded, '&amp;gt;' ) !== false ) {
            $decoded = str_ireplace( array( '&amp;lt;', '&amp;gt;' ), array( '<', '>' ), $decoded );
            $decoded = html_entity_decode( $decoded, ENT_QUOTES | ENT_HTML5, 'UTF-8' );
        }

        // 3) Sanitize with allowed tags (keeps <a href>, <span style>, 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, '&lt;' ) !== false || strpos( $text, '&amp;lt;' ) !== false ) {
        $search = array(
            '&lt;br /&gt;','&lt;br&gt;','&lt;br/&gt;',
            '&lt;p&gt;','&lt;/p&gt;',
            '&lt;h1&gt;','&lt;/h1&gt;','&lt;h2&gt;','&lt;/h2&gt;','&lt;h3&gt;','&lt;/h3&gt;',
            '&lt;h4&gt;','&lt;/h4&gt;','&lt;h5&gt;','&lt;/h5&gt;','&lt;h6&gt;','&lt;/h6&gt;',
            '&lt;strong&gt;','&lt;/strong&gt;','&lt;b&gt;','&lt;/b&gt;',
            '&lt;em&gt;','&lt;/em&gt;','&lt;i&gt;','&lt;/i&gt;','&lt;u&gt;','&lt;/u&gt;',
            '&lt;span&gt;','&lt;/span&gt;','&lt;div&gt;','&lt;/div&gt;',
            '&lt;a href=&quot;','&lt;/a&gt;',
            '&amp;lt;','&amp;gt;'
        );
        $replace = 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>',
            '<', '>'
        );

        $text = str_ireplace( $search, $replace, $text );
    }

    // Finally sanitize entire result again with allowed tags (keeps a href + span style)
    $text = wp_kses( $text, gf_rich_allowed_tags() );

    return $text;
}, 5, 6 );


/**
 * 3) Ensure gform_get_input_value returns safe rendered HTML for editor fields.
 *    Many templates/plugins call this directly to get the field value.
 */
add_filter( 'gform_get_input_value', function( $value, $entry, $field, $input_id ) {
    if ( is_object( $field ) && isset( $field->type ) && $field->type === 'editor' ) {
        return gf_render_editor_html_safe( $value );
    }
    return $value;
}, 10, 4 );

/**
 * 4) Admin Entry Detail try to force rendered HTML on entry detail page
 */
add_filter( 'gform_entry_field_value', function( $value, $field, $entry ) {
    if ( is_object( $field ) && isset( $field->type ) && $field->type === 'editor' ) {
        return gf_render_editor_html_safe( $value );
    }
    return $value;
}, 10, 3 );

/**
 * 5) Shortcode: [gf_editor entry="123" field="2"]
 *    Use this in templates/content to safely print the rendered editor field.
 */
if ( ! shortcode_exists( 'gf_editor' ) ) {
    add_shortcode( 'gf_editor', function( $atts ) {
        $atts = shortcode_atts( array(
            'entry' => '',
            '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 );
    } );
}

Once added, Gravity Forms will display a new field called:  Rich Text Editor under the “Custom Fields” tab.

 

Step 2 — Create a New Gravity Form

  1. Go to Forms → New Form
  2. Give it a name (Example: Blog Submission Form)
  3. Add standard fields like:
    • Name
    • Email
    • Post Title
  4. Add your new field: Rich Text Editor
  5. Save the form

Tip: Note the Field ID for later (Example: Field ID: 10).

Step 3 — Configure Gravity Forms Post Creation Add-On

  1. Go to Form → Settings → Post Creation
  2. Create a new feed
  3. Settings example:
Setting Example
Post Type Post (or Custom Post Type)
Status Draft (recommended for testing)
Author Logged-in User
Title {Post Title:1}
Content {Description:10} ← must match Rich Editor Field ID

(Optional) Map:

  • Categories
  • Tags
  • Featured Image
  • Custom fields

Important: Ensure the content field uses the field ID of the Rich Text Editor.

Step 4 — Add the Form to a Page

Use this shortcode anywhere:
[ gravityform id="123" title="true" description="false" ajax="true" ]

Replace 123 with your form ID.

Publish your page (example: Submit a Blog).

Step 5 — Test the Submission

  1. Open the form on the frontend
  2. Format content using the editor (bold, headings, images, lists, etc.)
  3. Submit the form
  4. Check:

Posts → All Posts

You should see a new post created — with formatting preserved.

  1. In WP Admin go to Posts → All Posts and find the new post (status based on your feed setting).
  2. Click Edit on the post and check the Visual tab in the editor — the content should render as formatted HTML (not raw HTML tags).
  3. View the post on the frontend and confirm headings, lists, images and styling display correctly.

Final Result

You now have a fully working frontend content editor inside Gravity Forms — without additional plugins.

  • Works with WordPress media uploader
  • Supports formatting, links, images, headings
  • Perfect for guest posting, user-generated content, and custom submission workflows

Conclusion

Adding a rich text editor to Gravity Forms dramatically improves the user experience for forms involving long-form content.

Whether you’re building a submission portal, directory, review system, or frontend publishing workflow — this upgrade makes Gravity Forms behave more like a real blogging platform.

If your project requires custom Gravity Forms functionality, enhanced user experience, or plugin-free custom editors, our team can handle the complete development—from planning and implementation to testing and launch.

You can Book a Free Project Consultation to discuss your requirements, timelines, and how we can deliver a scalable, high-quality solution for your website.

Subscribe
Notify of
guest
0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments

Contact us

Let's Unleash Your Digital Potential Together.

Address

C-605, Ganesh glory 11, Nr. BSNL Office, Jagatpur Road, S.G. Highway, Jagatpur, Ahmedabad, India - 382481.

Phone

INDIA : (091) 8200639242 USA : +1 (310) 868-6009

Limited Time Offer

X

Try a Free 2-Hour Test Task

Experience our quality, speed, and communication on any small WordPress task before you commit. No contract. No cost. No obligation.
[For New Agency Partners]

"*" indicates required fields

Name*
0
Would love your thoughts, please comment.x
()
x