From 84d2c511537c70ea7063d5a2d31ce419a23c0450 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Sun, 10 Sep 2017 06:33:44 +0000 Subject: [PATCH] Widgets: Add shortcode support inside Text widgets. * Used now in core to facilitate displaying inserted media. See #40854. * The `[embed]` shortcode is not supported because there is no post context for caching oEmbed responses. This depends on #34115. * Add `do_shortcode()` to the `widget_text_content` filter in the same way it is added for `the_content` at priority 11, with `shortcode_unautop()` called at priority 10 after `wpautop()`. * For Text widget in legacy mode, manually apply `do_shortcode()` (and `shortcode_unautop()` if auto-paragraph checked) if the core-added `widget_text_content` filter remains, unless a plugin added `do_shortcode()` to `widget_text` to prevent applying shortcodes twice. * Ensure that global `$post` is `null` while filters apply in the Text widget so shortcode handlers won't run with unexpected contexts. Props westonruter, nacin, aaroncampbell. See #40854, #34115. Fixes #10457. Built from https://develop.svn.wordpress.org/trunk@41361 git-svn-id: http://core.svn.wordpress.org/trunk@41194 1a063a9b-81f0-0310-95a4-ce76da25c4cd --- wp-includes/default-filters.php | 2 + wp-includes/version.php | 2 +- wp-includes/widgets/class-wp-widget-text.php | 54 +++++++++++++++----- 3 files changed, 45 insertions(+), 13 deletions(-) diff --git a/wp-includes/default-filters.php b/wp-includes/default-filters.php index a196f4ff19..0ed4be9056 100644 --- a/wp-includes/default-filters.php +++ b/wp-includes/default-filters.php @@ -169,6 +169,8 @@ add_filter( 'widget_text_content', 'capital_P_dangit', 11 ); add_filter( 'widget_text_content', 'wptexturize' ); add_filter( 'widget_text_content', 'convert_smilies', 20 ); add_filter( 'widget_text_content', 'wpautop' ); +add_filter( 'widget_text_content', 'shortcode_unautop' ); +add_filter( 'widget_text_content', 'do_shortcode', 11 ); // Runs after wpautop(); note that $post global will be null when shortcodes run. add_filter( 'date_i18n', 'wp_maybe_decline_date' ); diff --git a/wp-includes/version.php b/wp-includes/version.php index fb117da84d..a42c3e44a3 100644 --- a/wp-includes/version.php +++ b/wp-includes/version.php @@ -4,7 +4,7 @@ * * @global string $wp_version */ -$wp_version = '4.9-alpha-41360'; +$wp_version = '4.9-alpha-41361'; /** * 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 a79e0daa6c..4c8fa9b088 100644 --- a/wp-includes/widgets/class-wp-widget-text.php +++ b/wp-includes/widgets/class-wp-widget-text.php @@ -183,11 +183,14 @@ class WP_Widget_Text extends WP_Widget { * * @since 2.8.0 * + * @global WP_Post $post + * * @param array $args Display arguments including 'before_title', 'after_title', * 'before_widget', and 'after_widget'. * @param array $instance Settings for the current Text widget instance. */ public function widget( $args, $instance ) { + global $post; /** This filter is documented in wp-includes/widgets/class-wp-widget-pages.php */ $title = apply_filters( 'widget_title', empty( $instance['title'] ) ? '' : $instance['title'], $instance, $this->id_base ); @@ -205,16 +208,22 @@ class WP_Widget_Text extends WP_Widget { } /* - * Just-in-time temporarily upgrade Visual Text widget shortcode handling - * (with support added by plugin) from the widget_text filter to - * widget_text_content:11 to prevent wpautop from corrupting HTML output - * added by the shortcode. + * Suspend legacy plugin-supplied do_shortcode() for 'widget_text' filter for the visual Text widget to prevent + * shortcodes being processed twice. Now do_shortcode() is added to the 'widget_text_content' filter in core itself + * and it applies after wpautop() to prevent corrupting HTML output added by the shortcode. When do_shortcode() is + * added to 'widget_text_content' then do_shortcode() will be manually called when in legacy mode as well. */ $widget_text_do_shortcode_priority = has_filter( 'widget_text', 'do_shortcode' ); - $should_upgrade_shortcode_handling = ( $is_visual_text_widget && false !== $widget_text_do_shortcode_priority ); - if ( $should_upgrade_shortcode_handling ) { + $should_suspend_legacy_shortcode_support = ( $is_visual_text_widget && false !== $widget_text_do_shortcode_priority ); + if ( $should_suspend_legacy_shortcode_support ) { remove_filter( 'widget_text', 'do_shortcode', $widget_text_do_shortcode_priority ); - add_filter( 'widget_text_content', 'do_shortcode', 11 ); + } + + // Nullify the $post global during widget rendering to prevent shortcodes from running with the unexpected context. + $suspended_post = null; + if ( isset( $post ) ) { + $suspended_post = $post; + $post = null; } /** @@ -244,14 +253,35 @@ class WP_Widget_Text extends WP_Widget { * @param WP_Widget_Text $this Current Text widget instance. */ $text = apply_filters( 'widget_text_content', $text, $instance, $this ); + } else { + // Now in legacy mode, add paragraphs and line breaks when checkbox is checked. + if ( ! empty( $instance['filter'] ) ) { + $text = wpautop( $text ); + } - } elseif ( ! empty( $instance['filter'] ) ) { - $text = wpautop( $text ); // Back-compat for instances prior to 4.8. + /* + * Manually do shortcodes on the content when the core-added filter is present. It is added by default + * in core by adding do_shortcode() to the 'widget_text_content' filter to apply after wpautop(). + * Since the legacy Text widget runs wpautop() after 'widget_text' filters are applied, the widget in + * legacy mode here manually applies do_shortcode() on the content unless the default + * core filter for 'widget_text_content' has been removed, or if do_shortcode() has already + * been applied via a plugin adding do_shortcode() to 'widget_text' filters. + */ + if ( has_filter( 'widget_text_content', 'do_shortcode' ) && ! $widget_text_do_shortcode_priority ) { + if ( ! empty( $instance['filter'] ) ) { + $text = shortcode_unautop( $text ); + } + $text = do_shortcode( $text ); + } } - // Undo temporary upgrade of the plugin-supplied shortcode handling. - if ( $should_upgrade_shortcode_handling ) { - remove_filter( 'widget_text_content', 'do_shortcode', 11 ); + // Restore post global. + if ( isset( $suspended_post ) ) { + $post = $suspended_post; + } + + // Undo suspension of legacy plugin-supplied shortcode handling. + if ( $should_suspend_legacy_shortcode_support ) { add_filter( 'widget_text', 'do_shortcode', $widget_text_do_shortcode_priority ); }