Changes to Textarea and User Biography Sanitization (v2.11.2+)

As of Ultimate Member version 2.11.2, we have updated the sanitization process for the native WordPress Biography (user_description) field and Custom Textarea fields.

These changes were implemented to enhance site security by ensuring only safe, validated HTML is stored in your database, preventing potential vulnerabilities like Cross-Site Scripting (XSS).


Sanitization Logic: Version Comparison

The following table outlines how field data is handled depending on your version and whether HTML is enabled in the field settings.

Field Type Version < 2.11.2 (HTML Disabled) Version < 2.11.2 (HTML Enabled) Version ≥ 2.11.2 (HTML Disabled) Version ≥ 2.11.2 (HTML Enabled)
Biography (user_description) sanitize_textarea_field() wp_kses() with UM()->get_allowed_html( 'templates' ) + iframe tag sanitize_textarea_field() wp_kses() with 'user_description' allowed tags
Custom Textarea fields sanitize_textarea_field() wp_kses() with UM()->get_allowed_html( 'templates' ) + iframe tag sanitize_textarea_field() wp_kses() with UM()->get_allowed_html( 'templates' ) allowed tags

Technical Details: Allowed HTML Tags

1. Biography Field (user_description)

As of v2.11.2, this field uses the strict WordPress Native list. This focuses on basic text formatting. Layout tags like <div> and media tags like <iframe> are no longer allowed by default.

Understanding Tag Attributes

In the list below, keys like href, title, and rel are tag attributes. Only these specific properties are permitted; any other attributes (like class, id, or style) will be automatically stripped from the Biography field.

Allowed Tags & Attributes:

  • <a>: Available only with href, title, rel, target.
  • <abbr>, <acronym>: Available only with title.
  • <blockquote>, <q>: Available only with cite.
  • <del>: Available only with datetime.
  • Formatting only (No attributes): <b>, <cite>, <code>, <em>, <i>, <s>, <strike>, <strong>.

$allowedtags = array(
    'a'          => array(
       'href'   => true,
       'title'  => true,
       'rel'    => true,
       'target' => true,
    ),
    'abbr'       => array(
       'title' => true,
    ),
    'acronym'    => array(
       'title' => true,
    ),
    'b'          => array(),
    'blockquote' => array(
       'cite' => true,
    ),
    'cite'       => array(),
    'code'       => array(),
    'del'        => array(
       'datetime' => true,
    ),
    'em'         => array(),
    'i'          => array(),
    'q'          => array(
       'cite' => true,
    ),
    's'          => array(),
    'strike'     => array(),
    'strong'     => array(),
);<br>
	

2. Custom Textarea Fields (UM Template Tags)

Custom textarea fields use the Ultimate Member "Template" allowed list. This list is broader but, by default, excludes iframes as of v2.11.2.

$allowed_html = array(
    'style'      => array(),
    'link'       => array(
       'rel'   => true,
       'href'  => true,
       'media' => true,
    ),
    'svg'        => array(
       'xmlns'               => true,
       'height'              => true,
       'preserveaspectratio' => true,
       'viewbox'             => true,
       'width'               => true,
       'x'                   => true,
       'y'                   => true,
       'fill'                => true,
       'stroke'              => true,
       'stroke-linecap'      => true,
       'stroke-linejoin'     => true,
       'stroke-width'        => true,
    ),
    'path'       => array(
       'd'               => true,
       'stroke'          => true,
       'stroke-width'    => true,
       'stroke-linecap'  => true,
       'stroke-linejoin' => true,
       'fill'            => true,
    ),
    'form'       => array(
       'action'         => true,
       'accept'         => true,
       'accept-charset' => true,
       'enctype'        => true,
       'method'         => true,
       'name'           => true,
       'target'         => true,
       'novalidate'     => true,
    ),
    'label'      => array(
       'for' => true,
    ),
    'select'     => array(
       'name'         => true,
       'multiple'     => true,
       'disabled'     => true,
       'readonly'     => true,
       'required'     => true,
       'autocomplete' => true,
    ),
    'option'     => array(
       'value'    => true,
       'selected' => true,
       'disabled' => true,
    ),
    'input'      => array(
       'type'         => true,
       'name'         => true,
       'value'        => true,
       'placeholder'  => true,
       'readonly'     => true,
       'disabled'     => true,
       'checked'      => true,
       'selected'     => true,
       'required'     => true,
       'autocomplete' => true,
       'size'         => true,
       'step'         => true,
       'min'          => true,
       'max'          => true,
       'minlength'    => true,
       'maxlength'    => true,
       'pattern'      => true,
    ),
    'textarea'   => array(
       'cols'         => true,
       'rows'         => true,
       'disabled'     => true,
       'name'         => true,
       'readonly'     => true,
       'required'     => true,
       'autocomplete' => true,
       'placeholder'  => true,
    ),
    'button'     => array(
       'type'         => true,
       'name'         => true,
       'value'        => true,
       'placeholder'  => true,
       'readonly'     => true,
       'disabled'     => true,
       'checked'      => true,
       'selected'     => true,
       'required'     => true,
       'autocomplete' => true,
    ),
    'img'        => array(
       'alt'      => true,
       'align'    => true,
       'border'   => true,
       'height'   => true,
       'hspace'   => true,
       'loading'  => true,
       'longdesc' => true,
       'vspace'   => true,
       'src'      => true,
       'srcset'   => true,
       'usemap'   => true,
       'width'    => true,
    ),
    'h1'         => array(
       'align' => true,
    ),
    'h2'         => array(
       'align' => true,
    ),
    'h3'         => array(
       'align' => true,
    ),
    'h4'         => array(
       'align' => true,
    ),
    'h5'         => array(
       'align' => true,
    ),
    'h6'         => array(
       'align' => true,
    ),
    'p'          => array(
       'align' => true,
       'dir'   => true,
       'lang'  => true,
    ),
    'ol'         => array(),
    'ul'         => array(),
    'li'         => array(),
    'time'       => array(
       'datetime' => true,
    ),
    'section'    => array(),
    'table'      => array(
       'align'       => true,
       'bgcolor'     => true,
       'border'      => true,
       'cellpadding' => true,
       'cellspacing' => true,
       'dir'         => true,
       'rules'       => true,
       'summary'     => true,
       'width'       => true,
    ),
    'tbody'      => array(
       'align'   => true,
       'char'    => true,
       'charoff' => true,
       'valign'  => true,
    ),
    'thead'      => array(
       'align'   => true,
       'char'    => true,
       'charoff' => true,
       'valign'  => true,
    ),
    'th'         => array(
       'abbr'    => true,
       'align'   => true,
       'axis'    => true,
       'bgcolor' => true,
       'char'    => true,
       'charoff' => true,
       'colspan' => true,
       'headers' => true,
       'height'  => true,
       'nowrap'  => true,
       'rowspan' => true,
       'scope'   => true,
       'valign'  => true,
       'width'   => true,
    ),
    'tr'         => array(
       'align'   => true,
       'bgcolor' => true,
       'char'    => true,
       'charoff' => true,
       'valign'  => true,
    ),
    'td'         => array(
       'abbr'    => true,
       'align'   => true,
       'axis'    => true,
       'bgcolor' => true,
       'char'    => true,
       'charoff' => true,
       'colspan' => true,
       'dir'     => true,
       'headers' => true,
       'height'  => true,
       'nowrap'  => true,
       'rowspan' => true,
       'scope'   => true,
       'valign'  => true,
       'width'   => true,
    ),
    'tfoot'      => array(
       'align'   => true,
       'char'    => true,
       'charoff' => true,
       'valign'  => true,
    ),
    'noscript'   => array(),
    'del'        => array(),
    'blockquote' => array(
       'cite' => true,
    ),
);
// +Merged with globally allowed tags
$global_allowed = array(
				'a'      => array(
					'href'     => array(),
					'rel'      => true,
					'rev'      => true,
					'name'     => true,
					'target'   => true,
					'download' => array(
						'valueless' => 'y',
					),
				),
				'em'     => array(),
				'i'      => array(),
				'b'      => array(),
				'q'      => array(
					'cite' => true,
				),
				's'      => array(),
				'strike' => array(),
				'strong' => array(),
				'br'     => array(),
				'div'    => array(
					'align' => true,
					'dir'   => true,
					'lang'  => true,
				),
				'span'   => array(
					'dir'   => true,
					'align' => true,
					'lang'  => true,
				),
				'code'   => array(),
				'hr'     => array(
					'style' => true,
				),
			);

