WordPress.org

Make WordPress Core

Changeset 41392


Ignore:
Timestamp:
09/19/17 07:43:34 (2 months ago)
Author:
ocean90
Message:

Widgets: Prevent visual Text widget from decoding encoded HTML.

Also apply the_editor_content filters on widget text with format_for_editor() as is done for the post editor.

Merge of [41260] to the 4.8 branch.

Amends [40631].
Props westonruter, azaozz.
See #35243.
Fixes #41596.

Location:
branches/4.8
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • branches/4.8

  • branches/4.8/src/wp-admin/js/widgets/text-widgets.js

    r41133 r41392  
    8181            _.each( control.fields, function( fieldInput, fieldName ) { 
    8282                fieldInput.on( 'input change', function updateSyncField() { 
    83                     var syncInput = control.syncContainer.find( 'input[type=hidden].' + fieldName ); 
     83                    var syncInput = control.syncContainer.find( '.sync-input.' + fieldName ); 
    8484                    if ( syncInput.val() !== fieldInput.val() ) { 
    8585                        syncInput.val( fieldInput.val() ); 
     
    8989 
    9090                // Note that syncInput cannot be re-used because it will be destroyed with each widget-updated event. 
    91                 fieldInput.val( control.syncContainer.find( 'input[type=hidden].' + fieldName ).val() ); 
     91                fieldInput.val( control.syncContainer.find( '.sync-input.' + fieldName ).val() ); 
    9292            }); 
    9393        }, 
     
    145145 
    146146            if ( ! control.fields.title.is( document.activeElement ) ) { 
    147                 syncInput = control.syncContainer.find( 'input[type=hidden].title' ); 
     147                syncInput = control.syncContainer.find( '.sync-input.title' ); 
    148148                control.fields.title.val( syncInput.val() ); 
    149149            } 
    150150 
    151             syncInput = control.syncContainer.find( 'input[type=hidden].text' ); 
     151            syncInput = control.syncContainer.find( '.sync-input.text' ); 
    152152            if ( control.fields.text.is( ':visible' ) ) { 
    153153                if ( ! control.fields.text.is( document.activeElement ) ) { 
  • branches/4.8/src/wp-includes/widgets/class-wp-widget-text.php

    r41391 r41392  
    336336     * @access public 
    337337     * @see WP_Widget_Visual_Text::render_control_template_scripts() 
     338     * @see _WP_Editors::editor() 
    338339     * 
    339340     * @param array $instance Current settings. 
     
    350351        ?> 
    351352        <?php if ( ! $this->is_legacy_instance( $instance ) ) : ?> 
    352             <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'] ); ?>"> 
    353             <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'] ); ?>"> 
    354             <input id="<?php echo $this->get_field_id( 'filter' ); ?>" name="<?php echo $this->get_field_name( 'filter' ); ?>" class="filter" type="hidden" value="on"> 
    355             <input id="<?php echo $this->get_field_id( 'visual' ); ?>" name="<?php echo $this->get_field_name( 'visual' ); ?>" class="visual" type="hidden" value="on"> 
     353            <?php 
     354 
     355            if ( user_can_richedit() ) { 
     356                add_filter( 'the_editor_content', 'format_for_editor', 10, 2 ); 
     357                $default_editor = 'tinymce'; 
     358            } else { 
     359                $default_editor = 'html'; 
     360            } 
     361 
     362            /** This filter is documented in wp-includes/class-wp-editor.php */ 
     363            $text = apply_filters( 'the_editor_content', $instance['text'], $default_editor ); 
     364 
     365            // Reset filter addition. 
     366            if ( user_can_richedit() ) { 
     367                remove_filter( 'the_editor_content', 'format_for_editor' ); 
     368            } 
     369 
     370            // Prevent premature closing of textarea in case format_for_editor() didn't apply or the_editor_content filter did a wrong thing. 
     371            $escaped_text = preg_replace( '#</textarea#i', '&lt;/textarea', $text ); 
     372 
     373            ?> 
     374            <input id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" class="title sync-input" type="hidden" value="<?php echo esc_attr( $instance['title'] ); ?>"> 
     375            <textarea id="<?php echo $this->get_field_id( 'text' ); ?>" name="<?php echo $this->get_field_name( 'text' ); ?>" class="text sync-input" hidden><?php echo $escaped_text; ?></textarea> 
     376            <input id="<?php echo $this->get_field_id( 'filter' ); ?>" name="<?php echo $this->get_field_name( 'filter' ); ?>" class="filter sync-input" type="hidden" value="on"> 
     377            <input id="<?php echo $this->get_field_id( 'visual' ); ?>" name="<?php echo $this->get_field_name( 'visual' ); ?>" class="visual sync-input" type="hidden" value="on"> 
    356378        <?php else : ?> 
    357379            <input id="<?php echo $this->get_field_id( 'visual' ); ?>" name="<?php echo $this->get_field_name( 'visual' ); ?>" class="visual" type="hidden" value=""> 
  • branches/4.8/tests/phpunit/tests/widgets/text-widget.php

    r41391 r41392  
    447447     */ 
    448448    function test_form() { 
    449         $widget = new WP_Widget_Text(); 
     449        add_filter( 'user_can_richedit', '__return_true' ); 
     450        $widget = new WP_Widget_Text(); 
     451        $widget->_set( 2 ); 
    450452        $instance = array( 
    451453            'title' => 'Title', 
     
    459461        $form = ob_get_clean(); 
    460462        $this->assertContains( 'class="visual" type="hidden" value=""', $form ); 
    461         $this->assertNotContains( 'class="visual" type="hidden" value="on"', $form ); 
     463        $this->assertNotContains( 'class="visual sync-input" type="hidden" value="on"', $form ); 
    462464 
    463465        $instance = array( 
     
    470472        $widget->form( $instance ); 
    471473        $form = ob_get_clean(); 
    472         $this->assertContains( 'class="visual" type="hidden" value="on"', $form ); 
    473         $this->assertNotContains( 'class="visual" type="hidden" value=""', $form ); 
     474        $this->assertContains( 'class="visual sync-input" type="hidden" value="on"', $form ); 
     475        $this->assertNotContains( 'class="visual sync-input" type="hidden" value=""', $form ); 
    474476 
    475477        $instance = array( 
     
    482484        $widget->form( $instance ); 
    483485        $form = ob_get_clean(); 
    484         $this->assertContains( 'class="visual" type="hidden" value="on"', $form ); 
    485         $this->assertNotContains( 'class="visual" type="hidden" value=""', $form ); 
    486  
    487         $instance = array( 
    488             'title' => 'Title', 
    489             'text' => 'Text', 
     486        $this->assertContains( 'class="visual sync-input" type="hidden" value="on"', $form ); 
     487        $this->assertNotContains( 'class="visual sync-input" type="hidden" value=""', $form ); 
     488 
     489        $instance = array( 
     490            'title' => 'Title', 
     491            'text' => 'This is some HTML Code: <code>&lt;strong&gt;BOLD!&lt;/strong&gt;</code>', 
    490492            'filter' => true, 
    491493            'visual' => true, 
     
    495497        $widget->form( $instance ); 
    496498        $form = ob_get_clean(); 
    497         $this->assertContains( 'class="visual" type="hidden" value="on"', $form ); 
    498         $this->assertNotContains( 'class="visual" type="hidden" value=""', $form ); 
     499        $this->assertContains( 'class="visual sync-input" type="hidden" value="on"', $form ); 
     500        $this->assertContains( '&lt;code&gt;&amp;lt;strong&amp;gt;BOLD!', $form ); 
     501        $this->assertNotContains( 'class="visual sync-input" type="hidden" value=""', $form ); 
     502 
     503        remove_filter( 'user_can_richedit', '__return_true' ); 
     504        add_filter( 'user_can_richedit', '__return_false' ); 
     505        $instance = array( 
     506            'title' => 'Title', 
     507            'text' => 'Evil:</textarea><script>alert("XSS")</script>', 
     508            'filter' => true, 
     509            'visual' => true, 
     510        ); 
     511        $this->assertFalse( $widget->is_legacy_instance( $instance ) ); 
     512        ob_start(); 
     513        $widget->form( $instance ); 
     514        $form = ob_get_clean(); 
     515        $this->assertNotContains( 'Evil:</textarea>', $form ); 
     516        $this->assertContains( 'Evil:&lt;/textarea>', $form ); 
    499517    } 
    500518 
Note: See TracChangeset for help on using the changeset viewer.