wp/wp-includes/widgets/class-wp-widget-text.php
changeset 9 177826044cd9
parent 7 cf61fcea0001
child 16 a86126ab1dd4
equal deleted inserted replaced
8:c7c34916027a 9:177826044cd9
    28 	 * Sets up a new Text widget instance.
    28 	 * Sets up a new Text widget instance.
    29 	 *
    29 	 *
    30 	 * @since 2.8.0
    30 	 * @since 2.8.0
    31 	 */
    31 	 */
    32 	public function __construct() {
    32 	public function __construct() {
    33 		$widget_ops = array(
    33 		$widget_ops  = array(
    34 			'classname' => 'widget_text',
    34 			'classname'                   => 'widget_text',
    35 			'description' => __( 'Arbitrary text.' ),
    35 			'description'                 => __( 'Arbitrary text.' ),
    36 			'customize_selective_refresh' => true,
    36 			'customize_selective_refresh' => true,
    37 		);
    37 		);
    38 		$control_ops = array(
    38 		$control_ops = array(
    39 			'width' => 400,
    39 			'width'  => 400,
    40 			'height' => 350,
    40 			'height' => 350,
    41 		);
    41 		);
    42 		parent::__construct( 'text', __( 'Text' ), $widget_ops, $control_ops );
    42 		parent::__construct( 'text', __( 'Text' ), $widget_ops, $control_ops );
    43 	}
    43 	}
    44 
    44 
    97 		// If the text is empty, then nothing is preventing migration to TinyMCE.
    97 		// If the text is empty, then nothing is preventing migration to TinyMCE.
    98 		if ( empty( $instance['text'] ) ) {
    98 		if ( empty( $instance['text'] ) ) {
    99 			return false;
    99 			return false;
   100 		}
   100 		}
   101 
   101 
   102 		$wpautop = ! empty( $instance['filter'] );
   102 		$wpautop         = ! empty( $instance['filter'] );
   103 		$has_line_breaks = ( false !== strpos( trim( $instance['text'] ), "\n" ) );
   103 		$has_line_breaks = ( false !== strpos( trim( $instance['text'] ), "\n" ) );
   104 
   104 
   105 		// If auto-paragraphs are not enabled and there are line breaks, then ensure legacy mode.
   105 		// If auto-paragraphs are not enabled and there are line breaks, then ensure legacy mode.
   106 		if ( ! $wpautop && $has_line_breaks ) {
   106 		if ( ! $wpautop && $has_line_breaks ) {
   107 			return true;
   107 			return true;
   118 			return true;
   118 			return true;
   119 			// @codeCoverageIgnoreEnd
   119 			// @codeCoverageIgnoreEnd
   120 		}
   120 		}
   121 
   121 
   122 		$doc = new DOMDocument();
   122 		$doc = new DOMDocument();
   123 		@$doc->loadHTML( sprintf(
   123 
   124 			'<!DOCTYPE html><html><head><meta charset="%s"></head><body>%s</body></html>',
   124 		// Suppress warnings generated by loadHTML
   125 			esc_attr( get_bloginfo( 'charset' ) ),
   125 		$errors = libxml_use_internal_errors( true );
   126 			$instance['text']
   126 		@$doc->loadHTML(
   127 		) );
   127 			sprintf(
       
   128 				'<!DOCTYPE html><html><head><meta charset="%s"></head><body>%s</body></html>',
       
   129 				esc_attr( get_bloginfo( 'charset' ) ),
       
   130 				$instance['text']
       
   131 			)
       
   132 		);
       
   133 		libxml_use_internal_errors( $errors );
       
   134 
   128 		$body = $doc->getElementsByTagName( 'body' )->item( 0 );
   135 		$body = $doc->getElementsByTagName( 'body' )->item( 0 );
   129 
   136 
   130 		// See $allowedposttags.
   137 		// See $allowedposttags.
   131 		$safe_elements_attributes = array(
   138 		$safe_elements_attributes = array(
   132 			'strong' => array(),
   139 			'strong'  => array(),
   133 			'em' => array(),
   140 			'em'      => array(),
   134 			'b' => array(),
   141 			'b'       => array(),
   135 			'i' => array(),
   142 			'i'       => array(),
   136 			'u' => array(),
   143 			'u'       => array(),
   137 			's' => array(),
   144 			's'       => array(),
   138 			'ul' => array(),
   145 			'ul'      => array(),
   139 			'ol' => array(),
   146 			'ol'      => array(),
   140 			'li' => array(),
   147 			'li'      => array(),
   141 			'hr' => array(),
   148 			'hr'      => array(),
   142 			'abbr' => array(),
   149 			'abbr'    => array(),
   143 			'acronym' => array(),
   150 			'acronym' => array(),
   144 			'code' => array(),
   151 			'code'    => array(),
   145 			'dfn' => array(),
   152 			'dfn'     => array(),
   146 			'a' => array(
   153 			'a'       => array(
   147 				'href' => true,
   154 				'href' => true,
   148 			),
   155 			),
   149 			'img' => array(
   156 			'img'     => array(
   150 				'src' => true,
   157 				'src' => true,
   151 				'alt' => true,
   158 				'alt' => true,
   152 			),
   159 			),
   153 		);
   160 		);
   154 		$safe_empty_elements = array( 'img', 'hr', 'iframe' );
   161 		$safe_empty_elements      = array( 'img', 'hr', 'iframe' );
   155 
   162 
   156 		foreach ( $body->getElementsByTagName( '*' ) as $element ) {
   163 		foreach ( $body->getElementsByTagName( '*' ) as $element ) {
   157 			/** @var DOMElement $element */
   164 			/** @var DOMElement $element */
   158 			$tag_name = strtolower( $element->nodeName );
   165 			$tag_name = strtolower( $element->nodeName );
   159 
   166 
   217 		$title = ! empty( $instance['title'] ) ? $instance['title'] : '';
   224 		$title = ! empty( $instance['title'] ) ? $instance['title'] : '';
   218 
   225 
   219 		/** This filter is documented in wp-includes/widgets/class-wp-widget-pages.php */
   226 		/** This filter is documented in wp-includes/widgets/class-wp-widget-pages.php */
   220 		$title = apply_filters( 'widget_title', $title, $instance, $this->id_base );
   227 		$title = apply_filters( 'widget_title', $title, $instance, $this->id_base );
   221 
   228 
   222 		$text = ! empty( $instance['text'] ) ? $instance['text'] : '';
   229 		$text                  = ! empty( $instance['text'] ) ? $instance['text'] : '';
   223 		$is_visual_text_widget = ( ! empty( $instance['visual'] ) && ! empty( $instance['filter'] ) );
   230 		$is_visual_text_widget = ( ! empty( $instance['visual'] ) && ! empty( $instance['filter'] ) );
   224 
   231 
   225 		// In 4.8.0 only, visual Text widgets get filter=content, without visual prop; upgrade instance props just-in-time.
   232 		// In 4.8.0 only, visual Text widgets get filter=content, without visual prop; upgrade instance props just-in-time.
   226 		if ( ! $is_visual_text_widget ) {
   233 		if ( ! $is_visual_text_widget ) {
   227 			$is_visual_text_widget = ( isset( $instance['filter'] ) && 'content' === $instance['filter'] );
   234 			$is_visual_text_widget = ( isset( $instance['filter'] ) && 'content' === $instance['filter'] );
   235 		 * Suspend legacy plugin-supplied do_shortcode() for 'widget_text' filter for the visual Text widget to prevent
   242 		 * Suspend legacy plugin-supplied do_shortcode() for 'widget_text' filter for the visual Text widget to prevent
   236 		 * shortcodes being processed twice. Now do_shortcode() is added to the 'widget_text_content' filter in core itself
   243 		 * shortcodes being processed twice. Now do_shortcode() is added to the 'widget_text_content' filter in core itself
   237 		 * and it applies after wpautop() to prevent corrupting HTML output added by the shortcode. When do_shortcode() is
   244 		 * and it applies after wpautop() to prevent corrupting HTML output added by the shortcode. When do_shortcode() is
   238 		 * added to 'widget_text_content' then do_shortcode() will be manually called when in legacy mode as well.
   245 		 * added to 'widget_text_content' then do_shortcode() will be manually called when in legacy mode as well.
   239 		 */
   246 		 */
   240 		$widget_text_do_shortcode_priority = has_filter( 'widget_text', 'do_shortcode' );
   247 		$widget_text_do_shortcode_priority       = has_filter( 'widget_text', 'do_shortcode' );
   241 		$should_suspend_legacy_shortcode_support = ( $is_visual_text_widget && false !== $widget_text_do_shortcode_priority );
   248 		$should_suspend_legacy_shortcode_support = ( $is_visual_text_widget && false !== $widget_text_do_shortcode_priority );
   242 		if ( $should_suspend_legacy_shortcode_support ) {
   249 		if ( $should_suspend_legacy_shortcode_support ) {
   243 			remove_filter( 'widget_text', 'do_shortcode', $widget_text_do_shortcode_priority );
   250 			remove_filter( 'widget_text', 'do_shortcode', $widget_text_do_shortcode_priority );
   244 		}
   251 		}
   245 
   252 
   319 			echo $args['before_title'] . $title . $args['after_title'];
   326 			echo $args['before_title'] . $title . $args['after_title'];
   320 		}
   327 		}
   321 
   328 
   322 		$text = preg_replace_callback( '#<(video|iframe|object|embed)\s[^>]*>#i', array( $this, 'inject_video_max_width_style' ), $text );
   329 		$text = preg_replace_callback( '#<(video|iframe|object|embed)\s[^>]*>#i', array( $this, 'inject_video_max_width_style' ), $text );
   323 
   330 
       
   331 		// Adds noreferrer and noopener relationships, without duplicating values, to all HTML A elements that have a target.
       
   332 		$text = wp_targeted_link_rel( $text );
       
   333 
   324 		?>
   334 		?>
   325 			<div class="textwidget"><?php echo $text; ?></div>
   335 			<div class="textwidget"><?php echo $text; ?></div>
   326 		<?php
   336 		<?php
   327 		echo $args['after_widget'];
   337 		echo $args['after_widget'];
   328 	}
   338 	}
   353 	 *                            WP_Widget::form().
   363 	 *                            WP_Widget::form().
   354 	 * @param array $old_instance Old settings for this instance.
   364 	 * @param array $old_instance Old settings for this instance.
   355 	 * @return array Settings to save or bool false to cancel saving.
   365 	 * @return array Settings to save or bool false to cancel saving.
   356 	 */
   366 	 */
   357 	public function update( $new_instance, $old_instance ) {
   367 	public function update( $new_instance, $old_instance ) {
   358 		$new_instance = wp_parse_args( $new_instance, array(
   368 		$new_instance = wp_parse_args(
   359 			'title' => '',
   369 			$new_instance,
   360 			'text' => '',
   370 			array(
   361 			'filter' => false, // For back-compat.
   371 				'title'  => '',
   362 			'visual' => null, // Must be explicitly defined.
   372 				'text'   => '',
   363 		) );
   373 				'filter' => false, // For back-compat.
       
   374 				'visual' => null, // Must be explicitly defined.
       
   375 			)
       
   376 		);
   364 
   377 
   365 		$instance = $old_instance;
   378 		$instance = $old_instance;
   366 
   379 
   367 		$instance['title'] = sanitize_text_field( $new_instance['title'] );
   380 		$instance['title'] = sanitize_text_field( $new_instance['title'] );
   368 		if ( current_user_can( 'unfiltered_html' ) ) {
   381 		if ( current_user_can( 'unfiltered_html' ) ) {
   425 	 * Outputs the Text widget settings form.
   438 	 * Outputs the Text widget settings form.
   426 	 *
   439 	 *
   427 	 * @since 2.8.0
   440 	 * @since 2.8.0
   428 	 * @since 4.8.0 Form only contains hidden inputs which are synced with JS template.
   441 	 * @since 4.8.0 Form only contains hidden inputs which are synced with JS template.
   429 	 * @since 4.8.1 Restored original form to be displayed when in legacy mode.
   442 	 * @since 4.8.1 Restored original form to be displayed when in legacy mode.
   430 	 * @see WP_Widget_Visual_Text::render_control_template_scripts()
   443 	 * @see WP_Widget_Text::render_control_template_scripts()
   431 	 * @see _WP_Editors::editor()
   444 	 * @see _WP_Editors::editor()
   432 	 *
   445 	 *
   433 	 * @param array $instance Current settings.
   446 	 * @param array $instance Current settings.
   434 	 * @return void
   447 	 * @return void
   435 	 */
   448 	 */
   436 	public function form( $instance ) {
   449 	public function form( $instance ) {
   437 		$instance = wp_parse_args(
   450 		$instance = wp_parse_args(
   438 			(array) $instance,
   451 			(array) $instance,
   439 			array(
   452 			array(
   440 				'title' => '',
   453 				'title' => '',
   441 				'text' => '',
   454 				'text'  => '',
   442 			)
   455 			)
   443 		);
   456 		);
   444 		?>
   457 		?>
   445 		<?php if ( ! $this->is_legacy_instance( $instance ) ) : ?>
   458 		<?php if ( ! $this->is_legacy_instance( $instance ) ) : ?>
   446 			<?php
   459 			<?php
   486 				<textarea class="widefat" rows="16" cols="20" id="<?php echo $this->get_field_id( 'text' ); ?>" name="<?php echo $this->get_field_name( 'text' ); ?>"><?php echo esc_textarea( $instance['text'] ); ?></textarea>
   499 				<textarea class="widefat" rows="16" cols="20" id="<?php echo $this->get_field_id( 'text' ); ?>" name="<?php echo $this->get_field_name( 'text' ); ?>"><?php echo esc_textarea( $instance['text'] ); ?></textarea>
   487 			</p>
   500 			</p>
   488 			<p>
   501 			<p>
   489 				<input id="<?php echo $this->get_field_id( 'filter' ); ?>" name="<?php echo $this->get_field_name( 'filter' ); ?>" type="checkbox"<?php checked( ! empty( $instance['filter'] ) ); ?> />&nbsp;<label for="<?php echo $this->get_field_id( 'filter' ); ?>"><?php _e( 'Automatically add paragraphs' ); ?></label>
   502 				<input id="<?php echo $this->get_field_id( 'filter' ); ?>" name="<?php echo $this->get_field_name( 'filter' ); ?>" type="checkbox"<?php checked( ! empty( $instance['filter'] ) ); ?> />&nbsp;<label for="<?php echo $this->get_field_id( 'filter' ); ?>"><?php _e( 'Automatically add paragraphs' ); ?></label>
   490 			</p>
   503 			</p>
   491 		<?php
   504 			<?php
   492 		endif;
   505 		endif;
   493 	}
   506 	}
   494 
   507 
   495 	/**
   508 	/**
   496 	 * Render form template scripts.
   509 	 * Render form template scripts.