WordPress.org

Make WordPress Core

Changeset 41392


Ignore:
Timestamp:
09/19/2017 07:43:34 AM (8 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.