From fd423f720ea97694ec1ff65d63704dca07924935 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Mon, 24 Jul 2017 22:54:34 +0000 Subject: [PATCH] Widgets: Rename Text widget's `legacy` mode to non-`visual` mode, restore boolean `filter` prop, and improve compatibility for `widget_text` filters applied in Custom HTML widget. Merges [41132] onto 4.8 branch. Amends [41050]. Props westonruter, obenland, timmydcrawford for testing. See #35243, #40951, #40907. Fixes #41394 for 4.8.1. Built from https://develop.svn.wordpress.org/branches/4.8@41133 git-svn-id: http://core.svn.wordpress.org/branches/4.8@40973 1a063a9b-81f0-0310-95a4-ce76da25c4cd --- wp-admin/js/widgets/text-widgets.js | 4 +- wp-admin/js/widgets/text-widgets.min.js | 2 +- wp-includes/default-widgets.php | 10 ++- wp-includes/version.php | 2 +- wp-includes/widgets/class-wp-widget-text.php | 94 ++++++++++++-------- 5 files changed, 70 insertions(+), 42 deletions(-) diff --git a/wp-admin/js/widgets/text-widgets.js b/wp-admin/js/widgets/text-widgets.js index 282090d585..692a0642c9 100644 --- a/wp-admin/js/widgets/text-widgets.js +++ b/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/wp-admin/js/widgets/text-widgets.min.js b/wp-admin/js/widgets/text-widgets.min.js index 3929130223..cd297973d5 100644 --- a/wp-admin/js/widgets/text-widgets.min.js +++ b/wp-admin/js/widgets/text-widgets.min.js @@ -1 +1 @@ -wp.textWidgets=function(a){"use strict";var b={dismissedPointers:[]};return b.TextWidgetControl=Backbone.View.extend({events:{},initialize:function(b){var c=this;if(!b.el)throw new Error("Missing options.el");if(!b.syncContainer)throw new Error("Missing options.syncContainer");Backbone.View.prototype.initialize.call(c,b),c.syncContainer=b.syncContainer,c.$el.addClass("text-widget-fields"),c.$el.html(wp.template("widget-text-control-fields")),c.customHtmlWidgetPointer=c.$el.find(".wp-pointer.custom-html-widget-pointer"),c.customHtmlWidgetPointer.length&&(c.customHtmlWidgetPointer.find(".close").on("click",function(b){b.preventDefault(),c.customHtmlWidgetPointer.hide(),a("#"+c.fields.text.attr("id")+"-html").focus(),c.dismissPointers(["text_widget_custom_html"])}),c.customHtmlWidgetPointer.find(".add-widget").on("click",function(a){a.preventDefault(),c.customHtmlWidgetPointer.hide(),c.openAvailableWidgetsPanel()})),c.pasteHtmlPointer=c.$el.find(".wp-pointer.paste-html-pointer"),c.pasteHtmlPointer.length&&c.pasteHtmlPointer.find(".close").on("click",function(a){a.preventDefault(),c.pasteHtmlPointer.hide(),c.editor.focus(),c.dismissPointers(["text_widget_custom_html","text_widget_paste_html"])}),c.fields={title:c.$el.find(".title"),text:c.$el.find(".text")},_.each(c.fields,function(a,b){a.on("input change",function(){var d=c.syncContainer.find("input[type=hidden]."+b);d.val()!==a.val()&&(d.val(a.val()),d.trigger("change"))}),a.val(c.syncContainer.find("input[type=hidden]."+b).val())})},dismissPointers:function(a){_.each(a,function(a){wp.ajax.post("dismiss-wp-pointer",{pointer:a}),b.dismissedPointers.push(a)})},openAvailableWidgetsPanel:function(){var a;wp.customize.section.each(function(b){b.extended(wp.customize.Widgets.SidebarSection)&&b.expanded()&&(a=wp.customize.control("sidebars_widgets["+b.params.sidebarId+"]"))}),a&&setTimeout(function(){wp.customize.Widgets.availableWidgetsPanel.open(a),wp.customize.Widgets.availableWidgetsPanel.$search.val("HTML").trigger("keyup")})},updateFields:function(){var a,b=this;b.fields.title.is(document.activeElement)||(a=b.syncContainer.find("input[type=hidden].title"),b.fields.title.val(a.val())),a=b.syncContainer.find("input[type=hidden].text"),b.fields.text.is(":visible")?b.fields.text.is(document.activeElement)||b.fields.text.val(a.val()):b.editor&&!b.editorFocused&&a.val()!==b.fields.text.val()&&b.editor.setContent(wp.editor.autop(a.val()))},initializeEditor:function(){function c(){var e,k,l;if(document.getElementById(d)){if("undefined"==typeof window.tinymce)return void wp.editor.initialize(d,{quicktags:!0});if(tinymce.get(d)&&(i=tinymce.get(d).isHidden(),wp.editor.remove(d)),wp.editor.initialize(d,{tinymce:{wpautop:!0},quicktags:!0}),l=function(b){b.show(),b.find(".close").focus(),wp.a11y.speak(b.find("h3, p").map(function(){return a(this).text()}).get().join("\n\n"))},e=window.tinymce.get(d),!e)throw new Error("Failed to initialize editor");k=function(){a(e.getWin()).on("unload",function(){_.defer(c)}),i&&switchEditors.go(d,"html"),a("#"+d+"-html").on("click",function(){g.pasteHtmlPointer.hide(),-1===b.dismissedPointers.indexOf("text_widget_custom_html")&&l(g.customHtmlWidgetPointer)}),a("#"+d+"-tmce").on("click",function(){g.customHtmlWidgetPointer.hide()}),e.on("pastepreprocess",function(a){var c=a.content;-1===b.dismissedPointers.indexOf("text_widget_paste_html")&&c&&/<\w+.*?>/.test(c)&&_.delay(function(){l(g.pasteHtmlPointer)},250)})},e.initialized?k():e.on("init",k),g.editorFocused=!1,e.on("focus",function(){g.editorFocused=!0}),e.on("paste",function(){e.setDirty(!0),f()}),e.on("NodeChange",function(){j=!0}),e.on("NodeChange",_.debounce(f,h)),e.on("blur hide",function(){g.editorFocused=!1,f()}),g.editor=e}}var d,e,f,g=this,h=1e3,i=!1,j=!1;e=g.fields.text,d=e.attr("id"),f=function(){var a=300;g.editor.isDirty()&&(wp.customize&&wp.customize.state&&(wp.customize.state("processing").set(wp.customize.state("processing").get()+1),_.delay(function(){wp.customize.state("processing").set(wp.customize.state("processing").get()-1)},a)),g.editor.isHidden()||g.editor.save()),j&&(e.trigger("change"),j=!1)},g.syncContainer.closest(".widget").find("[name=savewidget]:first").on("click",function(){f()}),c()}}),b.widgetControls={},b.handleWidgetAdded=function(c,d){var e,f,g,h,i,j,k,l,m=50;e=d.find("> .widget-inside > .form, > .widget-inside > form"),f=e.find("> .id_base").val(),"text"===f&&(h=e.find(".widget-id").val(),b.widgetControls[h]||e.find(".legacy").length>0||(k=a("
"),l=d.find(".widget-content:first"),l.before(k),g=new b.TextWidgetControl({el:k,syncContainer:l}),b.widgetControls[h]=g,i=d.parent(),(j=function(){i.is(":animated")?setTimeout(j,m):g.initializeEditor()})()))},b.setupAccessibleMode=function(){var c,d,e,f,g;c=a(".editwidget > form"),0!==c.length&&(d=c.find("> .widget-control-actions > .id_base").val(),"text"===d&&(c.find(".legacy").length>0||(f=a("
"),g=c.find("> .widget-inside"),g.before(f),e=new b.TextWidgetControl({el:f,syncContainer:g}),e.initializeEditor())))},b.handleWidgetUpdated=function(a,c){var d,e,f,g;d=c.find("> .widget-inside > .form, > .widget-inside > form"),g=d.find("> .id_base").val(),"text"===g&&(e=d.find("> .widget-id").val(),f=b.widgetControls[e],f&&f.updateFields())},b.init=function(){var c=a(document);c.on("widget-added",b.handleWidgetAdded),c.on("widget-synced widget-updated",b.handleWidgetUpdated),a(function(){var c;"widgets"===window.pagenow&&(c=a(".widgets-holder-wrap:not(#available-widgets)").find("div.widget"),c.one("click.toggle-widget-expanded",function(){var c=a(this);b.handleWidgetAdded(new jQuery.Event("widget-added"),c)}),a(window).on("load",function(){b.setupAccessibleMode()}))})},b}(jQuery); \ No newline at end of file +wp.textWidgets=function(a){"use strict";var b={dismissedPointers:[]};return b.TextWidgetControl=Backbone.View.extend({events:{},initialize:function(b){var c=this;if(!b.el)throw new Error("Missing options.el");if(!b.syncContainer)throw new Error("Missing options.syncContainer");Backbone.View.prototype.initialize.call(c,b),c.syncContainer=b.syncContainer,c.$el.addClass("text-widget-fields"),c.$el.html(wp.template("widget-text-control-fields")),c.customHtmlWidgetPointer=c.$el.find(".wp-pointer.custom-html-widget-pointer"),c.customHtmlWidgetPointer.length&&(c.customHtmlWidgetPointer.find(".close").on("click",function(b){b.preventDefault(),c.customHtmlWidgetPointer.hide(),a("#"+c.fields.text.attr("id")+"-html").focus(),c.dismissPointers(["text_widget_custom_html"])}),c.customHtmlWidgetPointer.find(".add-widget").on("click",function(a){a.preventDefault(),c.customHtmlWidgetPointer.hide(),c.openAvailableWidgetsPanel()})),c.pasteHtmlPointer=c.$el.find(".wp-pointer.paste-html-pointer"),c.pasteHtmlPointer.length&&c.pasteHtmlPointer.find(".close").on("click",function(a){a.preventDefault(),c.pasteHtmlPointer.hide(),c.editor.focus(),c.dismissPointers(["text_widget_custom_html","text_widget_paste_html"])}),c.fields={title:c.$el.find(".title"),text:c.$el.find(".text")},_.each(c.fields,function(a,b){a.on("input change",function(){var d=c.syncContainer.find("input[type=hidden]."+b);d.val()!==a.val()&&(d.val(a.val()),d.trigger("change"))}),a.val(c.syncContainer.find("input[type=hidden]."+b).val())})},dismissPointers:function(a){_.each(a,function(a){wp.ajax.post("dismiss-wp-pointer",{pointer:a}),b.dismissedPointers.push(a)})},openAvailableWidgetsPanel:function(){var a;wp.customize.section.each(function(b){b.extended(wp.customize.Widgets.SidebarSection)&&b.expanded()&&(a=wp.customize.control("sidebars_widgets["+b.params.sidebarId+"]"))}),a&&setTimeout(function(){wp.customize.Widgets.availableWidgetsPanel.open(a),wp.customize.Widgets.availableWidgetsPanel.$search.val("HTML").trigger("keyup")})},updateFields:function(){var a,b=this;b.fields.title.is(document.activeElement)||(a=b.syncContainer.find("input[type=hidden].title"),b.fields.title.val(a.val())),a=b.syncContainer.find("input[type=hidden].text"),b.fields.text.is(":visible")?b.fields.text.is(document.activeElement)||b.fields.text.val(a.val()):b.editor&&!b.editorFocused&&a.val()!==b.fields.text.val()&&b.editor.setContent(wp.editor.autop(a.val()))},initializeEditor:function(){function c(){var e,k,l;if(document.getElementById(d)){if("undefined"==typeof window.tinymce)return void wp.editor.initialize(d,{quicktags:!0});if(tinymce.get(d)&&(i=tinymce.get(d).isHidden(),wp.editor.remove(d)),wp.editor.initialize(d,{tinymce:{wpautop:!0},quicktags:!0}),l=function(b){b.show(),b.find(".close").focus(),wp.a11y.speak(b.find("h3, p").map(function(){return a(this).text()}).get().join("\n\n"))},e=window.tinymce.get(d),!e)throw new Error("Failed to initialize editor");k=function(){a(e.getWin()).on("unload",function(){_.defer(c)}),i&&switchEditors.go(d,"html"),a("#"+d+"-html").on("click",function(){g.pasteHtmlPointer.hide(),-1===b.dismissedPointers.indexOf("text_widget_custom_html")&&l(g.customHtmlWidgetPointer)}),a("#"+d+"-tmce").on("click",function(){g.customHtmlWidgetPointer.hide()}),e.on("pastepreprocess",function(a){var c=a.content;-1===b.dismissedPointers.indexOf("text_widget_paste_html")&&c&&/<\w+.*?>/.test(c)&&_.delay(function(){l(g.pasteHtmlPointer)},250)})},e.initialized?k():e.on("init",k),g.editorFocused=!1,e.on("focus",function(){g.editorFocused=!0}),e.on("paste",function(){e.setDirty(!0),f()}),e.on("NodeChange",function(){j=!0}),e.on("NodeChange",_.debounce(f,h)),e.on("blur hide",function(){g.editorFocused=!1,f()}),g.editor=e}}var d,e,f,g=this,h=1e3,i=!1,j=!1;e=g.fields.text,d=e.attr("id"),f=function(){var a=300;g.editor.isDirty()&&(wp.customize&&wp.customize.state&&(wp.customize.state("processing").set(wp.customize.state("processing").get()+1),_.delay(function(){wp.customize.state("processing").set(wp.customize.state("processing").get()-1)},a)),g.editor.isHidden()||g.editor.save()),j&&(e.trigger("change"),j=!1)},g.syncContainer.closest(".widget").find("[name=savewidget]:first").on("click",function(){f()}),c()}}),b.widgetControls={},b.handleWidgetAdded=function(c,d){var e,f,g,h,i,j,k,l,m=50;e=d.find("> .widget-inside > .form, > .widget-inside > form"),f=e.find("> .id_base").val(),"text"===f&&(h=e.find(".widget-id").val(),b.widgetControls[h]||e.find(".visual").val()&&(k=a("
"),l=d.find(".widget-content:first"),l.before(k),g=new b.TextWidgetControl({el:k,syncContainer:l}),b.widgetControls[h]=g,i=d.parent(),(j=function(){i.is(":animated")?setTimeout(j,m):g.initializeEditor()})()))},b.setupAccessibleMode=function(){var c,d,e,f,g;c=a(".editwidget > form"),0!==c.length&&(d=c.find("> .widget-control-actions > .id_base").val(),"text"===d&&c.find(".visual").val()&&(f=a("
"),g=c.find("> .widget-inside"),g.before(f),e=new b.TextWidgetControl({el:f,syncContainer:g}),e.initializeEditor()))},b.handleWidgetUpdated=function(a,c){var d,e,f,g;d=c.find("> .widget-inside > .form, > .widget-inside > form"),g=d.find("> .id_base").val(),"text"===g&&(e=d.find("> .widget-id").val(),f=b.widgetControls[e],f&&f.updateFields())},b.init=function(){var c=a(document);c.on("widget-added",b.handleWidgetAdded),c.on("widget-synced widget-updated",b.handleWidgetUpdated),a(function(){var c;"widgets"===window.pagenow&&(c=a(".widgets-holder-wrap:not(#available-widgets)").find("div.widget"),c.one("click.toggle-widget-expanded",function(){var c=a(this);b.handleWidgetAdded(new jQuery.Event("widget-added"),c)}),a(window).on("load",function(){b.setupAccessibleMode()}))})},b}(jQuery); \ No newline at end of file diff --git a/wp-includes/default-widgets.php b/wp-includes/default-widgets.php index e649cbf689..cf3ca1ffc3 100644 --- a/wp-includes/default-widgets.php +++ b/wp-includes/default-widgets.php @@ -119,8 +119,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/wp-includes/version.php b/wp-includes/version.php index 32f08faae9..45f6f07266 100644 --- a/wp-includes/version.php +++ b/wp-includes/version.php @@ -4,7 +4,7 @@ * * @global string $wp_version */ -$wp_version = '4.8.1-beta1-41130'; +$wp_version = '4.8.1-beta1-41133'; /** * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema. diff --git a/wp-includes/widgets/class-wp-widget-text.php b/wp-includes/widgets/class-wp-widget-text.php index 2297d2bee2..912c6181bb 100644 --- a/wp-includes/widgets/class-wp-widget-text.php +++ b/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 ) ) : ?> + + - +