From 7e4e9f1ce7ef3d29228873b758f37ebdc8a2d735 Mon Sep 17 00:00:00 2001 From: Gary Pendergast Date: Tue, 4 Oct 2016 00:38:45 +0000 Subject: [PATCH] Shortcodes: Add a `do_shortcode_tag` filter. The addition of the `pre_do_shortcode_tag` in [38506] allows plugins to short-circuit the shortcode execution process, which is particularly helpful for caching expensive shortcodes. The `do_shortcode_tag` is the corresponding part of that system - when a shortcode hasn't been executed previously, there needs to be a clean method of populating the cache. Props flixos90. Fixes #32790. git-svn-id: https://develop.svn.wordpress.org/trunk@38713 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/shortcodes.php | 22 ++++++---- tests/phpunit/tests/shortcode.php | 69 ++++++++++++++++++++++++++++++- 2 files changed, 83 insertions(+), 8 deletions(-) diff --git a/src/wp-includes/shortcodes.php b/src/wp-includes/shortcodes.php index b2aad3dc4d..f0523622cc 100644 --- a/src/wp-includes/shortcodes.php +++ b/src/wp-includes/shortcodes.php @@ -339,13 +339,21 @@ function do_shortcode_tag( $m ) { return $return; } - if ( isset( $m[5] ) ) { - // enclosing tag - extra parameter - return $m[1] . call_user_func( $shortcode_tags[$tag], $attr, $m[5], $tag ) . $m[6]; - } else { - // self-closing tag - return $m[1] . call_user_func( $shortcode_tags[$tag], $attr, null, $tag ) . $m[6]; - } + $content = isset( $m[5] ) ? $m[5] : null; + + $output = $m[1] . call_user_func( $shortcode_tags[ $tag ], $attr, $content, $tag ) . $m[6]; + + /** + * Filters the output created by a shortcode callback. + * + * @since 4.7.0 + * + * @param string $output Shortcode output. + * @param string $tag Shortcode name. + * @param array $attr Shortcode attributes array, + * @param array $m Regular expression match array. + */ + return apply_filters( 'do_shortcode_tag', $output, $tag, $attr, $m ); } /** diff --git a/tests/phpunit/tests/shortcode.php b/tests/phpunit/tests/shortcode.php index f5e8ae2d9c..e807f9539e 100644 --- a/tests/phpunit/tests/shortcode.php +++ b/tests/phpunit/tests/shortcode.php @@ -719,7 +719,7 @@ EOF; remove_filter( 'pre_do_shortcode_tag', array( $this, '_filter_pre_do_shortcode_tag_attr' ), 12, 4 ); remove_filter( 'pre_do_shortcode_tag', array( $this, '_filter_pre_do_shortcode_tag_p11' ), 11 ); remove_filter( 'pre_do_shortcode_tag', array( $this, '_filter_pre_do_shortcode_tag_bar' ) ); - remove_shortcode( $str, array( $this, '_shortcode_pre_do_shortcode_tag' ) ); + remove_shortcode( $str ); } public function _shortcode_pre_do_shortcode_tag( $atts = array(), $content = '' ) { @@ -743,4 +743,71 @@ EOF; ); return wp_json_encode( $arr ); } + + /** + * @ticket 32790 + */ + public function test_do_shortcode_tag_filter() { + // does nothing if no filters are set up + $str = 'do_shortcode_tag'; + add_shortcode( $str, array( $this, '_shortcode_do_shortcode_tag' ) ); + $result_nofilter = do_shortcode( "[{$str}]" ); + $this->assertSame( 'foo', $result_nofilter ); + + // modify output with filter + add_filter( 'do_shortcode_tag', array( $this, '_filter_do_shortcode_tag_replace' ) ); + $result_filter = do_shortcode( "[{$str}]" ); + $this->assertSame( 'fee', $result_filter ); + + // respect priority + add_filter( 'do_shortcode_tag', array( $this, '_filter_do_shortcode_tag_generate' ), 11 ); + $result_priority = do_shortcode( "[{$str}]" ); + $this->assertSame( 'foobar', $result_priority ); + + // pass arguments + $arr = array( + 'return' => 'foobar', + 'key' => $str, + 'atts' => array( 'a' => 'b', 'c' => 'd' ), + 'm' => array( + "[{$str} a='b' c='d']", + "", + $str, + " a='b' c='d'", + "", + "", + "", + ), + ); + add_filter( 'do_shortcode_tag', array( $this, '_filter_do_shortcode_tag_attr' ), 12, 4 ); + $result_atts = do_shortcode( "[{$str} a='b' c='d']" ); + $this->assertSame( wp_json_encode( $arr ), $result_atts ); + + remove_filter( 'do_shortcode_tag', array( $this, '_filter_do_shortcode_tag_attr' ), 12 ); + remove_filter( 'do_shortcode_tag', array( $this, '_filter_do_shortcode_tag_generate' ), 11 ); + remove_filter( 'do_shortcode_tag', array( $this, '_filter_do_shortcode_tag_replace' ) ); + remove_shortcode( $str ); + } + + public function _shortcode_do_shortcode_tag( $atts = array(), $content = '' ) { + return 'foo'; + } + + public function _filter_do_shortcode_tag_replace( $return ) { + return str_replace( 'oo', 'ee', $return ); + } + + public function _filter_do_shortcode_tag_generate( $return ) { + return 'foobar'; + } + + public function _filter_do_shortcode_tag_attr( $return, $key, $atts, $m ){ + $arr = array( + 'return' => $return, + 'key' => $key, + 'atts' => $atts, + 'm' => $m, + ); + return wp_json_encode( $arr ); + } }