Skip to content

Commit

Permalink
Instagram: update embed to support new TV URLs (#11329)
Browse files Browse the repository at this point in the history
#### 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 <david.binovec@gmail.com>
  • Loading branch information
jeherve and david-binda committed Feb 25, 2019
1 parent 7c49646 commit 2171105
Show file tree
Hide file tree
Showing 2 changed files with 182 additions and 18 deletions.
88 changes: 70 additions & 18 deletions modules/shortcodes/instagram.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,25 @@ function jetpack_instagram_embed_reversal( $content ) {

$regexes = array();

// new style js
$regexes[] = '#<blockquote[^>]+?class="instagram-media"[^>](.+?)>(.+?)</blockquote><script[^>]+?src="(https?:)?//platform\.instagram\.com/(.+?)/embeds\.js"></script>#ix';
// new style js.
$regexes[] = '#<blockquote[^>]+?class="instagram-media"[^>].+?>(.+?)</blockquote><script[^>]+?src="(https?:)?//platform\.instagram\.com/(.+?)/embeds\.js"></script>#ix';

// Let's play nice with the visual editor too.
$regexes[] = '#&lt;blockquote(?:[^&]|&(?!gt;))+?class="instagram-media"(?:[^&]|&(?!gt;))(.+?)&gt;(.+?)&lt;/blockquote&gt;&lt;script(?:[^&]|&(?!gt;))+?src="(https?:)?//platform\.instagram\.com/(.+?)/embeds\.js"(?:[^&]|&(?!gt;))*+&gt;&lt;/script&gt;#ix';
$regexes[] = '#&lt;blockquote(?:[^&]|&(?!gt;))+?class="instagram-media"(?:[^&]|&(?!gt;)).+?&gt;(.+?)&lt;/blockquote&gt;&lt;script(?:[^&]|&(?!gt;))+?src="(https?:)?//platform\.instagram\.com/(.+?)/embeds\.js"(?:[^&]|&(?!gt;))*+&gt;&lt;/script&gt;#ix';

// old style iframe
$regexes[] = '#<iframe[^>]+?src="(?:https?:)?//instagram\.com/p/([^"\'/]++)[^"\']*?"[^>]*+>\s*?</iframe>#i';
// old style iframe.
$regexes[] = '#<iframe[^>]+?src="((?:https?:)?//(?:www\.)?instagram\.com/p/([^"\'/]++)[^"\']*?)"[^>]*+>\s*?</iframe>#i';

// Let's play nice with the visual editor too.
$regexes[] = '#&lt;iframe(?:[^&]|&(?!gt;))+?src="(?:https?:)?//instagram\.com/p/([^"\'/]++)[^"\']*?"(?:[^&]|&(?!gt;))*+&gt;\s*?&lt;/iframe&gt;#i';
$regexes[] = '#&lt;iframe(?:[^&]|&(?!gt;))+?src="((?:https?:)?//(?:www\.)instagram\.com/p/([^"\'/]++)[^"\']*?)"(?:[^&]|&(?!gt;))*+&gt;\s*?&lt;/iframe&gt;#i';

foreach ( $regexes as $regex ) {
if ( ! preg_match_all( $regex, $content, $matches, PREG_SET_ORDER ) ) {
continue;
}

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;
}

Expand All @@ -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;

Expand All @@ -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( '<a href="%s" title="%s" target="_blank"><img src="%s" alt="Instagram Photo" /></a>', 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(
'<a href="%1$s" title="%2$s" target="_blank"><img src="%3$s" alt="%4$s" /></a>',
esc_url( $url ),
esc_attr__( 'View on Instagram', 'jetpack' ),
esc_url( $media_url ),
esc_html__( 'Instagram Photo', 'jetpack' )
);
} elseif ( 'tv' === $matches[1] ) {
return sprintf(
'<a href="%1$s" title="%2$s" target="_blank">%3$s</a>',
esc_url( $url ),
esc_attr__( 'View on Instagram', 'jetpack' ),
esc_html__( 'Instagram Video', 'jetpack' )
);
}
}

$atts = shortcode_atts(
Expand Down Expand Up @@ -166,13 +199,32 @@ function jetpack_instagram_handler( $matches, $atts, $url ) {
return '<!-- instagram error: no embed found -->';
}

// 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 );
}
Expand Down
112 changes: 112 additions & 0 deletions tests/php/modules/shortcodes/test_class.instagram.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
<?php

class WP_Test_Jetpack_Shortcodes_Instagram extends WP_UnitTestCase {
/**
* @covers ::jetpack_shortcode_instagram
*/
public function test_shortcode_instagram() {
$instagram_url = 'https://www.instagram.com/p/BnMO9vRleEx/';
$content = '[instagram url="' . $instagram_url . '"]';

$shortcode_content = do_shortcode( $content );

$this->assertContains(
'<blockquote class="instagram-media" data-instgrm-captioned data-instgrm-permalink="' . $instagram_url,
$shortcode_content
);
}

/**
* @covers ::jetpack_instagram_handler
*/
public function test_instagram_replace_image_url_with_embed() {
global $post;

$instagram_url = 'https://www.instagram.com/p/BnMO9vRleEx/';
$post = $this->factory->post->create_and_get( array( 'post_content' => $instagram_url ) );

do_action( 'init' );
setup_postdata( $post );
ob_start();
the_content();
$actual = ob_get_clean();
wp_reset_postdata();

$this->assertContains(
'<blockquote class="instagram-media" data-instgrm-captioned data-instgrm-permalink="' . $instagram_url,
$actual
);
}

/**
* @covers ::jetpack_instagram_handler
*/
public function test_instagram_replace_video_url_with_embed() {
global $post;

$instagram_url = 'https://www.instagram.com/tv/BkQjCfsBIzi/';
$post = $this->factory->post->create_and_get( array( 'post_content' => $instagram_url ) );

do_action( 'init' );
setup_postdata( $post );
ob_start();
the_content();
$actual = ob_get_clean();
wp_reset_postdata();

$this->assertContains(
'<blockquote class="instagram-media" data-instgrm-captioned data-instgrm-permalink="' . $instagram_url,
$actual
);
}

/**
* @covers ::jetpack_instagram_handler
*/
public function test_instagram_replace_profile_image_url_with_embed() {
global $post;

$instagram_username = 'jeherve';
$instagram_id = 'BnMO9vRleEx';
$instagram_original_url = 'https://www.instagram.com/' . $instagram_username . '/p/' . $instagram_id . '/';
$instagram_canonical_url = 'https://www.instagram.com/p/' . $instagram_id . '/';
$post = $this->factory->post->create_and_get( array( 'post_content' => $instagram_original_url ) );

do_action( 'init' );
setup_postdata( $post );
ob_start();
the_content();
$actual = ob_get_clean();
wp_reset_postdata();

$this->assertContains(
'<blockquote class="instagram-media" data-instgrm-captioned data-instgrm-permalink="' . $instagram_canonical_url,
$actual
);
}

/**
* @covers ::jetpack_instagram_handler
*/
public function test_instagram_replace_profile_video_url_with_embed() {
global $post;

$instagram_username = 'instagram';
$instagram_id = 'BkQjCfsBIzi';
$instagram_original_url = 'https://www.instagram.com/' . $instagram_username . '/tv/' . $instagram_id . '/';
$instagram_canonical_url = 'https://www.instagram.com/tv/' . $instagram_id . '/';
$post = $this->factory->post->create_and_get( array( 'post_content' => $instagram_original_url ) );

do_action( 'init' );
setup_postdata( $post );
ob_start();
the_content();
$actual = ob_get_clean();
wp_reset_postdata();

$this->assertContains(
'<blockquote class="instagram-media" data-instgrm-captioned data-instgrm-permalink="' . $instagram_canonical_url,
$actual
);
}
}

0 comments on commit 2171105

Please sign in to comment.