Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merges changes to the GettyImages shortcode from WordPress.com. #8591

Merged
merged 3 commits into from
Jan 30, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
131 changes: 100 additions & 31 deletions modules/shortcodes/getty.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,20 @@
if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
add_action( 'init', 'jetpack_getty_enable_embeds' );
} else {
jetpack_getty_enable_embeds( 'jetpack' );
jetpack_getty_enable_embeds();
}

/**
* Register Getty as oembed provider. Add filter to reverse iframes to shortcode. Register [getty] shortcode.
*
* @since 4.5.0
*
* @param string $site Can be 'wpcom' or 'jetpack' and determines if we're in wpcom or in a Jetpack site.
* @since 5.8.0 removed string parameter.
*/
function jetpack_getty_enable_embeds( $site = 'wpcom' ) {

// Set the caller argument to pass to Getty's oembed provider.
$caller = 'jetpack' === $site
? parse_url( get_home_url(), PHP_URL_HOST )
: 'wordpress.com';
function jetpack_getty_enable_embeds() {

// Support their oEmbed Endpoint
wp_oembed_add_provider( '#https?://www\.gettyimages\.com/detail/.*#i', "https://embed.gettyimages.com/oembed/?caller=$caller", true );
wp_oembed_add_provider( '#https?://(www\.)?gty\.im/.*#i', "https://embed.gettyimages.com/oembed/?caller=$caller", true );
wp_oembed_add_provider( '#https?://www\.gettyimages\.com/detail/.*#i', "https://embed.gettyimages.com/oembed/", true );
wp_oembed_add_provider( '#https?://(www\.)?gty\.im/.*#i', "https://embed.gettyimages.com/oembed/", true );

// Allow iframes to be filtered to short code (so direct copy+paste can be done)
add_filter( 'pre_kses', 'wpcom_shortcodereverse_getty' );
Expand All @@ -37,6 +31,47 @@ function jetpack_getty_enable_embeds( $site = 'wpcom' ) {
add_shortcode( 'getty', 'jetpack_getty_shortcode' );
}

/**
* Filters the oEmbed provider URL for Getty URLs to include site URL host as
* caller if available, falling back to "wordpress.com". Must be applied at
* time of embed in case that `init` is too early (WP.com REST API).
*
* @module shortcodes
*
* @since 5.8.0
*
* @see WP_oEmbed::fetch
*
* @return string oEmbed provider URL
*/
add_filter( 'oembed_fetch_url', 'getty_add_oembed_endpoint_caller' );

function getty_add_oembed_endpoint_caller( $provider ) {
// By time filter is called, original provider URL has had url, maxwidth,
// maxheight query parameters added.
if ( 0 !== strpos( $provider, 'https://embed.gettyimages.com/oembed/' ) ) {
return $provider;
}

// Set the caller argument to pass to Getty's oembed provider.
if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {

// Only include caller for non-private sites
if ( ! function_exists( 'is_private_blog' ) || ! is_private_blog() ) {
$host = parse_url( get_bloginfo( 'url' ), PHP_URL_HOST );
}

// Fall back to WordPress.com
if ( empty( $host ) ) {
$host = 'wordpress.com';
}
} else {
$host = parse_url( get_home_url(), PHP_URL_HOST );
}

return add_query_arg( 'caller', $host, $provider );
}

/**
* Compose shortcode based on Getty iframes.
*
Expand All @@ -47,39 +82,68 @@ function jetpack_getty_enable_embeds( $site = 'wpcom' ) {
* @return mixed
*/
function wpcom_shortcodereverse_getty( $content ) {
if ( ! is_string( $content ) || false === stripos( $content, 'embed.gettyimages.com/embed' ) ) {
if ( ! is_string( $content ) || false === stripos( $content, '.gettyimages.com/' ) ) {
return $content;
}

$regexp = '!<iframe\s+src=[\'"](https?:)?//embed\.gettyimages\.com/embed(/|/?\?assets=)(\d+(,\d+)*)[^\'"]*?[\'"]((?:\s+\w+=[\'"][^\'"]*[\'"])*)((?:[\s\w]*))></iframe>!i';
$regexp = '!<iframe\s+src=[\'"](https?:)?//embed\.gettyimages\.com/embed(/|/?\?assets=)([a-z0-9_-]+(,[a-z0-9_-]+)*)[^\'"]*?[\'"]((?:\s+\w+=[\'"][^\'"]*[\'"])*)((?:[\s\w]*))></iframe>!i';
$regexp_ent = str_replace( '&amp;#0*58;', '&amp;#0*58;|&#0*58;', htmlspecialchars( $regexp, ENT_NOQUOTES ) );

foreach ( array( 'regexp', 'regexp_ent' ) as $reg ) {

// Markup pattern for 2017 embed syntax with significant differences from
// the prior pattern:
$regexp_2017 = '!<a.+?class=\'gie-(single|slideshow)\'.+?gie\.widgets\.load\({([^}]+)}\).+?embed-cdn\.gettyimages\.com/widgets\.js.+?</script>!';
$regexp_2017_ent = str_replace( '&amp;#0*58;', '&amp;#0*58;|&#0*58;', htmlspecialchars( $regexp_2017, ENT_NOQUOTES ) );

foreach ( array( 'regexp_2017', 'regexp_2017_ent', 'regexp', 'regexp_ent' ) as $reg ) {
if ( ! preg_match_all( $$reg, $content, $matches, PREG_SET_ORDER ) ) {
continue;
}

foreach ( $matches as $match ) {
$ids = esc_html( $match[3] );

$params = $match[5];

if ( 'regexp_ent' == $reg ) {
$params = html_entity_decode( $params );
if ( 'regexp_2017' === $reg || 'regexp_2017_ent' === $reg ) {
// Extract individual keys from the matched JavaScript object
$params = $match[2];
if ( ! preg_match_all( '!(?P<key>\w+)\s*:\s*([\'"](?P<value>[^\'"]*?)(px)?[\'"])!', $params, $key_matches, PREG_SET_ORDER ) ) {
continue;
}

foreach ( $key_matches as $key_match ) {
switch ( $key_match['key'] ) {
case 'items': $ids = $key_match['value']; break;
case 'w': $width = (int) $key_match['value']; break;
case 'h': $height = (int) $key_match['value']; break;
case 'tld': $tld = $key_match['value']; break;
}
}
} else {
$params = $match[5];
if ( 'regexp_ent' === $reg ) {
$params = html_entity_decode( $params );
}
$params = wp_kses_hair( $params, array( 'http' ) );

$ids = esc_html( $match[3] );
$width = isset( $params['width'] ) ? (int) $params['width']['value'] : 0;
$height = isset( $params['height'] ) ? (int) $params['height']['value'] : 0;
}

$params = wp_kses_hair( $params, array( 'http' ) );

$width = isset( $params['width'] ) ? (int) $params['width']['value'] : 0;
$height = isset( $params['height'] ) ? (int) $params['height']['value'] : 0;
if ( empty( $ids ) ) {
continue;
}

$shortcode = '[getty src="' . esc_attr( $ids ) . '"';
if ( $width ) {
if ( ! empty( $width ) ) {
$shortcode .= ' width="' . esc_attr( $width ) . '"';
}
if ( $height ) {
if ( ! empty( $height ) ) {
$shortcode .= ' height="' . esc_attr( $height ) . '"';
}
// While it does not appear to have any practical impact, Getty has
// requested that we include TLD in the embed request
if ( ! empty( $tld ) ) {
$shortcode .= ' tld="' . esc_attr( $tld ). '"';
}
$shortcode .= ']';

$content = str_replace( $match[0], $shortcode, $content );
Expand Down Expand Up @@ -128,11 +192,16 @@ function jetpack_getty_shortcode( $atts, $content = '' ) {
return '<!-- Missing Getty Source ID -->';
}

$src = preg_replace( '/^(\d+(,\d+)*).*$/', '$1', $src );
$src = preg_replace( '/^([\da-z-]+(,[\da-z-]+)*).*$/', '$1', $src );

$args = array();
$args['width'] = isset( $atts['width'] ) ? (int) $atts['width'] : '462';
$args['height'] = isset( $atts['height'] ) ? (int) $atts['height'] : '370';
$params = array(
'width' => isset( $atts['width'] ) ? (int) $atts['width'] : null,
'height' => isset( $atts['height'] ) ? (int) $atts['height'] : null
);

if ( ! empty( $atts['tld'] ) ) {
$params['tld'] = $atts['tld'];
}

return wp_oembed_get( 'https://gty.im/' . $src, $args );
return wp_oembed_get( 'https://gty.im/' . $src, array_filter( $params ) );
}
116 changes: 103 additions & 13 deletions tests/php/modules/shortcodes/test_class.getty.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,42 @@

class WP_Test_Jetpack_Shortcodes_Getty extends WP_UnitTestCase {

const GETTY_IDENTIFIER = '82278805';

const GETTY_SHORTCODE = '[getty src="82278805" width="462" height="370"]';

const GETTY_SHORTCODE_TLD = '[getty src="82278805" width="462" height="370" tld="com"]';

const GETTY_SHORTCODE_SLIDESHOW = '[getty src="601312382,sb10068163bs-001,157480765,sb10068163br-001,157480920" width="457" height="377" tld="com"]';

const GETTY_SHORTCODE_MULTI = '[getty src="125972920,83421977" width="507" height="337"]';

const GETTY_SHORTCODE_ALPHANUMERIC_DASHED_ID = '[getty src="sb10065012a-001" width="426" height="400"]';

const GETTY_SHORTCODE_WITH_ARGS = '[getty src="82278805?et=wi6iT1Wqn0yYxEh6Ocx_aA&amp;sig=G63PuQ-eKJqGCnssk8rsSu1wcGoyUsgwqL8Jfu83wis=&amp;viewMoreLink%3Don" width="462" height="370"]';

const GETTY_EMBED = '<div class="getty embed image" style="background-color:#fff;display:inline-block;font-family:\'Helvetica Neue\',Helvetica,Arial,sans-serif;color:#a7a7a7;font-size:11px;width:100%;max-width:462px;"><div style="padding:0;margin:0;text-align:left;"><a href="http://www.gettyimages.com/detail/82278805" target="_blank" style="color:#a7a7a7;text-decoration:none;font-weight:normal !important;border:none;display:inline-block;">Embed from Getty Images</a></div><div style="overflow:hidden;position:relative;height:0;padding:80.086580% 0 0 0;width:100%;"><iframe src="//embed.gettyimages.com/embed/82278805?et=wi6iT1Wqn0yYxEh6Ocx_aA&amp;sig=G63PuQ-eKJqGCnssk8rsSu1wcGoyUsgwqL8Jfu83wis=&tld=com" width="462" height="370" scrolling="no" frameborder="0" style="display:inline-block;position:absolute;top:0;left:0;width:100%;height:100%;margin:0;" ></iframe></div><p style="margin:0;"></p></div>';

const GETTY_EMBED_MULTI = '<div class="getty embed image" style="background-color:#fff;display:inline-block;font-family:\'Helvetica Neue\',Helvetica,Arial,sans-serif;color:#a7a7a7;font-size:11px;width:100%;max-width:507px;"><div style="padding:0;margin:0;text-align:left;"><a href="http://www.gettyimages.com/detail/125972920" target="_blank" style="color:#a7a7a7;text-decoration:none;font-weight:normal !important;border:none;display:inline-block;">Embed from Getty Images</a></div><div style="overflow:hidden;position:relative;height:0;padding:66.469428% 0 0 0;width:100%;"><iframe src="//embed.gettyimages.com/embed?assets=125972920,83421977&et=mRtKtGrSS9RpMnENPzEAIQ&tld=com&sig=7cbyy8qX5L-4wrESym68jkKwv98QuF_RbdI4q6Sa_3s=" width="507" height="337" scrolling="no" frameborder="0" style="display:inline-block;position:absolute;top:0;left:0;width:100%;height:100%;margin:0;" ></iframe></div><p style="margin:0;"></p></div>';

const GETTY_EMBED_2017 = '<a id=\'giY-P3UyQ7NgmhoUs69FfA\' class=\'gie-single\' href=\'http://www.gettyimages.com/detail/82278805\' target=\'_blank\' style=\'color:#a7a7a7;text-decoration:none;font-weight:normal !important;border:none;display:inline-block;\'>Embed from Getty Images</a><script>window.gie=window.gie||function(c){(gie.q=gie.q||[]).push(c)};gie(function(){gie.widgets.load({id:\'giY-P3UyQ7NgmhoUs69FfA\',sig:\'7_gkXdhdHtVWWsyemkD0qPEuDZVBmfepEDjfqlTi61M=\',w:\'462px\',h:\'370px\',items:\'82278805\',caption: true ,tld:\'com\',is360: false })});</script><script src=\'//embed-cdn.gettyimages.com/widgets.js\' charset=\'utf-8\' async></script>';

const GETTY_EMBED_2017_SLIDESHOW = '<a id=\'CEIWqB2vSz5lH9pABhmy0A\' class=\'gie-slideshow\' href=\'http://www.gettyimages.com/detail/601312382\' style=\'color:#a7a7a7;text-decoration:none;font-weight:normal !important;border:none;display:inline-block;\'>Embed from Getty Images</a><script>window.gie=window.gie||function(c){(gie.q=gie.q||[]).push(c)};gie(function(){gie.widgets.load({id:\'CEIWqB2vSz5lH9pABhmy0A\',sig:\'cDACdf5bJZlDWoauJkdbDwvhtdjhQ5kn4GDr2nBQ9iA=\',w:\'457px\',h:\'377px\',items:\'601312382,sb10068163bs-001,157480765,sb10068163br-001,157480920\',caption: true ,tld:\'com\',is360: false })});</script><script src=\'//embed-cdn.gettyimages.com/widgets.js\' charset=\'utf-8\' async></script>';

const GETTY_EMBED_ALPHANUMERIC_DASHED_ID = '<div class="getty embed image" style="background-color:#fff;display:inline-block;font-family:\'Helvetica Neue\',Helvetica,Arial,sans-serif;color:#a7a7a7;font-size:11px;width:100%;max-width:426px;"><div style="padding:0;margin:0;text-align:left;"><a href="http://www.gettyimages.com/detail/sb10065012a-001" target="_blank" style="color:#a7a7a7;text-decoration:none;font-weight:normal !important;border:none;display:inline-block;">Embed from Getty Images</a></div><div style="overflow:hidden;position:relative;height:0;padding:93.896714% 0 0 0;width:100%;"><iframe src="//embed.gettyimages.com/embed/sb10065012a-001?et=kbBO9dIMTBZzGVtzySE_7g&viewMoreLink=off&sig=gFY-3rZCMdUEiVCbM2wqVAKDkGwskGl3W8pSn_4QCQc=&caption=true" width="426" height="400" scrolling="no" frameborder="0" style="display:inline-block;position:absolute;top:0;left:0;width:100%;height:100%;margin:0;"></iframe></div><p style="margin:0;"></p></div>';

const GETTY_OLD_EMBED = '<iframe src="//embed.gettyimages.com/embed/82278805?et=wi6iT1Wqn0yYxEh6Ocx_aA&sig=G63PuQ-eKJqGCnssk8rsSu1wcGoyUsgwqL8Jfu83wis=" width="462" height="370" scrolling="no" frameborder="0" style="display:inline-block;"></iframe>';

const GETTY_ESCAPED_EMBED = '&lt;div class="getty embed image" style="background-color:#fff;display:inline-block;font-family:\'Helvetica Neue\',Helvetica,Arial,sans-serif;color:#a7a7a7;font-size:11px;width:100%;max-width:462px;"&gt;&lt;div style="padding:0;margin:0;text-align:left;"&gt;&lt;a href="http://www.gettyimages.com/detail/82278805" target="_blank" style="color:#a7a7a7;text-decoration:none;font-weight:normal !important;border:none;display:inline-block;"&gt;Embed from Getty Images&lt;/a&gt;&lt;/div&gt;&lt;div style="overflow:hidden;position:relative;height:0;padding:80.086580% 0 0 0;width:100%;"&gt;&lt;iframe src="//embed.gettyimages.com/embed/82278805?et=wi6iT1Wqn0yYxEh6Ocx_aA&amp;sig=G63PuQ-eKJqGCnssk8rsSu1wcGoyUsgwqL8Jfu83wis=" width="462" height="370" scrolling="no" frameborder="0" style="display:inline-block;position:absolute;top:0;left:0;width:100%;height:100%;"&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;p style="margin:0;"&gt;&lt;/p&gt;&lt;/div&gt;';

const GETTY_ESCAPED_EMBED_2017 = '&lt;a id=\'giY-P3UyQ7NgmhoUs69FfA\' class=\'gie-single\' href=\'http://www.gettyimages.com/detail/82278805\' target=\'_blank\' style=\'color:#a7a7a7;text-decoration:none;font-weight:normal !important;border:none;display:inline-block;\'&gt;Embed from Getty Images&lt;/a&gt;&lt;script&gt;window.gie=window.gie||function(c){(gie.q=gie.q||[]).push(c)};gie(function(){gie.widgets.load({id:\'giY-P3UyQ7NgmhoUs69FfA\',sig:\'7_gkXdhdHtVWWsyemkD0qPEuDZVBmfepEDjfqlTi61M=\',w:\'462px\',h:\'370px\',items:\'82278805\',caption: true ,tld:\'com\',is360: false })});&lt;/script&gt;&lt;script src=\'//embed-cdn.gettyimages.com/widgets.js\' charset=\'utf-8\' async&gt;&lt;/script&gt;';

const GETTY_EXAMPLE_PROCESSED = '<div class="getty embed image" style="background-color:#fff;display:inline-block;font-family:\'Helvetica Neue\',Helvetica,Arial,sans-serif;color:#a7a7a7;font-size:11px;width:100%;max-width:462px;"><div style="padding:0;margin:0;text-align:left;"><a href="http://www.gettyimages.com/detail/82278805" target="_blank" style="color:#a7a7a7;text-decoration:none;font-weight:normal !important;border:none;display:inline-block;">Embed from Getty Images</a></div><div style="overflow:hidden;position:relative;height:0;padding:80.086580% 0 0 0;width:100%;"><iframe src="//embed.gettyimages.com/embed/82278805?et=wi6iT1Wqn0yYxEh6Ocx_aA&amp;sig=G63PuQ-eKJqGCnssk8rsSu1wcGoyUsgwqL8Jfu83wis=&tld=com" width="462" height="370" scrolling="no" frameborder="0" style="display:inline-block;position:absolute;top:0;left:0;width:100%;height:100%;margin:0;" ></iframe></div><p style="margin:0;"></p></div>';

static function strip_url_signature_args( $str ) {
return preg_replace( '/((id=\'[:alpha:\-]+)|[\?&]|&amp;|&#038;)(et=[\w-]+|sig=[\w-=]+)/', '', $str );
}

/**
* Verify that [getty] exists.
*
Expand All @@ -11,18 +47,74 @@ public function test_shortcodes_getty_exists() {
$this->assertEquals( shortcode_exists( 'getty' ), true );
}

/**
* Verify that calling do_shortcode with the shortcode doesn't return the same content.
*
* @since 4.5.0
*/
public function test_shortcodes_getty() {
$content = '[getty]';
function test_getty_shortcode() {
$parsed = do_shortcode( self::GETTY_SHORTCODE );

$shortcode_content = do_shortcode( $content );
$doc = new DOMDocument();
$doc->loadHTML( $parsed );
$links = $doc->getElementsByTagName( 'a' );

foreach( $links as $link ) {
$this->assertTrue( $link->hasAttribute( 'href' ) );
$this->assertContains( self::GETTY_IDENTIFIER, $link->getAttribute( 'href' ) );
}
}

function test_getty_reverse_shortcode() {
$shortcode = wpcom_shortcodereverse_getty( self::GETTY_EMBED );
$this->assertEquals( self::GETTY_SHORTCODE, $shortcode );
}

function test_getty_reverse_multi_shortcode() {
$shortcode = wpcom_shortcodereverse_getty( self::GETTY_EMBED_MULTI );
$this->assertEquals( self::GETTY_SHORTCODE_MULTI, $shortcode );
}

function test_getty_reverse_alphanumeric_daashed_id_shortcode() {
$shortcode = wpcom_shortcodereverse_getty( self::GETTY_EMBED_ALPHANUMERIC_DASHED_ID );
$this->assertEquals( self::GETTY_SHORTCODE_ALPHANUMERIC_DASHED_ID, $shortcode );
}

function test_getty_reverse_shortcode_works_on_escaped_html() {
$shortcode = wpcom_shortcodereverse_getty( self::GETTY_ESCAPED_EMBED );
$this->assertEquals( self::GETTY_SHORTCODE, $shortcode );
}

$this->assertNotEquals( $content, $shortcode_content );
$this->assertEquals( '<!-- Missing Getty Source ID -->', $shortcode_content );
function test_getty_reverse_shortcode_works_on_old_embed() {
$shortcode = wpcom_shortcodereverse_getty( self::GETTY_OLD_EMBED );
$this->assertEquals( self::GETTY_SHORTCODE, $shortcode );
}

function test_getty_reverse_shortcode_2017() {
$shortcode = wpcom_shortcodereverse_getty( self::GETTY_EMBED_2017 );
$this->assertEquals( self::GETTY_SHORTCODE_TLD, $shortcode );
}

function test_getty_reverse_shortcode_2017_works_on_escaped_html() {
$shortcode = wpcom_shortcodereverse_getty( self::GETTY_ESCAPED_EMBED_2017 );
$this->assertEquals( self::GETTY_SHORTCODE_TLD, $shortcode );
}

function test_getty_reverse_shortcode_doesnt_remove_too_much() {
$before = '<div class="something else">test<div class=\'something\'>another div';
$after = 'blah</div></div>';
$shortcode = wpcom_shortcodereverse_getty( $before . self::GETTY_EMBED . $after );
$expected = $before . self::GETTY_SHORTCODE . $after;
$this->assertEquals( $expected, $shortcode );
}

function test_getty_add_oembed_endpoint_caller_non_getty() {
$provider_url = apply_filters(
'oembed_fetch_url',
'https://www.youtube.com/oembed?maxwidth=471&maxheight=594&url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DdQw4w9WgXcQ',
'https://www.youtube.com/watch?v=dQw4w9WgXcQ',
''
);

$this->assertEquals(
$provider_url,
'https://www.youtube.com/oembed?maxwidth=471&maxheight=594&url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DdQw4w9WgXcQ'
);
}

/**
Expand All @@ -31,13 +123,11 @@ public function test_shortcodes_getty() {
* @since 4.5.0
*/
public function test_shortcodes_getty_image() {
$this->markTestSkipped();

$image_id = '82278805';
$content = "[getty src='$image_id']";

$shortcode_content = do_shortcode( $content );

$this->assertContains( '<iframe src="//embed.gettyimages.com/embed/' . $image_id, $shortcode_content );
$this->assertContains( $image_id, $shortcode_content );
}
}