- Timestamp:
- 07/14/2017 05:27:33 PM (7 years ago)
- Location:
- branches/4.8
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/4.8
-
branches/4.8/src/wp-includes/widgets/class-wp-widget-text.php
r41052 r41053 65 65 66 66 /** 67 * Determines whether a given instance is legacy and should bypass using TinyMCE. 68 * 69 * @since 4.8.1 70 * 71 * @param array $instance { 72 * Instance data. 73 * 74 * @type string $text Content. 75 * @type bool|string $filter Whether autop or content filters should apply. 76 * @type bool $legacy Whether widget is in legacy mode. 77 * } 78 * @return bool Whether Text widget instance contains legacy data. 79 */ 80 public function is_legacy_instance( $instance ) { 81 82 // If the widget has been updated while in legacy mode, it stays in legacy mode. 83 if ( ! empty( $instance['legacy'] ) ) { 84 return true; 85 } 86 87 // If the widget has been added/updated in 4.8 then filter prop is 'content' and it is no longer legacy. 88 if ( isset( $instance['filter'] ) && 'content' === $instance['filter'] ) { 89 return false; 90 } 91 92 // If the text is empty, then nothing is preventing migration to TinyMCE. 93 if ( empty( $instance['text'] ) ) { 94 return false; 95 } 96 97 $wpautop = ! empty( $instance['filter'] ); 98 $has_line_breaks = ( false !== strpos( $instance['text'], "\n" ) ); 99 100 // If auto-paragraphs are not enabled and there are line breaks, then ensure legacy mode. 101 if ( ! $wpautop && $has_line_breaks ) { 102 return true; 103 } 104 105 // If an HTML comment is present, assume legacy mode. 106 if ( false !== strpos( $instance['text'], '<!--' ) ) { 107 return true; 108 } 109 110 /* 111 * If a shortcode is present (with support added by a plugin), assume legacy mode 112 * since shortcodes would apply at the widget_text filter and thus be applied 113 * before wpautop runs at the widget_text_content filter. 114 */ 115 if ( preg_match( '/' . get_shortcode_regex() . '/', $instance['text'] ) ) { 116 return true; 117 } 118 119 // In the rare case that DOMDocument is not available we cannot reliably sniff content and so we assume legacy. 120 if ( ! class_exists( 'DOMDocument' ) ) { 121 // @codeCoverageIgnoreStart 122 return true; 123 // @codeCoverageIgnoreEnd 124 } 125 126 $doc = new DOMDocument(); 127 $doc->loadHTML( sprintf( 128 '<html><head><meta charset="%s"></head><body>%s</body></html>', 129 esc_attr( get_bloginfo( 'charset' ) ), 130 $instance['text'] 131 ) ); 132 $body = $doc->getElementsByTagName( 'body' )->item( 0 ); 133 134 // See $allowedposttags. 135 $safe_elements_attributes = array( 136 'strong' => array(), 137 'em' => array(), 138 'b' => array(), 139 'i' => array(), 140 'u' => array(), 141 's' => array(), 142 'ul' => array(), 143 'ol' => array(), 144 'li' => array(), 145 'hr' => array(), 146 'abbr' => array(), 147 'acronym' => array(), 148 'code' => array(), 149 'dfn' => array(), 150 'a' => array( 151 'href' => true, 152 ), 153 'img' => array( 154 'src' => true, 155 'alt' => true, 156 ), 157 ); 158 $safe_empty_elements = array( 'img', 'hr', 'iframe' ); 159 160 foreach ( $body->getElementsByTagName( '*' ) as $element ) { 161 /** @var DOMElement $element */ 162 $tag_name = strtolower( $element->nodeName ); 163 164 // If the element is not safe, then the instance is legacy. 165 if ( ! isset( $safe_elements_attributes[ $tag_name ] ) ) { 166 return true; 167 } 168 169 // If the element is not safely empty and it has empty contents, then legacy mode. 170 if ( ! in_array( $tag_name, $safe_empty_elements, true ) && '' === trim( $element->textContent ) ) { 171 return true; 172 } 173 174 // If an attribute is not recognized as safe, then the instance is legacy. 175 foreach ( $element->attributes as $attribute ) { 176 /** @var DOMAttr $attribute */ 177 $attribute_name = strtolower( $attribute->nodeName ); 178 179 if ( ! isset( $safe_elements_attributes[ $tag_name ][ $attribute_name ] ) ) { 180 return true; 181 } 182 } 183 } 184 185 // Otherwise, the text contains no elements/attributes that TinyMCE could drop, and therefore the widget does not need legacy mode. 186 return false; 187 } 188 189 /** 67 190 * Outputs the content for the current Text widget instance. 68 191 * … … 80 203 81 204 $text = ! empty( $instance['text'] ) ? $instance['text'] : ''; 205 $is_visual_text_widget = ( isset( $instance['filter'] ) && 'content' === $instance['filter'] ); 206 207 /* 208 * Just-in-time temporarily upgrade Visual Text widget shortcode handling 209 * (with support added by plugin) from the widget_text filter to 210 * widget_text_content:11 to prevent wpautop from corrupting HTML output 211 * added by the shortcode. 212 */ 213 $widget_text_do_shortcode_priority = has_filter( 'widget_text', 'do_shortcode' ); 214 $should_upgrade_shortcode_handling = ( $is_visual_text_widget && false !== $widget_text_do_shortcode_priority ); 215 if ( $should_upgrade_shortcode_handling ) { 216 remove_filter( 'widget_text', 'do_shortcode', $widget_text_do_shortcode_priority ); 217 add_filter( 'widget_text_content', 'do_shortcode', 11 ); 218 } 82 219 83 220 /** … … 114 251 } 115 252 253 // Undo temporary upgrade of the plugin-supplied shortcode handling. 254 if ( $should_upgrade_shortcode_handling ) { 255 remove_filter( 'widget_text_content', 'do_shortcode', 11 ); 256 add_filter( 'widget_text', 'do_shortcode', $widget_text_do_shortcode_priority ); 257 } 258 116 259 echo $args['before_widget']; 117 260 if ( ! empty( $title ) ) { … … 146 289 147 290 /* 148 * Re-use legacy 'filter' (wpautop) property to now indicate content filters will always apply. 291 * If the Text widget is in legacy mode, then a hidden input will indicate this 292 * and the new content value for the filter prop will by bypassed. Otherwise, 293 * re-use legacy 'filter' (wpautop) property to now indicate content filters will always apply. 149 294 * Prior to 4.8, this is a boolean value used to indicate whether or not wpautop should be 150 295 * applied. By re-using this property, downgrading WordPress from 4.8 to 4.7 will ensure 151 296 * that the content for Text widgets created with TinyMCE will continue to get wpautop. 152 297 */ 153 $instance['filter'] = 'content'; 298 if ( isset( $new_instance['legacy'] ) || isset( $old_instance['legacy'] ) || ( isset( $new_instance['filter'] ) && 'content' !== $new_instance['filter'] ) ) { 299 $instance['filter'] = ! empty( $new_instance['filter'] ); 300 $instance['legacy'] = true; 301 } else { 302 $instance['filter'] = 'content'; 303 unset( $instance['legacy'] ); 304 } 154 305 155 306 return $instance; … … 172 323 * @since 2.8.0 173 324 * @since 4.8.0 Form only contains hidden inputs which are synced with JS template. 325 * @since 4.8.1 Restored original form to be displayed when in legacy mode. 174 326 * @access public 175 327 * @see WP_Widget_Visual_Text::render_control_template_scripts() … … 187 339 ); 188 340 ?> 189 <input id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" class="title" type="hidden" value="<?php echo esc_attr( $instance['title'] ); ?>"> 190 <input id="<?php echo $this->get_field_id( 'text' ); ?>" name="<?php echo $this->get_field_name( 'text' ); ?>" class="text" type="hidden" value="<?php echo esc_attr( $instance['text'] ); ?>"> 341 <?php if ( ! $this->is_legacy_instance( $instance ) ) : ?> 342 <input id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" class="title" type="hidden" value="<?php echo esc_attr( $instance['title'] ); ?>"> 343 <input id="<?php echo $this->get_field_id( 'text' ); ?>" name="<?php echo $this->get_field_name( 'text' ); ?>" class="text" type="hidden" value="<?php echo esc_attr( $instance['text'] ); ?>"> 344 <?php else : ?> 345 <input name="<?php echo $this->get_field_name( 'legacy' ); ?>" type="hidden" class="legacy" value="true"> 346 <p> 347 <label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php _e( 'Title:' ); ?></label> 348 <input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo esc_attr( $instance['title'] ); ?>"/> 349 </p> 350 <div class="notice inline notice-info notice-alt"> 351 <p><?php _e( 'This widget contains code that may work better in the new “Custom HTML” widget. How about trying that widget instead?' ); ?></p> 352 </div> 353 <p> 354 <label for="<?php echo $this->get_field_id( 'text' ); ?>"><?php _e( 'Content:' ); ?></label> 355 <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> 356 </p> 357 <p> 358 <input id="<?php echo $this->get_field_id( 'filter' ); ?>" name="<?php echo $this->get_field_name( 'filter' ); ?>" type="checkbox"<?php checked( ! empty( $instance['filter'] ) ); ?> /> <label for="<?php echo $this->get_field_id( 'filter' ); ?>"><?php _e( 'Automatically add paragraphs' ); ?></label> 359 </p> 191 360 <?php 361 endif; 192 362 } 193 363 … … 199 369 */ 200 370 public function render_control_template_scripts() { 371 $dismissed_pointers = explode( ',', (string) get_user_meta( get_current_user_id(), 'dismissed_wp_pointers', true ) ); 201 372 ?> 202 373 <script type="text/html" id="tmpl-widget-text-control-fields"> … … 206 377 <input id="{{ elementIdPrefix }}title" type="text" class="widefat title"> 207 378 </p> 379 380 <?php if ( ! in_array( 'text_widget_custom_html', $dismissed_pointers, true ) ) : ?> 381 <div hidden class="wp-pointer custom-html-widget-pointer wp-pointer-top"> 382 <div class="wp-pointer-content"> 383 <h3><?php _e( 'New Custom HTML Widget' ); ?></h3> 384 <?php if ( is_customize_preview() ) : ?> 385 <p><?php _e( 'Hey, did you hear we have a “Custom HTML” widget now? You can find it by pressing the “<a class="add-widget" href="#">Add a Widget</a>” button and searching for “HTML”. Check it out to add some custom code to your site!' ); ?></p> 386 <?php else : ?> 387 <p><?php _e( 'Hey, did you hear we have a “Custom HTML” widget now? You can find it by scanning the list of available widgets on this screen. Check it out to add some custom code to your site!' ); ?></p> 388 <?php endif; ?> 389 <div class="wp-pointer-buttons"> 390 <a class="close" href="#"><?php _e( 'Dismiss' ); ?></a> 391 </div> 392 </div> 393 <div class="wp-pointer-arrow"> 394 <div class="wp-pointer-arrow-inner"></div> 395 </div> 396 </div> 397 <?php endif; ?> 398 399 <?php if ( ! in_array( 'text_widget_paste_html', $dismissed_pointers, true ) ) : ?> 400 <div hidden class="wp-pointer paste-html-pointer wp-pointer-top"> 401 <div class="wp-pointer-content"> 402 <h3><?php _e( 'Did you just paste HTML?' ); ?></h3> 403 <p><?php _e( 'Hey there, looks like you just pasted HTML into the “Visual” tab of the Text widget. You may want to paste your code into the “Text” tab instead. Alternately, try out the new “Custom HTML” widget!' ); ?></p> 404 <div class="wp-pointer-buttons"> 405 <a class="close" href="#"><?php _e( 'Dismiss' ); ?></a> 406 </div> 407 </div> 408 <div class="wp-pointer-arrow"> 409 <div class="wp-pointer-arrow-inner"></div> 410 </div> 411 </div> 412 <?php endif; ?> 413 208 414 <p> 209 415 <label for="{{ elementIdPrefix }}text" class="screen-reader-text"><?php esc_html_e( 'Content:' ); ?></label>
Note: See TracChangeset
for help on using the changeset viewer.