WP_Widget_Text::is_legacy_instance( array $instance )

Determines whether a given instance is legacy and should bypass using TinyMCE.


Parameters

$instance

(Required) Instance data.

  • 'text'
    (string) Content.
  • 'filter'
    (bool|string) Whether autop or content filters should apply.
  • 'legacy'
    (bool) Whether widget is in legacy mode.


Return

(bool) Whether Text widget instance contains legacy data.


Source

File: wp-includes/widgets/class-wp-widget-text.php

	public function is_legacy_instance( $instance ) {

		// Legacy mode when not in visual mode.
		if ( isset( $instance['visual'] ) ) {
			return ! $instance['visual'];
		}

		// Or, the widget has been added/updated in WP-4.8.0 then filter prop is 'content' and it is no longer legacy.
		if ( isset( $instance['filter'] ) && 'content' === $instance['filter'] ) {
			return false;
		}

		// If the text is empty, then nothing is preventing migration to TinyMCE.
		if ( empty( $instance['text'] ) ) {
			return false;
		}

		$wpautop = ! empty( $instance['filter'] );
		$has_line_breaks = ( false !== strpos( trim( $instance['text'] ), "\n" ) );

		// If auto-paragraphs are not enabled and there are line breaks, then ensure legacy mode.
		if ( ! $wpautop && $has_line_breaks ) {
			return true;
		}

		// If an HTML comment is present, assume legacy mode.
		if ( false !== strpos( $instance['text'], '<!--' ) ) {
			return true;
		}

		// In the rare case that DOMDocument is not available we cannot reliably sniff content and so we assume legacy.
		if ( ! class_exists( 'DOMDocument' ) ) {
			// @codeCoverageIgnoreStart
			return true;
			// @codeCoverageIgnoreEnd
		}

		$doc = new DOMDocument();
		@$doc->loadHTML( sprintf(
			'<!DOCTYPE html><html><head><meta charset="%s"></head><body>%s</body></html>',
			esc_attr( get_bloginfo( 'charset' ) ),
			$instance['text']
		) );
		$body = $doc->getElementsByTagName( 'body' )->item( 0 );

		// See $allowedposttags.
		$safe_elements_attributes = array(
			'strong' => array(),
			'em' => array(),
			'b' => array(),
			'i' => array(),
			'u' => array(),
			's' => array(),
			'ul' => array(),
			'ol' => array(),
			'li' => array(),
			'hr' => array(),
			'abbr' => array(),
			'acronym' => array(),
			'code' => array(),
			'dfn' => array(),
			'a' => array(
				'href' => true,
			),
			'img' => array(
				'src' => true,
				'alt' => true,
			),
		);
		$safe_empty_elements = array( 'img', 'hr', 'iframe' );

		foreach ( $body->getElementsByTagName( '*' ) as $element ) {
			/** @var DOMElement $element */
			$tag_name = strtolower( $element->nodeName );

			// If the element is not safe, then the instance is legacy.
			if ( ! isset( $safe_elements_attributes[ $tag_name ] ) ) {
				return true;
			}

			// If the element is not safely empty and it has empty contents, then legacy mode.
			if ( ! in_array( $tag_name, $safe_empty_elements, true ) && '' === trim( $element->textContent ) ) {
				return true;
			}

			// If an attribute is not recognized as safe, then the instance is legacy.
			foreach ( $element->attributes as $attribute ) {
				/** @var DOMAttr $attribute */
				$attribute_name = strtolower( $attribute->nodeName );

				if ( ! isset( $safe_elements_attributes[ $tag_name ][ $attribute_name ] ) ) {
					return true;
				}
			}
		}

		// Otherwise, the text contains no elements/attributes that TinyMCE could drop, and therefore the widget does not need legacy mode.
		return false;
	}


Changelog

Changelog
Version Description
WP-4.8.1 Introduced.