diff --git a/src/wp-includes/class-wp-embed.php b/src/wp-includes/class-wp-embed.php index 10d36afcd0..e981fb2591 100644 --- a/src/wp-includes/class-wp-embed.php +++ b/src/wp-includes/class-wp-embed.php @@ -125,6 +125,53 @@ class WP_Embed { unset( $this->handlers[ $priority ][ $id ] ); } + /** + * Returns embed HTML for a given URL from embed handlers. + * + * Attempts to convert a URL into embed HTML by checking the URL + * against the regex of the registered embed handlers. + * + * @since 5.5.0 + * + * @param array $attr { + * Shortcode attributes. Optional. + * + * @type int $width Width of the embed in pixels. + * @type int $height Height of the embed in pixels. + * } + * @param string $url The URL attempting to be embedded. + * @return string|false The embed HTML on success, false otherwise. + */ + public function get_embed_handler_html( $attr, $url ) { + $rawattr = $attr; + $attr = wp_parse_args( $attr, wp_embed_defaults( $url ) ); + + ksort( $this->handlers ); + foreach ( $this->handlers as $priority => $handlers ) { + foreach ( $handlers as $id => $handler ) { + if ( preg_match( $handler['regex'], $url, $matches ) && is_callable( $handler['callback'] ) ) { + $return = call_user_func( $handler['callback'], $matches, $attr, $url, $rawattr ); + if ( false !== $return ) { + /** + * Filters the returned embed HTML. + * + * @since 2.9.0 + * + * @see WP_Embed::shortcode() + * + * @param string|false $return The HTML result of the shortcode, or false on failure. + * @param string $url The embed URL. + * @param array $attr An array of shortcode attributes. + */ + return apply_filters( 'embed_handler_html', $return, $url, $attr ); + } + } + } + } + + return false; + } + /** * The do_shortcode() callback function. * @@ -166,27 +213,9 @@ class WP_Embed { $url = str_replace( '&', '&', $url ); // Look for known internal handlers. - ksort( $this->handlers ); - foreach ( $this->handlers as $priority => $handlers ) { - foreach ( $handlers as $id => $handler ) { - if ( preg_match( $handler['regex'], $url, $matches ) && is_callable( $handler['callback'] ) ) { - $return = call_user_func( $handler['callback'], $matches, $attr, $url, $rawattr ); - if ( false !== $return ) { - /** - * Filters the returned embed HTML. - * - * @since 2.9.0 - * - * @see WP_Embed::shortcode() - * - * @param string|false $return The HTML result of the shortcode, or false on failure. - * @param string $url The embed URL. - * @param array $attr An array of shortcode attributes. - */ - return apply_filters( 'embed_handler_html', $return, $url, $attr ); - } - } - } + $embed_handler_html = $this->get_embed_handler_html( $rawattr, $url ); + if ( false !== $embed_handler_html ) { + return $embed_handler_html; } $post_ID = ( ! empty( $post->ID ) ) ? $post->ID : null; diff --git a/src/wp-includes/class-wp-oembed-controller.php b/src/wp-includes/class-wp-oembed-controller.php index 31951041ef..3ab621408e 100644 --- a/src/wp-includes/class-wp-oembed-controller.php +++ b/src/wp-includes/class-wp-oembed-controller.php @@ -193,6 +193,28 @@ final class WP_oEmbed_Controller { $data = _wp_oembed_get_object()->get_data( $url, $args ); if ( false === $data ) { + // Try using a classic embed, instead. + global $wp_embed; + + /* @var WP_Embed $wp_embed */ + $html = $wp_embed->get_embed_handler_html( $args, $url ); + + if ( $html ) { + global $wp_scripts; + // Check if any scripts were enqueued by the shortcode, and include them in the response. + $enqueued_scripts = array(); + + foreach ( $wp_scripts->queue as $script ) { + $enqueued_scripts[] = $wp_scripts->registered[ $script ]->src; + } + + return (object) array( + 'provider_name' => __( 'Embed Handler' ), + 'html' => $html, + 'scripts' => $enqueued_scripts, + ); + } + return new WP_Error( 'oembed_invalid_url', get_status_header_desc( 404 ), array( 'status' => 404 ) ); } diff --git a/tests/phpunit/tests/oembed/controller.php b/tests/phpunit/tests/oembed/controller.php index 40a9dfccf7..72b3aed0bf 100644 --- a/tests/phpunit/tests/oembed/controller.php +++ b/tests/phpunit/tests/oembed/controller.php @@ -97,7 +97,7 @@ class Test_oEmbed_Controller extends WP_UnitTestCase { $this->request_count += 1; // Mock request to YouTube Embed. - if ( ! empty( $query_params['url'] ) && false !== strpos( $query_params['url'], self::YOUTUBE_VIDEO_ID ) ) { + if ( ! empty( $query_params['url'] ) && false !== strpos( $query_params['url'], '?v=' . self::YOUTUBE_VIDEO_ID ) ) { return array( 'response' => array( 'code' => 200, @@ -609,13 +609,38 @@ class Test_oEmbed_Controller extends WP_UnitTestCase { $this->assertEquals( $data->height, $request['maxheight'] ); } + /** + * @ticket 45447 + * + * @see wp_maybe_load_embeds() + */ + public function test_proxy_with_classic_embed_provider() { + wp_set_current_user( self::$editor ); + $request = new WP_REST_Request( 'GET', '/oembed/1.0/proxy' ); + $request->set_param( 'url', 'https://www.youtube.com/embed/' . self::YOUTUBE_VIDEO_ID ); + $request->set_param( 'maxwidth', 456 ); + $request->set_param( 'maxheight', 789 ); + $request->set_param( '_wpnonce', wp_create_nonce( 'wp_rest' ) ); + $response = rest_get_server()->dispatch( $request ); + $this->assertEquals( 200, $response->get_status() ); + $this->assertEquals( 2, $this->request_count ); + + // Test data object. + $data = $response->get_data(); + + $this->assertNotEmpty( $data ); + $this->assertInternalType( 'object', $data ); + $this->assertInternalType( 'string', $data->html ); + $this->assertInternalType( 'array', $data->scripts ); + } + public function test_proxy_with_invalid_oembed_provider_no_discovery() { wp_set_current_user( self::$editor ); - // If discover is false for an unkown provider, no discovery request should take place. + // If discover is false for an unknown provider, no discovery request should take place. $request = new WP_REST_Request( 'GET', '/oembed/1.0/proxy' ); $request->set_param( 'url', self::INVALID_OEMBED_URL ); - $request->set_param( 'discover', 0 ); + $request->set_param( 'discover', false ); $response = rest_get_server()->dispatch( $request ); $this->assertEquals( 404, $response->get_status() ); $this->assertEquals( 0, $this->request_count ); @@ -624,7 +649,7 @@ class Test_oEmbed_Controller extends WP_UnitTestCase { public function test_proxy_with_invalid_oembed_provider_with_default_discover_param() { wp_set_current_user( self::$editor ); - // For an unkown provider, a discovery request should happen. + // For an unknown provider, a discovery request should happen. $request = new WP_REST_Request( 'GET', '/oembed/1.0/proxy' ); $request->set_param( 'url', self::INVALID_OEMBED_URL ); $response = rest_get_server()->dispatch( $request );