// And global attributes for each allowed tag from WordPress native function:
$global_attributes = array(
		'aria-controls'    => true,
		'aria-current'     => true,
		'aria-describedby' => true,
		'aria-details'     => true,
		'aria-expanded'    => true,
		'aria-hidden'      => true,
		'aria-label'       => true,
		'aria-labelledby'  => true,
		'aria-live'        => true,
		'class'            => true,
		'data-*'           => true,
		'dir'              => true,
		'hidden'           => true,
		'id'               => true,
		'lang'             => true,
		'style'            => true,
		'title'            => true,
		'role'             => true,
		'xml:lang'         => true,
	);<br>
	

Global Attributes (UM Template List Only)

Unlike the Biography field, tags used in the UM Template context (Custom Textareas) support a wider range of global attributes. If an attribute is not on this list or the specific tag list, it will be stripped.

Supported Global Attributes: id, class, style, title, role, dir, lang, hidden, and aria-* or data-* attributes.

$allowed_html['iframe'] = array(
			'allow'           => true,
			'frameborder'     => true,
			'loading'         => true,
			'name'            => true,
			'referrerpolicy'  => true,
			'sandbox'         => true,
			'src'             => true,
			'srcdoc'          => true,
			'title'           => true,
			'width'           => true,
			'height'          => true,
			'allowfullscreen' => true,
		);
	

UM allowed HTML tags

Ultimate Member manages HTML differently depending on where the data is displayed. For a full technical breakdown of every allowed tag and attribute, please see our dedicated UM Allowed HTML Tags Guide.


How to Restore Legacy Functionality

Because we cannot leave the sanitization as it was for everyone due to security reasons, you can manually restore the previous behavior (allowing iframes or broader tags) using a filter in your theme's functions.php.

Option A: Restore iframes and Template Tags to Biography

This snippet allows the Biography field to use the broader UM Template list and explicitly whitelists the <iframe> tag.

[!WARNING] Security Note: Enabling iframes and broader HTML tags is not recommended for sites with untrusted registrations. Only use this if you trust your members, as it allows more permissive HTML to be saved to your database.

Option B: The um_sanitize_form_submission Filter

End-customers can also use the um_sanitize_form_submission filter hook to change sanitized data in a custom way for specific fields to maintain legacy behavior where needed.


Troubleshooting FAQ

Why did my YouTube/Vimeo videos disappear?

As of v2.11.2, the <iframe> tag is stripped by default for security. To allow them again, you must use the code snippet provided above.

My custom Biography layout is broken. Why?

The Biography field is now restricted to basic WordPress text tags. Complex layouts using <div> or <span> will be removed unless you use the restoration snippet above to revert to the "UM Template" list.

Can I use the um_sanitize_form_submission filter?

Yes. Starting with version 2.11.3, you can use the um_sanitize_form_submission filter hook to change sanitized data in a custom way for specific fields.

Would you like me to add a section explaining the specific global attributes supported by the UM Template list?