Make WordPress Core

Changeset 41260


Ignore:
Timestamp:
08/17/2017 11:36:53 PM (9 years ago)
Author:
westonruter
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.

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

Location:
trunk
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/js/widgets/text-widgets.js

    r41249 r41260  
    8282                        _.each( control.fields, function( fieldInput, fieldName ) {
    8383                                fieldInput.on( 'input change', function updateSyncField() {
    84                                         var syncInput = control.syncContainer.find( 'input[type=hidden].' + fieldName );
     84                                        var syncInput = control.syncContainer.find( '.sync-input.' + fieldName );
    8585                                        if ( syncInput.val() !== fieldInput.val() ) {
    8686                                                syncInput.val( fieldInput.val() );
     
    9090
    9191                                // Note that syncInput cannot be re-used because it will be destroyed with each widget-updated event.
    92                                 fieldInput.val( control.syncContainer.find( 'input[type=hidden].' + fieldName ).val() );
     92                                fieldInput.val( control.syncContainer.find( '.sync-input.' + fieldName ).val() );
    9393                        });
    9494                },
     
    146146
    147147                        if ( ! control.fields.title.is( document.activeElement ) ) {
    148                                 syncInput = control.syncContainer.find( 'input[type=hidden].title' );
     148                                syncInput = control.syncContainer.find( '.sync-input.title' );
    149149                                control.fields.title.val( syncInput.val() );
    150150                        }
    151151
    152                         syncInput = control.syncContainer.find( 'input[type=hidden].text' );
     152                        syncInput = control.syncContainer.find( '.sync-input.text' );
    153153                        if ( control.fields.text.is( ':visible' ) ) {
    154154                                if ( ! control.fields.text.is( document.activeElement ) ) {
  • trunk/src/wp-includes/widgets/class-wp-widget-text.php

    r41251 r41260  
    333333         * @since 4.8.1 Restored original form to be displayed when in legacy mode.
    334334         * @see WP_Widget_Visual_Text::render_control_template_scripts()
     335         * @see _WP_Editors::editor()
    335336         *
    336337         * @param array $instance Current settings.
     
    347348                ?>
    348349                <?php if ( ! $this->is_legacy_instance( $instance ) ) : ?>
    349                         <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'] ); ?>">
    350                         <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'] ); ?>">
    351                         <input id="<?php echo $this->get_field_id( 'filter' ); ?>" name="<?php echo $this->get_field_name( 'filter' ); ?>" class="filter" type="hidden" value="on">
    352                         <input id="<?php echo $this->get_field_id( 'visual' ); ?>" name="<?php echo $this->get_field_name( 'visual' ); ?>" class="visual" type="hidden" value="on">
     350                        <?php
     351
     352                        if ( user_can_richedit() ) {
     353                                add_filter( 'the_editor_content', 'format_for_editor', 10, 2 );
     354                                $default_editor = 'tinymce';
     355                        } else {
     356                                $default_editor = 'html';
     357                        }
     358
     359                        /** This filter is documented in wp-includes/class-wp-editor.php */
     360                        $text = apply_filters( 'the_editor_content', $instance['text'], $default_editor );
     361
     362                        // Reset filter addition.
     363                        if ( user_can_richedit() ) {
     364                                remove_filter( 'the_editor_content', 'format_for_editor' );
     365                        }
     366
     367                        // Prevent premature closing of textarea in case format_for_editor() didn't apply or the_editor_content filter did a wrong thing.
     368                        $escaped_text = preg_replace( '#</textarea#i', '&lt;/textarea', $text );
     369
     370                        ?>
     371                        <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'] ); ?>">
     372                        <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>
     373                        <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">
     374                        <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">
    353375                <?php else : ?>
    354376                        <input id="<?php echo $this->get_field_id( 'visual' ); ?>" name="<?php echo $this->get_field_name( 'visual' ); ?>" class="visual" type="hidden" value="">
  • trunk/tests/phpunit/tests/widgets/text-widget.php

    r41251 r41260  
    448448         */
    449449        function test_form() {
    450                 $widget = new WP_Widget_Text();
     450                add_filter( 'user_can_richedit', '__return_true' );
     451                $widget = new WP_Widget_Text();
     452                $widget->_set( 2 );
    451453                $instance = array(
    452454                        'title' => 'Title',
     
    460462                $form = ob_get_clean();
    461463                $this->assertContains( 'class="visual" type="hidden" value=""', $form );
    462                 $this->assertNotContains( 'class="visual" type="hidden" value="on"', $form );
     464                $this->assertNotContains( 'class="visual sync-input" type="hidden" value="on"', $form );
    463465
    464466                $instance = array(
     
    471473                $widget->form( $instance );
    472474                $form = ob_get_clean();
    473                 $this->assertContains( 'class="visual" type="hidden" value="on"', $form );
    474                 $this->assertNotContains( 'class="visual" type="hidden" value=""', $form );
     475                $this->assertContains( 'class="visual sync-input" type="hidden" value="on"', $form );
     476                $this->assertNotContains( 'class="visual sync-input" type="hidden" value=""', $form );
    475477
    476478                $instance = array(
     
    483485                $widget->form( $instance );
    484486                $form = ob_get_clean();
    485                 $this->assertContains( 'class="visual" type="hidden" value="on"', $form );
    486                 $this->assertNotContains( 'class="visual" type="hidden" value=""', $form );
    487 
    488                 $instance = array(
    489                         'title' => 'Title',
    490                         'text' => 'Text',
     487                $this->assertContains( 'class="visual sync-input" type="hidden" value="on"', $form );
     488                $this->assertNotContains( 'class="visual sync-input" type="hidden" value=""', $form );
     489
     490                $instance = array(
     491                        'title' => 'Title',
     492                        'text' => 'This is some HTML Code: <code>&lt;strong&gt;BOLD!&lt;/strong&gt;</code>',
    491493                        'filter' => true,
    492494                        'visual' => true,
     
    496498                $widget->form( $instance );
    497499                $form = ob_get_clean();
    498                 $this->assertContains( 'class="visual" type="hidden" value="on"', $form );
    499                 $this->assertNotContains( 'class="visual" type="hidden" value=""', $form );
     500                $this->assertContains( 'class="visual sync-input" type="hidden" value="on"', $form );
     501                $this->assertContains( '&lt;code&gt;&amp;lt;strong&amp;gt;BOLD!', $form );
     502                $this->assertNotContains( 'class="visual sync-input" type="hidden" value=""', $form );
     503
     504                remove_filter( 'user_can_richedit', '__return_true' );
     505                add_filter( 'user_can_richedit', '__return_false' );
     506                $instance = array(
     507                        'title' => 'Title',
     508                        'text' => 'Evil:</textarea><script>alert("XSS")</script>',
     509                        'filter' => true,
     510                        'visual' => true,
     511                );
     512                $this->assertFalse( $widget->is_legacy_instance( $instance ) );
     513                ob_start();
     514                $widget->form( $instance );
     515                $form = ob_get_clean();
     516                $this->assertNotContains( 'Evil:</textarea>', $form );
     517                $this->assertContains( 'Evil:&lt;/textarea>', $form );
    500518        }
    501519
Note: See TracChangeset for help on using the changeset viewer.