From 21711053288f1c4f3925bd20215100ada57a9f80 Mon Sep 17 00:00:00 2001 From: Jeremy Herve Date: Mon, 25 Feb 2019 12:55:46 +0100 Subject: [PATCH] Instagram: update embed to support new TV URLs (#11329) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #### Changes proposed in this Pull Request: This updates our custom embed provider to support Instagram TV URLs, just like Core will soon: https://core.trac.wordpress.org/changeset/44486 I also took the opportunity to add some Unit Tests for Instagram, we did not have any before. #### Testing instructions: * Try adding the following URLs to a brand new post, and see that they all get transformed into embeds on publish: ``` A classic IG embed https://www.instagram.com/p/BnMOk_FFsxg/ A TV IG embed https://www.instagram.com/tv/BkQjCfsBIzi/ A profile alternative picture IG embed https://www.instagram.com/jeherve/p/BnMO9vRleEx/ A profile alternative video IG embed https://www.instagram.com/instagram/tv/BkQjCfsBIzi/ An Instagram shortcode [instagram url="http://instagram.com/p/BnMO9vRleEx/"] ``` * I would recommend testing this with the Classic Editor, because Instagram Embeds are currently broken in the block editor (see #9331) #### Proposed changelog entry for your changes: * Instagram: update embed to support Instagram TV URLs Co-authored-by: David Biňovec --- modules/shortcodes/instagram.php | 88 +++++++++++--- .../shortcodes/test_class.instagram.php | 112 ++++++++++++++++++ 2 files changed, 182 insertions(+), 18 deletions(-) create mode 100644 tests/php/modules/shortcodes/test_class.instagram.php diff --git a/modules/shortcodes/instagram.php b/modules/shortcodes/instagram.php index fc164d820b5c6..656703bdf8adf 100644 --- a/modules/shortcodes/instagram.php +++ b/modules/shortcodes/instagram.php @@ -21,17 +21,17 @@ function jetpack_instagram_embed_reversal( $content ) { $regexes = array(); - // new style js - $regexes[] = '#]+?class="instagram-media"[^>](.+?)>(.+?)]+?src="(https?:)?//platform\.instagram\.com/(.+?)/embeds\.js">#ix'; + // new style js. + $regexes[] = '#]+?class="instagram-media"[^>].+?>(.+?)]+?src="(https?:)?//platform\.instagram\.com/(.+?)/embeds\.js">#ix'; // Let's play nice with the visual editor too. - $regexes[] = '#<blockquote(?:[^&]|&(?!gt;))+?class="instagram-media"(?:[^&]|&(?!gt;))(.+?)>(.+?)</blockquote><script(?:[^&]|&(?!gt;))+?src="(https?:)?//platform\.instagram\.com/(.+?)/embeds\.js"(?:[^&]|&(?!gt;))*+></script>#ix'; + $regexes[] = '#<blockquote(?:[^&]|&(?!gt;))+?class="instagram-media"(?:[^&]|&(?!gt;)).+?>(.+?)</blockquote><script(?:[^&]|&(?!gt;))+?src="(https?:)?//platform\.instagram\.com/(.+?)/embeds\.js"(?:[^&]|&(?!gt;))*+></script>#ix'; - // old style iframe - $regexes[] = '#]+?src="(?:https?:)?//instagram\.com/p/([^"\'/]++)[^"\']*?"[^>]*+>\s*?#i'; + // old style iframe. + $regexes[] = '#]+?src="((?:https?:)?//(?:www\.)?instagram\.com/p/([^"\'/]++)[^"\']*?)"[^>]*+>\s*?#i'; // Let's play nice with the visual editor too. - $regexes[] = '#<iframe(?:[^&]|&(?!gt;))+?src="(?:https?:)?//instagram\.com/p/([^"\'/]++)[^"\']*?"(?:[^&]|&(?!gt;))*+>\s*?</iframe>#i'; + $regexes[] = '#<iframe(?:[^&]|&(?!gt;))+?src="((?:https?:)?//(?:www\.)instagram\.com/p/([^"\'/]++)[^"\']*?)"(?:[^&]|&(?!gt;))*+>\s*?</iframe>#i'; foreach ( $regexes as $regex ) { if ( ! preg_match_all( $regex, $content, $matches, PREG_SET_ORDER ) ) { @@ -39,7 +39,7 @@ function jetpack_instagram_embed_reversal( $content ) { } foreach ( $matches as $match ) { - if ( ! preg_match( '#(https?:)?//instagr(\.am|am\.com)/p/([^/]*)#i', $match[2], $url_matches ) ) { + if ( ! preg_match( '#(https?:)?//(?:www\.)?instagr(\.am|am\.com)/p/([^/]*)#i', $match[1], $url_matches ) ) { continue; } @@ -59,11 +59,28 @@ function jetpack_instagram_embed_reversal( $content ) { add_filter( 'pre_kses', 'jetpack_instagram_embed_reversal' ); /** - * Instagram + * Instagram's custom Embed provider. + * We first remove 2 different embed providers, both registered by Core. + * - The first is the original provider,that only supports images. + * - The second is tne new provider that replaced the first one in Core when Core added support for videos. https://core.trac.wordpress.org/changeset/44486 + * + * Once the core embed provider is removed (one or the other, depending on your version of Core), we declare our own. */ -wp_oembed_remove_provider( '#https?://(www\.)?instagr(\.am|am\.com)/p/.*#i' ); // remove core's oEmbed support so we can override -wp_embed_register_handler( 'jetpack_instagram', '#http(s?)://(www\.)?instagr(\.am|am\.com)/p/([^/]*)#i', 'jetpack_instagram_handler' ); +wp_oembed_remove_provider( '#https?://(www\.)?instagr(\.am|am\.com)/p/.*#i' ); +wp_oembed_remove_provider( '#https?://(www\.)?instagr(\.am|am\.com)/(p|tv)/.*#i' ); +wp_embed_register_handler( + 'jetpack_instagram', + '#http(s?)://(www\.)?instagr(\.am|am\.com)/(p|tv)/([^\/]*)#i', + 'jetpack_instagram_handler' +); +/** + * Handle Instagram embeds (build embed from regex). + * + * @param array $matches Array of matches from the regex. + * @param array $atts The original unmodified attributes. + * @param string $url The original URL that was matched by the regex. + */ function jetpack_instagram_handler( $matches, $atts, $url ) { global $content_width; @@ -74,8 +91,24 @@ function jetpack_instagram_handler( $matches, $atts, $url ) { $min_width = 320; if ( is_feed() ) { - $media_url = sprintf( 'http://instagr.am/p/%s/media/?size=l', $matches[4] ); - return sprintf( 'Instagram Photo', esc_url( $url ), esc_attr__( 'View on Instagram', 'jetpack' ), esc_url( $media_url ) ); + // Instagram offers direct links to images, but not to videos. + if ( 'p' === $matches[1] ) { + $media_url = sprintf( 'http://instagr.am/p/%1$s/media/?size=l', $matches[2] ); + return sprintf( + '%4$s', + esc_url( $url ), + esc_attr__( 'View on Instagram', 'jetpack' ), + esc_url( $media_url ), + esc_html__( 'Instagram Photo', 'jetpack' ) + ); + } elseif ( 'tv' === $matches[1] ) { + return sprintf( + '%3$s', + esc_url( $url ), + esc_attr__( 'View on Instagram', 'jetpack' ), + esc_html__( 'Instagram Video', 'jetpack' ) + ); + } } $atts = shortcode_atts( @@ -166,13 +199,32 @@ function jetpack_instagram_handler( $matches, $atts, $url ) { return ''; } -// filters instagram's username format to the expected format that matches the embed handler -wp_embed_register_handler( 'jetpack_instagram_alternate_format', '#http(s?)://instagr(\.am|am\.com)/([^/]*)/p/([^/]*)#i', 'jetpack_instagram_alternate_format_handler' ); +/** + * Handle an alternate Instagram URL format, where the username is also part of the URL. + * We do not actually need that username for the embed. + */ +wp_embed_register_handler( + 'jetpack_instagram_alternate_format', + '#https?://(?:www\.)?instagr(?:\.am|am\.com)/(?:[^/]*)/(p|tv)/([^\/]*)#i', + 'jetpack_instagram_alternate_format_handler' +); + +/** + * Handle alternate Instagram embeds (build embed from regex). + * + * @param array $matches Array of matches from the regex. + * @param array $atts The original unmodified attributes. + * @param string $url The original URL that was matched by the regex. + */ function jetpack_instagram_alternate_format_handler( $matches, $atts, $url ) { - $url = esc_url_raw( 'https://instagram.com/p/' . $matches[4] ); - $matches[0] = $url; - $matches[3] = $matches[4]; - unset( $matches[4] ); + // Replace URL saved by original Instagram URL (no username). + $matches[0] = esc_url_raw( + sprintf( + 'https://www.instagram.com/%1$s/%2$s', + $matches[1], + $matches[2] + ) + ); return jetpack_instagram_handler( $matches, $atts, $url ); } diff --git a/tests/php/modules/shortcodes/test_class.instagram.php b/tests/php/modules/shortcodes/test_class.instagram.php new file mode 100644 index 0000000000000..3a8360924aedc --- /dev/null +++ b/tests/php/modules/shortcodes/test_class.instagram.php @@ -0,0 +1,112 @@ +assertContains( + '