diff --git a/src/wp-includes/class-oembed.php b/src/wp-includes/class-oembed.php index ef36683bc0..6bdc925e63 100644 --- a/src/wp-includes/class-oembed.php +++ b/src/wp-includes/class-oembed.php @@ -315,10 +315,32 @@ class WP_oEmbed { * @return false|string False on failure, otherwise the UNSANITIZED (and potentially unsafe) HTML that should be used to embed. */ public function get_html( $url, $args = '' ) { + /** + * Filters the oEmbed result before any HTTP requests are made. + * + * This allows one to short-circuit the default logic, perhaps by + * replacing it with a routine that is more optimal for your setup. + * + * Passing a non-null value to the filter will effectively short-circuit retrieval, + * returning the passed value instead. + * + * @since 4.5.3 + * + * @param null|string $result The UNSANITIZED (and potentially unsafe) HTML that should be used to embed. Default null. + * @param string $url The URL to the content that should be attempted to be embedded. + * @param array $args Optional. Arguments, usually passed from a shortcode. Default empty. + */ + $pre = apply_filters( 'pre_oembed_result', null, $url, $args ); + + if ( null !== $pre ) { + return $pre; + } + $provider = $this->get_provider( $url, $args ); - if ( !$provider || false === $data = $this->fetch( $provider, $url, $args ) ) + if ( ! $provider || false === $data = $this->fetch( $provider, $url, $args ) ) { return false; + } /** * Filters the HTML returned by the oEmbed provider. diff --git a/src/wp-includes/default-filters.php b/src/wp-includes/default-filters.php index f7bfeb52fb..ddaa5efe24 100644 --- a/src/wp-includes/default-filters.php +++ b/src/wp-includes/default-filters.php @@ -476,5 +476,6 @@ add_filter( 'the_excerpt_embed', 'wp_embed_excerpt_attachment' ); add_filter( 'oembed_dataparse', 'wp_filter_oembed_result', 10, 3 ); add_filter( 'oembed_response_data', 'get_oembed_response_data_rich', 10, 4 ); +add_filter( 'pre_oembed_result', 'wp_filter_pre_oembed_result', 10, 3 ); unset( $filter, $action ); diff --git a/src/wp-includes/embed.php b/src/wp-includes/embed.php index 79b0503180..785b5f3a20 100644 --- a/src/wp-includes/embed.php +++ b/src/wp-includes/embed.php @@ -1079,3 +1079,35 @@ function the_embed_site_title() { */ echo apply_filters( 'embed_site_title_html', $site_title ); } + +/** + * Filters the oEmbed result before any HTTP requests are made. + * + * If the URL belongs to the current site, the result is fetched directly instead of + * going through the oEmbed discovery process. + * + * @since 4.5.3 + * + * @param null|string $result The UNSANITIZED (and potentially unsafe) HTML that should be used to embed. Default null. + * @param string $url The URL that should be inspected for discovery `` tags. + * @param array $args oEmbed remote get arguments. + * @return null|string The UNSANITIZED (and potentially unsafe) HTML that should be used to embed. + * Null if the URL does not belong to the current site. + */ +function wp_filter_pre_oembed_result( $result, $url, $args ) { + $post_id = url_to_postid( $url ); + + /** This filter is documented in wp-includes/class-wp-oembed-controller.php */ + $post_id = apply_filters( 'oembed_request_post_id', $post_id, $url ); + + $width = isset( $args['width'] ) ? $args['width'] : 0; + + $data = get_oembed_response_data( $post_id, $width ); + $data = _wp_oembed_get_object()->data2html( (object) $data, $url ); + + if ( ! $data ) { + return $result; + } + + return $data; +} diff --git a/tests/phpunit/tests/oembed/wpOembed.php b/tests/phpunit/tests/oembed/wpOembed.php new file mode 100644 index 0000000000..93a9cca77f --- /dev/null +++ b/tests/phpunit/tests/oembed/wpOembed.php @@ -0,0 +1,56 @@ +oembed = _wp_oembed_get_object(); + + $this->pre_oembed_result_filtered = false; + } + + public function _filter_pre_oembed_result( $result ) { + // If this is not null, the oEmbed result has been filtered before any HTTP requests were made. + $this->pre_oembed_result_filtered = $result; + + return $result; + } + + public function test_wp_filter_pre_oembed_result_prevents_http_request_for_internal_permalinks() { + $post_id = self::factory()->post->create(); + $permalink = get_permalink( $post_id ); + + add_filter( 'pre_oembed_result', array( $this, '_filter_pre_oembed_result' ) ); + $actual = $this->oembed->get_html( $permalink ); + remove_filter( 'pre_oembed_result', array( $this, '_filter_pre_oembed_result' ) ); + + $this->assertNotFalse( $this->pre_oembed_result_filtered ); + $this->assertEquals( $this->pre_oembed_result_filtered, $actual ); + } + + public function test_wp_filter_pre_oembed_result_prevents_http_request_when_viewing_the_post() { + $post_id = self::factory()->post->create(); + $permalink = get_permalink( $post_id ); + + $this->go_to( $permalink ); + $this->assertQueryTrue( 'is_single', 'is_singular' ); + + add_filter( 'pre_oembed_result', array( $this, '_filter_pre_oembed_result' ) ); + $actual = $this->oembed->get_html( $permalink ); + remove_filter( 'pre_oembed_result', array( $this, '_filter_pre_oembed_result' ) ); + + $this->assertNotFalse( $this->pre_oembed_result_filtered ); + $this->assertEquals( $this->pre_oembed_result_filtered, $actual ); + } +}