diff --git a/src/wp-admin/js/widgets/text-widgets.js b/src/wp-admin/js/widgets/text-widgets.js index 282090d585..692a0642c9 100644 --- a/src/wp-admin/js/widgets/text-widgets.js +++ b/src/wp-admin/js/widgets/text-widgets.js @@ -368,7 +368,7 @@ wp.textWidgets = ( function( $ ) { } // Bypass using TinyMCE when widget is in legacy mode. - if ( widgetForm.find( '.legacy' ).length > 0 ) { + if ( ! widgetForm.find( '.visual' ).val() ) { return; } @@ -429,7 +429,7 @@ wp.textWidgets = ( function( $ ) { } // Bypass using TinyMCE when widget is in legacy mode. - if ( widgetForm.find( '.legacy' ).length > 0 ) { + if ( ! widgetForm.find( '.visual' ).val() ) { return; } diff --git a/src/wp-includes/widgets/class-wp-widget-custom-html.php b/src/wp-includes/widgets/class-wp-widget-custom-html.php index 7fcce78f19..25d221ba46 100644 --- a/src/wp-includes/widgets/class-wp-widget-custom-html.php +++ b/src/wp-includes/widgets/class-wp-widget-custom-html.php @@ -61,8 +61,16 @@ class WP_Widget_Custom_HTML extends WP_Widget { /** This filter is documented in wp-includes/widgets/class-wp-widget-pages.php */ $title = apply_filters( 'widget_title', $instance['title'], $instance, $this->id_base ); + // Prepare instance data that looks like a normal Text widget. + $simulated_text_widget_instance = array_merge( $instance, array( + 'text' => isset( $instance['content'] ) ? $instance['content'] : '', + 'filter' => false, // Because wpautop is not applied. + 'visual' => false, // Because it wasn't created in TinyMCE. + ) ); + unset( $simulated_text_widget_instance['content'] ); // Was moved to 'text' prop. + /** This filter is documented in wp-includes/widgets/class-wp-widget-text.php */ - $content = apply_filters( 'widget_text', $instance['content'], $instance, $this ); + $content = apply_filters( 'widget_text', $instance['content'], $simulated_text_widget_instance, $this ); /** * Filters the content of the Custom HTML widget. diff --git a/src/wp-includes/widgets/class-wp-widget-text.php b/src/wp-includes/widgets/class-wp-widget-text.php index 2297d2bee2..912c6181bb 100644 --- a/src/wp-includes/widgets/class-wp-widget-text.php +++ b/src/wp-includes/widgets/class-wp-widget-text.php @@ -79,12 +79,12 @@ class WP_Widget_Text extends WP_Widget { */ public function is_legacy_instance( $instance ) { - // If the widget has been updated while in legacy mode, it stays in legacy mode. - if ( ! empty( $instance['legacy'] ) ) { - return true; + // Legacy mode when not in visual mode. + if ( isset( $instance['visual'] ) ) { + return ! $instance['visual']; } - // If the widget has been added/updated in 4.8 then filter prop is 'content' and it is no longer legacy. + // Or, the widget has been added/updated in 4.8.0 then filter prop is 'content' and it is no longer legacy. if ( isset( $instance['filter'] ) && 'content' === $instance['filter'] ) { return false; } @@ -193,7 +193,16 @@ class WP_Widget_Text extends WP_Widget { $title = apply_filters( 'widget_title', empty( $instance['title'] ) ? '' : $instance['title'], $instance, $this->id_base ); $text = ! empty( $instance['text'] ) ? $instance['text'] : ''; - $is_visual_text_widget = ( isset( $instance['filter'] ) && 'content' === $instance['filter'] ); + $is_visual_text_widget = ( ! empty( $instance['visual'] ) && ! empty( $instance['filter'] ) ); + + // In 4.8.0 only, visual Text widgets get filter=content, without visual prop; upgrade instance props just-in-time. + if ( ! $is_visual_text_widget ) { + $is_visual_text_widget = ( isset( $instance['filter'] ) && 'content' === $instance['filter'] ); + } + if ( $is_visual_text_widget ) { + $instance['filter'] = true; + $instance['visual'] = true; + } /* * Just-in-time temporarily upgrade Visual Text widget shortcode handling @@ -221,25 +230,23 @@ class WP_Widget_Text extends WP_Widget { */ $text = apply_filters( 'widget_text', $text, $instance, $this ); - if ( isset( $instance['filter'] ) ) { - if ( 'content' === $instance['filter'] ) { + if ( $is_visual_text_widget ) { - /** - * Filters the content of the Text widget to apply changes expected from the visual (TinyMCE) editor. - * - * By default a subset of the_content filters are applied, including wpautop and wptexturize. - * - * @since 4.8.0 - * - * @param string $text The widget content. - * @param array $instance Array of settings for the current widget. - * @param WP_Widget_Text $this Current Text widget instance. - */ - $text = apply_filters( 'widget_text_content', $text, $instance, $this ); + /** + * Filters the content of the Text widget to apply changes expected from the visual (TinyMCE) editor. + * + * By default a subset of the_content filters are applied, including wpautop and wptexturize. + * + * @since 4.8.0 + * + * @param string $text The widget content. + * @param array $instance Array of settings for the current widget. + * @param WP_Widget_Text $this Current Text widget instance. + */ + $text = apply_filters( 'widget_text_content', $text, $instance, $this ); - } elseif ( $instance['filter'] ) { - $text = wpautop( $text ); // Back-compat for instances prior to 4.8. - } + } elseif ( ! empty( $instance['filter'] ) ) { + $text = wpautop( $text ); // Back-compat for instances prior to 4.8. } // Undo temporary upgrade of the plugin-supplied shortcode handling. @@ -271,7 +278,15 @@ class WP_Widget_Text extends WP_Widget { * @return array Settings to save or bool false to cancel saving. */ public function update( $new_instance, $old_instance ) { + $new_instance = wp_parse_args( $new_instance, array( + 'title' => '', + 'text' => '', + 'filter' => false, // For back-compat. + 'visual' => null, // Must be explicitly defined. + ) ); + $instance = $old_instance; + $instance['title'] = sanitize_text_field( $new_instance['title'] ); if ( current_user_can( 'unfiltered_html' ) ) { $instance['text'] = $new_instance['text']; @@ -279,20 +294,23 @@ class WP_Widget_Text extends WP_Widget { $instance['text'] = wp_kses_post( $new_instance['text'] ); } - /* - * If the Text widget is in legacy mode, then a hidden input will indicate this - * and the new content value for the filter prop will by bypassed. Otherwise, - * re-use legacy 'filter' (wpautop) property to now indicate content filters will always apply. - * Prior to 4.8, this is a boolean value used to indicate whether or not wpautop should be - * applied. By re-using this property, downgrading WordPress from 4.8 to 4.7 will ensure - * that the content for Text widgets created with TinyMCE will continue to get wpautop. - */ - if ( isset( $new_instance['legacy'] ) || isset( $old_instance['legacy'] ) || ( isset( $new_instance['filter'] ) && 'content' !== $new_instance['filter'] ) ) { - $instance['filter'] = ! empty( $new_instance['filter'] ); - $instance['legacy'] = true; - } else { - $instance['filter'] = 'content'; - unset( $instance['legacy'] ); + $instance['filter'] = ! empty( $new_instance['filter'] ); + + // Upgrade 4.8.0 format. + if ( isset( $old_instance['filter'] ) && 'content' === $old_instance['filter'] ) { + $instance['visual'] = true; + } + if ( 'content' === $new_instance['filter'] ) { + $instance['visual'] = true; + } + + if ( isset( $new_instance['visual'] ) ) { + $instance['visual'] = ! empty( $new_instance['visual'] ); + } + + // Filter is always true in visual mode. + if ( ! empty( $instance['visual'] ) ) { + $instance['filter'] = true; } return $instance; @@ -333,8 +351,10 @@ class WP_Widget_Text extends WP_Widget { is_legacy_instance( $instance ) ) : ?> + + - +

diff --git a/tests/phpunit/tests/widgets/custom-html-widget.php b/tests/phpunit/tests/widgets/custom-html-widget.php index dcd03d2007..35dac8462a 100644 --- a/tests/phpunit/tests/widgets/custom-html-widget.php +++ b/tests/phpunit/tests/widgets/custom-html-widget.php @@ -59,6 +59,14 @@ class Test_WP_Widget_Custom_HTML extends WP_UnitTestCase { 'content' => $content, ); + // Convert Custom HTML widget instance into Text widget instance data. + $text_widget_instance = array_merge( $instance, array( + 'text' => $instance['content'], + 'filter' => false, + 'visual' => false, + ) ); + unset( $text_widget_instance['content'] ); + update_option( 'use_balanceTags', 0 ); add_filter( 'widget_custom_html_content', array( $this, 'filter_widget_custom_html_content' ), 5, 3 ); add_filter( 'widget_text', array( $this, 'filter_widget_text' ), 10, 3 ); @@ -75,11 +83,11 @@ class Test_WP_Widget_Custom_HTML extends WP_UnitTestCase { $this->assertNotContains( '

', $output ); $this->assertNotContains( '
', $output ); $this->assertNotContains( '', $output ); - $this->assertEquals( $instance, $this->widget_text_args[1] ); + $this->assertEquals( $text_widget_instance, $this->widget_text_args[1] ); $this->assertEquals( $instance, $this->widget_custom_html_content_args[1] ); $this->assertSame( $widget, $this->widget_text_args[2] ); $this->assertSame( $widget, $this->widget_custom_html_content_args[2] ); - remove_filter( 'widget_custom_html_content', array( $this, 'filter_widget_custom_html_content' ), 5, 3 ); + remove_filter( 'widget_custom_html_content', array( $this, 'filter_widget_custom_html_content' ), 5 ); remove_filter( 'widget_text', array( $this, 'filter_widget_text' ), 10 ); update_option( 'use_balanceTags', 1 ); diff --git a/tests/phpunit/tests/widgets/text-widget.php b/tests/phpunit/tests/widgets/text-widget.php index 764b4eaeac..c65e2e0f5c 100644 --- a/tests/phpunit/tests/widgets/text-widget.php +++ b/tests/phpunit/tests/widgets/text-widget.php @@ -82,17 +82,18 @@ class Test_WP_Widget_Text extends WP_UnitTestCase { 'before_widget' => '

', 'after_widget' => "
\n", ); + + add_filter( 'widget_text_content', array( $this, 'filter_widget_text_content' ), 5, 3 ); + add_filter( 'widget_text', array( $this, 'filter_widget_text' ), 5, 3 ); + + // Test with filter=false, implicit legacy mode. + $this->widget_text_content_args = null; + ob_start(); $instance = array( 'title' => 'Foo', 'text' => $text, 'filter' => false, ); - - add_filter( 'widget_text_content', array( $this, 'filter_widget_text_content' ), 5, 3 ); - add_filter( 'widget_text', array( $this, 'filter_widget_text' ), 5, 3 ); - - // Test with filter=false. - ob_start(); $widget->widget( $args, $instance ); $output = ob_get_clean(); $this->assertNotContains( '

', $output ); @@ -102,8 +103,13 @@ class Test_WP_Widget_Text extends WP_UnitTestCase { $this->assertContains( '[filter:widget_text]', $output ); $this->assertNotContains( '[filter:widget_text_content]', $output ); - // Test with filter=true. - $instance['filter'] = true; + // Test with filter=true, implicit legacy mode. + $this->widget_text_content_args = null; + $instance = array( + 'title' => 'Foo', + 'text' => $text, + 'filter' => true, + ); ob_start(); $widget->widget( $args, $instance ); $output = ob_get_clean(); @@ -117,22 +123,97 @@ class Test_WP_Widget_Text extends WP_UnitTestCase { $this->assertContains( '[filter:widget_text]', $output ); $this->assertNotContains( '[filter:widget_text_content]', $output ); - // Test with filter=content, the upgraded widget. - $instance['filter'] = 'content'; + // Test with filter=content, the upgraded widget, in 4.8.0 only. + $this->widget_text_content_args = null; + $instance = array( + 'title' => 'Foo', + 'text' => $text, + 'filter' => 'content', + ); + $expected_instance = array_merge( $instance, array( + 'filter' => true, + 'visual' => true, + ) ); ob_start(); $widget->widget( $args, $instance ); $output = ob_get_clean(); $this->assertContains( '

', $output ); $this->assertContains( '
', $output ); $this->assertCount( 3, $this->widget_text_args ); - $this->assertEquals( $instance['text'], $this->widget_text_args[0] ); - $this->assertEquals( $instance, $this->widget_text_args[1] ); + $this->assertEquals( $expected_instance['text'], $this->widget_text_args[0] ); + $this->assertEquals( $expected_instance, $this->widget_text_args[1] ); $this->assertEquals( $widget, $this->widget_text_args[2] ); $this->assertCount( 3, $this->widget_text_content_args ); - $this->assertEquals( $instance['text'] . '[filter:widget_text]', $this->widget_text_content_args[0] ); - $this->assertEquals( $instance, $this->widget_text_content_args[1] ); + $this->assertEquals( $expected_instance['text'] . '[filter:widget_text]', $this->widget_text_content_args[0] ); + $this->assertEquals( $expected_instance, $this->widget_text_content_args[1] ); $this->assertEquals( $widget, $this->widget_text_content_args[2] ); - $this->assertContains( wpautop( $instance['text'] . '[filter:widget_text][filter:widget_text_content]' ), $output ); + $this->assertContains( wpautop( $expected_instance['text'] . '[filter:widget_text][filter:widget_text_content]' ), $output ); + + // Test with filter=true&visual=true, the upgraded widget, in 4.8.1 and above. + $this->widget_text_content_args = null; + $instance = array( + 'title' => 'Foo', + 'text' => $text, + 'filter' => true, + 'visual' => true, + ); + $expected_instance = $instance; + ob_start(); + $widget->widget( $args, $instance ); + $output = ob_get_clean(); + $this->assertContains( '

', $output ); + $this->assertContains( '
', $output ); + $this->assertCount( 3, $this->widget_text_args ); + $this->assertEquals( $expected_instance['text'], $this->widget_text_args[0] ); + $this->assertEquals( $expected_instance, $this->widget_text_args[1] ); + $this->assertEquals( $widget, $this->widget_text_args[2] ); + $this->assertCount( 3, $this->widget_text_content_args ); + $this->assertEquals( $expected_instance['text'] . '[filter:widget_text]', $this->widget_text_content_args[0] ); + $this->assertEquals( $expected_instance, $this->widget_text_content_args[1] ); + $this->assertEquals( $widget, $this->widget_text_content_args[2] ); + $this->assertContains( wpautop( $expected_instance['text'] . '[filter:widget_text][filter:widget_text_content]' ), $output ); + + // Test with filter=true&visual=true, the upgraded widget, in 4.8.1 and above. + $this->widget_text_content_args = null; + $instance = array( + 'title' => 'Foo', + 'text' => $text, + 'filter' => true, + 'visual' => false, + ); + $expected_instance = $instance; + ob_start(); + $widget->widget( $args, $instance ); + $output = ob_get_clean(); + $this->assertContains( '

', $output ); + $this->assertContains( '
', $output ); + $this->assertCount( 3, $this->widget_text_args ); + $this->assertEquals( $expected_instance['text'], $this->widget_text_args[0] ); + $this->assertEquals( $expected_instance, $this->widget_text_args[1] ); + $this->assertEquals( $widget, $this->widget_text_args[2] ); + $this->assertNull( $this->widget_text_content_args ); + $this->assertContains( wpautop( $expected_instance['text'] . '[filter:widget_text]' ), $output ); + + // Test with filter=false&visual=false, the upgraded widget, in 4.8.1 and above. + $this->widget_text_content_args = null; + $instance = array( + 'title' => 'Foo', + 'text' => $text, + 'filter' => false, + 'visual' => false, + ); + $expected_instance = $instance; + ob_start(); + $widget->widget( $args, $instance ); + $output = ob_get_clean(); + $this->assertNotContains( '

', $output ); + $this->assertNotContains( '
', $output ); + $this->assertCount( 3, $this->widget_text_args ); + $this->assertEquals( $expected_instance['text'], $this->widget_text_args[0] ); + $this->assertEquals( $expected_instance, $this->widget_text_args[1] ); + $this->assertEquals( $widget, $this->widget_text_args[2] ); + $this->assertNull( $this->widget_text_content_args ); + $this->assertContains( $expected_instance['text'] . '[filter:widget_text]', $output ); } /** @@ -250,14 +331,19 @@ class Test_WP_Widget_Text extends WP_UnitTestCase { ); $instance = array_merge( $base_instance, array( - 'legacy' => true, + 'visual' => false, ) ); - $this->assertTrue( $widget->is_legacy_instance( $instance ), 'Legacy when legacy prop is present.' ); + $this->assertTrue( $widget->is_legacy_instance( $instance ), 'Legacy when visual=false prop is present.' ); + + $instance = array_merge( $base_instance, array( + 'visual' => true, + ) ); + $this->assertFalse( $widget->is_legacy_instance( $instance ), 'Not legacy when visual=true prop is present.' ); $instance = array_merge( $base_instance, array( 'filter' => 'content', ) ); - $this->assertFalse( $widget->is_legacy_instance( $instance ), 'Not legacy when filter is explicitly content.' ); + $this->assertFalse( $widget->is_legacy_instance( $instance ), 'Not legacy when filter is explicitly content (in WP 4.8.0 only).' ); $instance = array_merge( $base_instance, array( 'text' => '', @@ -364,13 +450,14 @@ class Test_WP_Widget_Text extends WP_UnitTestCase { 'title' => 'Title', 'text' => 'Text', 'filter' => false, - 'legacy' => true, + 'visual' => false, ); $this->assertTrue( $widget->is_legacy_instance( $instance ) ); ob_start(); $widget->form( $instance ); $form = ob_get_clean(); - $this->assertContains( 'class="legacy"', $form ); + $this->assertContains( 'class="visual" type="hidden" value=""', $form ); + $this->assertNotContains( 'class="visual" type="hidden" value="1"', $form ); $instance = array( 'title' => 'Title', @@ -381,7 +468,33 @@ class Test_WP_Widget_Text extends WP_UnitTestCase { ob_start(); $widget->form( $instance ); $form = ob_get_clean(); - $this->assertNotContains( 'class="legacy"', $form ); + $this->assertContains( 'class="visual" type="hidden" value="1"', $form ); + $this->assertNotContains( 'class="visual" type="hidden" value=""', $form ); + + $instance = array( + 'title' => 'Title', + 'text' => 'Text', + 'filter' => true, + ); + $this->assertFalse( $widget->is_legacy_instance( $instance ) ); + ob_start(); + $widget->form( $instance ); + $form = ob_get_clean(); + $this->assertContains( 'class="visual" type="hidden" value="1"', $form ); + $this->assertNotContains( 'class="visual" type="hidden" value=""', $form ); + + $instance = array( + 'title' => 'Title', + 'text' => 'Text', + 'filter' => true, + 'visual' => true, + ); + $this->assertFalse( $widget->is_legacy_instance( $instance ) ); + ob_start(); + $widget->form( $instance ); + $form = ob_get_clean(); + $this->assertContains( 'class="visual" type="hidden" value="1"', $form ); + $this->assertNotContains( 'class="visual" type="hidden" value=""', $form ); } /** @@ -394,30 +507,30 @@ class Test_WP_Widget_Text extends WP_UnitTestCase { $instance = array( 'title' => "The\nTitle", 'text' => "The\n\nText", - 'filter' => 'content', + 'filter' => true, + 'visual' => true, ); wp_set_current_user( $this->factory()->user->create( array( 'role' => 'administrator', ) ) ); - // Should return valid instance in legacy mode since filter=false and there are line breaks. $expected = array( 'title' => sanitize_text_field( $instance['title'] ), 'text' => $instance['text'], - 'filter' => 'content', + 'filter' => true, + 'visual' => true, ); $result = $widget->update( $instance, array() ); $this->assertEquals( $expected, $result ); $this->assertTrue( ! empty( $expected['filter'] ), 'Expected filter prop to be truthy, to handle case where 4.8 is downgraded to 4.7.' ); - // Make sure KSES is applying as expected. add_filter( 'map_meta_cap', array( $this, 'grant_unfiltered_html_cap' ), 10, 2 ); $this->assertTrue( current_user_can( 'unfiltered_html' ) ); $instance['text'] = ''; $expected['text'] = $instance['text']; $result = $widget->update( $instance, array() ); - $this->assertEquals( $expected, $result ); + $this->assertEquals( $expected, $result, 'KSES should apply as expected.' ); remove_filter( 'map_meta_cap', array( $this, 'grant_unfiltered_html_cap' ) ); add_filter( 'map_meta_cap', array( $this, 'revoke_unfiltered_html_cap' ), 10, 2 ); @@ -425,7 +538,7 @@ class Test_WP_Widget_Text extends WP_UnitTestCase { $instance['text'] = ''; $expected['text'] = wp_kses_post( $instance['text'] ); $result = $widget->update( $instance, array() ); - $this->assertEquals( $expected, $result ); + $this->assertEquals( $expected, $result, 'KSES should not apply since user can unfiltered_html.' ); remove_filter( 'map_meta_cap', array( $this, 'revoke_unfiltered_html_cap' ), 10 ); } @@ -437,48 +550,150 @@ class Test_WP_Widget_Text extends WP_UnitTestCase { function test_update_legacy() { $widget = new WP_Widget_Text(); - // Updating a widget with explicit filter=true persists with legacy mode. + // -- + $instance = array( + 'title' => 'Legacy', + 'text' => 'Text', + 'filter' => false, + ); + $result = $widget->update( $instance, array() ); + $this->assertEquals( $instance, $result, 'Updating a widget without visual prop and explicit filter=false leaves visual prop absent' ); + + // -- $instance = array( 'title' => 'Legacy', 'text' => 'Text', 'filter' => true, ); $result = $widget->update( $instance, array() ); - $expected = array_merge( $instance, array( - 'legacy' => true, - 'filter' => true, - ) ); - $this->assertEquals( $expected, $result ); + $this->assertEquals( $instance, $result, 'Updating a widget without visual prop and explicit filter=true leaves legacy prop absent.' ); - // Updating a widget with explicit filter=false persists with legacy mode. - $instance['filter'] = false; - $result = $widget->update( $instance, array() ); - $expected = array_merge( $instance, array( - 'legacy' => true, + // -- + $instance = array( + 'title' => 'Legacy', + 'text' => 'Text', + 'visual' => true, + ); + $old_instance = array_merge( $instance, array( 'filter' => false, ) ); - $this->assertEquals( $expected, $result ); + $expected = array_merge( $instance, array( + 'filter' => true, + ) ); + $result = $widget->update( $instance, $old_instance ); + $this->assertEquals( $expected, $result, 'Updating a pre-existing widget with visual mode forces filter to be true.' ); - // Updating a widget in legacy form results in filter=false when checkbox not checked. - $instance['filter'] = true; + // -- + $instance = array( + 'title' => 'Legacy', + 'text' => 'Text', + 'filter' => true, + ); + $old_instance = array_merge( $instance, array( + 'visual' => true, + ) ); + $result = $widget->update( $instance, $old_instance ); + $expected = array_merge( $instance, array( + 'visual' => true, + ) ); + $this->assertEquals( $expected, $result, 'Updating a pre-existing visual widget retains visual mode when updated.' ); + + // -- + $instance = array( + 'title' => 'Legacy', + 'text' => 'Text', + ); + $old_instance = array_merge( $instance, array( + 'visual' => true, + ) ); + $result = $widget->update( $instance, $old_instance ); + $expected = array_merge( $instance, array( + 'visual' => true, + 'filter' => true, + ) ); + $this->assertEquals( $expected, $result, 'Updating a pre-existing visual widget retains visual=true and supplies missing filter=true.' ); + + // -- + $instance = array( + 'title' => 'Legacy', + 'text' => 'Text', + 'visual' => true, + ); + $expected = array_merge( $instance, array( + 'filter' => true, + ) ); + $result = $widget->update( $instance, array() ); + $this->assertEquals( $expected, $result, 'Updating a widget with explicit visual=true and absent filter prop causes filter to be set to true.' ); + + // -- + $instance = array( + 'title' => 'Legacy', + 'text' => 'Text', + 'visual' => false, + ); $result = $widget->update( $instance, array() ); $expected = array_merge( $instance, array( - 'legacy' => true, - 'filter' => true, + 'filter' => false, ) ); - $this->assertEquals( $expected, $result ); + $this->assertEquals( $expected, $result, 'Updating a widget in legacy mode results in filter=false as if checkbox not checked.' ); - // Updating a widget that previously had legacy form results in filter persisting. - unset( $instance['legacy'] ); - $instance['filter'] = true; - $result = $widget->update( $instance, array( - 'legacy' => true, - ) ); - $expected = array_merge( $instance, array( - 'legacy' => true, + // -- + $instance = array( + 'title' => 'Title', + 'text' => 'Text', + 'filter' => false, + ); + $old_instance = array_merge( $instance, array( + 'visual' => false, 'filter' => true, ) ); - $this->assertEquals( $expected, $result ); + $result = $widget->update( $instance, $old_instance ); + $expected = array_merge( $instance, array( + 'visual' => false, + 'filter' => false, + ) ); + $this->assertEquals( $expected, $result, 'Updating a widget that previously had legacy form results in filter allowed to be false.' ); + + // -- + $instance = array( + 'title' => 'Title', + 'text' => 'Text', + 'filter' => 'content', + ); + $result = $widget->update( $instance, array() ); + $expected = array_merge( $instance, array( + 'filter' => true, + 'visual' => true, + ) ); + $this->assertEquals( $expected, $result, 'Updating a widget that had \'content\' as its filter value persists non-legacy mode. This only existed in WP 4.8.0.' ); + + // -- + $instance = array( + 'title' => 'Title', + 'text' => 'Text', + ); + $old_instance = array_merge( $instance, array( + 'filter' => 'content', + ) ); + $result = $widget->update( $instance, $old_instance ); + $expected = array_merge( $instance, array( + 'visual' => true, + 'filter' => true, + ) ); + $this->assertEquals( $expected, $result, 'Updating a pre-existing widget with the filter=content prop in WP 4.8.0 upgrades to filter=true&visual=true.' ); + + // -- + $instance = array( + 'title' => 'Title', + 'text' => 'Text', + 'filter' => 'content', + ); + $result = $widget->update( $instance, array() ); + $expected = array_merge( $instance, array( + 'filter' => true, + 'visual' => true, + ) ); + $this->assertEquals( $expected, $result, 'Updating a widget with filter=content (from WP 4.8.0) upgrades to filter=true&visual=true.' ); } /**