diff --git a/includes/class-amp-theme-support.php b/includes/class-amp-theme-support.php index cfb180bde66..595037e02e2 100644 --- a/includes/class-amp-theme-support.php +++ b/includes/class-amp-theme-support.php @@ -6,6 +6,7 @@ */ use AmpProject\Amp; +use AmpProject\AmpWP\Embed\Registerable; use AmpProject\AmpWP\Option; use AmpProject\AmpWP\RemoteRequest\CachedRemoteGetRequest; use AmpProject\AmpWP\ConfigurationArgument; @@ -1179,8 +1180,9 @@ public static function register_content_embed_handlers() { ); continue; } - - $embed_handler->register_embed(); + if ( $embed_handler instanceof Registerable ) { + $embed_handler->register_embed(); + } $embed_handlers[] = $embed_handler; } diff --git a/includes/embeds/class-amp-base-embed-handler.php b/includes/embeds/class-amp-base-embed-handler.php index 77f86b83d79..6d35e315cd8 100644 --- a/includes/embeds/class-amp-base-embed-handler.php +++ b/includes/embeds/class-amp-base-embed-handler.php @@ -7,6 +7,8 @@ * @package AMP */ +use AmpProject\Dom\Document; + /** * Class AMP_Base_Embed_Handler */ @@ -40,14 +42,18 @@ abstract class AMP_Base_Embed_Handler { protected $did_convert_elements = false; /** - * Registers embed. + * Default AMP tag to be used when sanitizing embeds. + * + * @var string */ - abstract public function register_embed(); + protected $amp_tag = 'amp-iframe'; /** - * Unregisters embed. + * Base URL used for identifying embeds. + * + * @var string */ - abstract public function unregister_embed(); + protected $base_embed_url = ''; /** * Constructor. @@ -64,6 +70,56 @@ public function __construct( $args = [] ) { ); } + /** + * Sanitize all embeds on the page to be AMP compatible. + * + * @param Document $dom DOM. + */ + public function sanitize_raw_embeds( Document $dom ) { + $nodes = $this->get_raw_embed_nodes( $dom ); + + if ( null === $nodes ) { + // Bail if the embed handler returns null. + return; + } + + if ( 0 === $nodes->length ) { + return; + } + + foreach ( $nodes as $node ) { + if ( ! $this->is_raw_embed( $node ) ) { + continue; + } + $this->sanitize_raw_embed( $node ); + } + } + + /** + * Determine if the node is indeed a raw embed. + * + * @param DOMElement $node DOM element. + * @return bool True if it is a raw embed, false otherwise. + */ + protected function is_raw_embed( DOMElement $node ) { + return $node->parentNode && $this->amp_tag !== $node->parentNode->nodeName; + } + + /** + * Get all raw embeds from the DOM. + * + * @param Document $dom Document. + * @return DOMNodeList|null A list of DOMElement nodes, or null if not implemented. + */ + abstract protected function get_raw_embed_nodes( Document $dom ); + + /** + * Make embed AMP compatible. + * + * @param DOMElement $node DOM element. + */ + abstract protected function sanitize_raw_embed( DOMElement $node ); + /** * Get mapping of AMP component names to AMP script URLs. * @@ -107,4 +163,90 @@ function ( $attr_name ) { } return wp_array_slice_assoc( $matches, $attribute_names ); } + + /** + * Get all child elements of the specified element. + * + * @param DOMElement $node Element. + * @return DOMElement[] Array of child elements for specified element. + */ + protected function get_child_elements( DOMElement $node ) { + return array_filter( + iterator_to_array( $node->childNodes ), + static function ( DOMNode $child ) { + return $child instanceof DOMElement; + } + ); + } + + /** + * Replace the node's parent with itself if the parent is a

tag, has no attributes and has no other children. + * This usually happens while `wpautop()` processes the element. + * + * @since 1.6 + * + * @param DOMElement $node Node. + */ + protected function unwrap_p_element( DOMElement $node ) { + $parent_node = $node->parentNode; + while ( $parent_node && ! ( $parent_node instanceof DOMElement ) ) { + $parent_node = $parent_node->parentNode; + } + + if ( $parent_node instanceof DOMElement && 'p' === $parent_node->nodeName && false === $parent_node->hasAttributes() ) { + $child_element_count = count( $this->get_child_elements( $parent_node ) ); + if ( 1 === $child_element_count ) { + $parent_node->parentNode->replaceChild( $node, $parent_node ); + } + } + } + + /** + * Removes the node's nearest - */ - $fb_root = $dom->getElementById( 'fb-root' ); - if ( $fb_root ) { - $script_elements = $dom->xpath->query( '//script[ starts-with( @src, "https://connect.facebook.net" ) and contains( @src, "sdk.js" ) ]' ); - foreach ( $script_elements as $script ) { + $node->parentNode->replaceChild( $amp_facebook_node, $node ); + if ( $fallback ) { + $amp_facebook_node->appendChild( $fallback ); + } + + $this->did_convert_elements = true; + } + + /** + * Remove instances of the `fb-root` div element and its accompanied Facebook Connect JS script since they would be irrelevant. + * + * @param Document $dom DOM. + */ + private function remove_fb_root_nodes( Document $dom ) { + $fb_root_query = $dom->xpath->query( '//div[ @id = "fb-root" ]' ); + + if ( 0 < $fb_root_query->length ) { + // Remove instances of

. + foreach ( $fb_root_query as $fb_root ) { + $fb_root->parentNode->removeChild( $fb_root ); + } + + // Remove instances of the accompanied script. + $script_query = $dom->xpath->query( '//script[ starts-with( @src, "https://connect.facebook.net" ) and contains( @src, "sdk.js" ) ]' ); + + foreach ( $script_query as $script ) { + /** @var DOMElement $parent_node */ $parent_node = $script->parentNode; $parent_node->removeChild( $script ); @@ -89,12 +144,6 @@ public function sanitize_raw_embeds( Document $dom ) { $parent_node->parentNode->removeChild( $parent_node ); } } - - // Remove other instances of
. - $fb_root_elements = $dom->xpath->query( '//div[ @id = "fb-root" ]' ); - foreach ( $fb_root_elements as $fb_root ) { - $fb_root->parentNode->removeChild( $fb_root ); - } } } @@ -136,66 +185,4 @@ private function get_embed_type( DOMElement $node ) { return null; } - - /** - * Create amp-facebook and replace node. - * - * @param Document $dom The HTML Document. - * @param DOMElement $node The DOMNode to adjust and replace. - * @param string $embed_type Embed type. - */ - private function create_amp_facebook_and_replace_node( Document $dom, DOMElement $node, $embed_type ) { - - $attributes = [ - // The layout sanitizer will convert this to `layout` when being sanitized. - // The data attribute needs to be used so that the layout sanitizer will process it. - 'data-amp-layout' => 'responsive', - 'width' => $node->hasAttribute( 'data-width' ) ? $node->getAttribute( 'data-width' ) : $this->DEFAULT_WIDTH, - 'height' => $node->hasAttribute( 'data-height' ) ? $node->getAttribute( 'data-height' ) : $this->DEFAULT_HEIGHT, - ]; - - $node->removeAttribute( 'data-width' ); - $node->removeAttribute( 'data-height' ); - - foreach ( $node->attributes as $attribute ) { - if ( 'data-' === substr( $attribute->nodeName, 0, 5 ) ) { - $attributes[ $attribute->nodeName ] = $attribute->nodeValue; - } - } - - if ( 'page' === $embed_type ) { - $amp_tag = 'amp-facebook-page'; - } elseif ( 'like' === $embed_type ) { - $amp_tag = 'amp-facebook-like'; - } elseif ( 'comments' === $embed_type ) { - $amp_tag = 'amp-facebook-comments'; - } else { - $amp_tag = $this->amp_tag; - - $attributes['data-embed-as'] = $embed_type; - } - - $amp_facebook_node = AMP_DOM_Utils::create_node( - $dom, - $amp_tag, - $attributes - ); - - $fallback = null; - foreach ( $node->childNodes as $child_node ) { - if ( $child_node instanceof DOMElement && false !== strpos( $child_node->getAttribute( 'class' ), 'fb-xfbml-parse-ignore' ) ) { - $fallback = $child_node; - $child_node->parentNode->removeChild( $child_node ); - $fallback->setAttribute( 'fallback', '' ); - break; - } - } - - $node->parentNode->replaceChild( $amp_facebook_node, $node ); - if ( $fallback ) { - $amp_facebook_node->appendChild( $fallback ); - } - - $this->did_convert_elements = true; - } } diff --git a/includes/embeds/class-amp-gallery-embed-handler.php b/includes/embeds/class-amp-gallery-embed-handler.php index 875ad3e793a..fe097637af0 100644 --- a/includes/embeds/class-amp-gallery-embed-handler.php +++ b/includes/embeds/class-amp-gallery-embed-handler.php @@ -5,6 +5,7 @@ * @package AMP */ +use AmpProject\AmpWP\Embed\Registerable; use AmpProject\Dom\Document; use AmpProject\AmpWP\Dom\ElementList; use AmpProject\AmpWP\Component\Carousel; @@ -14,7 +15,7 @@ * * @since 0.2 */ -class AMP_Gallery_Embed_Handler extends AMP_Base_Embed_Handler { +class AMP_Gallery_Embed_Handler extends AMP_Base_Embed_Handler implements Registerable { /** * Register embed. @@ -220,7 +221,7 @@ public function render( $args ) { $images = new ElementList(); foreach ( $args['images'] as $props ) { - $image_atts = [ + $image_attrs = [ 'src' => $props['url'], 'width' => $props['width'], 'height' => $props['height'], @@ -228,16 +229,16 @@ public function render( $args ) { 'alt' => $props['alt'], ]; if ( ! empty( $props['srcset'] ) ) { - $image_atts['srcset'] = $props['srcset']; + $image_attrs['srcset'] = $props['srcset']; } if ( ! empty( $args['lightbox'] ) ) { - $image_atts['lightbox'] = ''; + $image_attrs['lightbox'] = ''; } $image = AMP_DOM_Utils::create_node( $dom, 'img', - $image_atts + $image_attrs ); if ( ! empty( $props['href'] ) ) { @@ -285,4 +286,22 @@ public function print_styles() { xpath->query( sprintf( '//iframe[ starts-with( @src, "%s" ) ]', $this->base_embed_url ) ); } /** - * Filter oEmbed HTML for Gfycat to prepare it for AMP. + * Make embed AMP compatible. * - * @param mixed $return The oEmbed HTML. - * @param string $url The attempted embed URL. - * @param array $attr Attributes. - * @return string Embed. + * @param DOMElement $node DOM element. */ - public function filter_embed_oembed_html( $return, $url, $attr ) { - $parsed_url = wp_parse_url( $url ); - if ( false !== strpos( $parsed_url['host'], 'gfycat.com' ) ) { - if ( preg_match( '/width=["\']?(\d+)/', $return, $matches ) ) { - $attr['width'] = $matches[1]; - } - if ( preg_match( '/height=["\']?(\d+)/', $return, $matches ) ) { - $attr['height'] = $matches[1]; - } + protected function sanitize_raw_embed( DOMElement $node ) { + $iframe_src = $node->getAttribute( 'src' ); - if ( empty( $attr['height'] ) ) { - return $return; - } + $gfycat_id = strtok( substr( $iframe_src, strlen( $this->base_embed_url ) ), '/?#' ); + if ( empty( $gfycat_id ) ) { + // Nothing to do if the ID could not be found. + return; + } - $attributes = wp_array_slice_assoc( $attr, [ 'width', 'height' ] ); + $attributes = [ + 'data-gfyid' => $gfycat_id, + 'layout' => 'responsive', + 'height' => $this->args['height'], + 'width' => $this->args['width'], + ]; - if ( empty( $attr['width'] ) ) { - $attributes['layout'] = 'fixed-height'; - $attributes['width'] = 'auto'; + if ( '100%' === $node->getAttribute( 'width' ) && '100%' === $node->getAttribute( 'height' ) ) { + $attributes['layout'] = 'fill'; + unset( $attributes['width'], $attributes['height'] ); + } else { + if ( $node->hasAttribute( 'width' ) ) { + $attributes['width'] = $node->getAttribute( 'width' ); } - $pieces = explode( '/detail/', $parsed_url['path'] ); - if ( ! isset( $pieces[1] ) ) { - if ( ! preg_match( '/\/([A-Za-z0-9]+)/', $parsed_url['path'], $matches ) ) { - return $return; - } - $attributes['data-gfyid'] = $matches[1]; - } else { - $attributes['data-gfyid'] = $pieces[1]; + if ( $node->hasAttribute( 'height' ) ) { + $attributes['height'] = $node->getAttribute( 'height' ); } - - $return = AMP_HTML_Utils::build_tag( - 'amp-gfycat', - $attributes - ); } - return $return; + + $amp_node = AMP_DOM_Utils::create_node( + Document::fromNode( $node ), + 'amp-gfycat', + $attributes + ); + + $this->unwrap_p_element( $node ); + + $node->parentNode->replaceChild( $amp_node, $node ); } } diff --git a/includes/embeds/class-amp-hulu-embed-handler.php b/includes/embeds/class-amp-hulu-embed-handler.php index e9dca1df449..3e1a1dd5559 100644 --- a/includes/embeds/class-amp-hulu-embed-handler.php +++ b/includes/embeds/class-amp-hulu-embed-handler.php @@ -6,16 +6,12 @@ * @since 1.0 */ +use AmpProject\Dom\Document; + /** * Class AMP_Hulu_Embed_Handler */ class AMP_Hulu_Embed_Handler extends AMP_Base_Embed_Handler { - /** - * Regex matched to produce output amp-hulu. - * - * @var string - */ - const URL_PATTERN = '#https?://(www\.)?hulu\.com/.*#i'; /** * Default height. @@ -25,63 +21,65 @@ class AMP_Hulu_Embed_Handler extends AMP_Base_Embed_Handler { protected $DEFAULT_HEIGHT = 600; /** - * Register embed. + * Default AMP tag to be used when sanitizing embeds. + * + * @var string */ - public function register_embed() { - add_filter( 'embed_oembed_html', [ $this, 'filter_embed_oembed_html' ], 10, 3 ); - } + protected $amp_tag = 'amp-hulu'; + + /** + * Base URL used for identifying embeds. + * + * @var string + */ + protected $base_embed_url = 'www.hulu.com/embed.html'; /** - * Unregister embed. + * Get all raw embeds from the DOM. + * + * @param Document $dom Document. + * @return DOMNodeList A list of DOMElement nodes. */ - public function unregister_embed() { - remove_filter( 'embed_oembed_html', [ $this, 'filter_embed_oembed_html' ], 10 ); + protected function get_raw_embed_nodes( Document $dom ) { + return $dom->xpath->query( sprintf( '//iframe[ contains( @src, "%s" ) ]', $this->base_embed_url ) ); } /** - * Filter oEmbed HTML for Hulu to prepare it for AMP. + * Make embed AMP compatible. * - * @param mixed $return The oEmbed HTML. - * @param string $url The attempted embed URL. - * @param array $attr Attributes. - * @return string Embed. + * @param DOMElement $node DOM element. */ - public function filter_embed_oembed_html( $return, $url, $attr ) { - $parsed_url = wp_parse_url( $url ); - if ( false !== strpos( $parsed_url['host'], 'hulu.com' ) ) { - if ( preg_match( '/width=["\']?(\d+)/', $return, $matches ) ) { - $attr['width'] = $matches[1]; - } - if ( preg_match( '/height=["\']?(\d+)/', $return, $matches ) ) { - $attr['height'] = $matches[1]; - } - - if ( empty( $attr['height'] ) ) { - return $return; - } + protected function sanitize_raw_embed( DOMElement $node ) { + $iframe_src = $node->getAttribute( 'src' ); - $attributes = wp_array_slice_assoc( $attr, [ 'width', 'height' ] ); + parse_str( wp_parse_url( $iframe_src, PHP_URL_QUERY ), $query ); + if ( empty( $query['eid'] ) ) { + return; + } - if ( empty( $attr['width'] ) ) { - $attributes['layout'] = 'fixed-height'; - $attributes['width'] = 'auto'; - } + $attributes = [ + 'data-eid' => $query['eid'], + 'layout' => 'responsive', + 'width' => $this->DEFAULT_WIDTH, + 'height' => $this->DEFAULT_HEIGHT, + ]; - $pieces = explode( '/watch/', $parsed_url['path'] ); - if ( ! isset( $pieces[1] ) ) { - if ( ! preg_match( '/\/([A-Za-z0-9]+)/', $parsed_url['path'], $matches ) ) { - return $return; - } - $attributes['data-eid'] = $matches[1]; - } else { - $attributes['data-eid'] = $pieces[1]; - } + if ( $node->hasAttribute( 'width' ) ) { + $attributes['width'] = $node->getAttribute( 'width' ); + } - $return = AMP_HTML_Utils::build_tag( - 'amp-hulu', - $attributes - ); + if ( $node->hasAttribute( 'height' ) ) { + $attributes['height'] = $node->getAttribute( 'height' ); } - return $return; + + $amp_node = AMP_DOM_Utils::create_node( + Document::fromNode( $node ), + $this->amp_tag, + $attributes + ); + + $this->unwrap_p_element( $node ); + + $node->parentNode->replaceChild( $amp_node, $node ); } } diff --git a/includes/embeds/class-amp-imgur-embed-handler.php b/includes/embeds/class-amp-imgur-embed-handler.php index 3d862302192..e19d3f25866 100644 --- a/includes/embeds/class-amp-imgur-embed-handler.php +++ b/includes/embeds/class-amp-imgur-embed-handler.php @@ -6,145 +6,69 @@ * @since 1.0 */ +use AmpProject\Dom\Document; + /** * Class AMP_Imgur_Embed_Handler */ class AMP_Imgur_Embed_Handler extends AMP_Base_Embed_Handler { + /** - * Regex matched to produce output amp-imgur. + * Default width. * - * @var string + * @var int */ - const URL_PATTERN = '#https?://(www\.)?imgur\.com/.*#i'; + protected $DEFAULT_WIDTH = 540; /** - * Register embed. + * Default height. + * + * @var int */ - public function register_embed() { - if ( version_compare( strtok( get_bloginfo( 'version' ), '-' ), '4.9', '<' ) ) { - - // Before 4.9 the embedding Imgur is not working properly, register embed for that case. - wp_embed_register_handler( 'amp-imgur', self::URL_PATTERN, [ $this, 'oembed' ], -1 ); - } else { - add_filter( 'embed_oembed_html', [ $this, 'filter_embed_oembed_html' ], 10, 3 ); - } - } + protected $DEFAULT_HEIGHT = 500; /** - * Unregister embed. + * Default AMP tag to be used when sanitizing embeds. + * + * @var string */ - public function unregister_embed() { - if ( version_compare( strtok( get_bloginfo( 'version' ), '-' ), '4.9', '<' ) ) { - wp_embed_unregister_handler( 'amp-imgur', -1 ); - } else { - remove_filter( 'embed_oembed_html', [ $this, 'filter_embed_oembed_html' ], 10 ); - } - } + protected $amp_tag = 'amp-imgur'; /** - * Oembed. + * Get all raw embeds from the DOM. * - * @param array $matches Matches. - * @param array $attr Attributes. - * @param string $url URL. - * @return string Embed. + * @param Document $dom Document. + * @return DOMNodeList A list of DOMElement nodes. */ - public function oembed( $matches, $attr, $url ) { - return $this->render( [ 'url' => $url ] ); + protected function get_raw_embed_nodes( Document $dom ) { + return $dom->xpath->query( '//blockquote[ @class = "imgur-embed-pub" ]' ); } /** - * Render embed. + * Make embed AMP compatible. * - * @param array $args Args. - * @return string Embed. + * @param DOMElement $node DOM element. */ - public function render( $args ) { - $args = wp_parse_args( - $args, - [ - 'url' => false, - ] - ); + protected function sanitize_raw_embed( DOMElement $node ) { + $imgur_id = $node->getAttribute( 'data-id' ); - if ( empty( $args['url'] ) ) { - return ''; + if ( empty( $imgur_id ) ) { + return; } - $this->did_convert_elements = true; - - $id = $this->get_imgur_id_from_url( $args['url'] ); - if ( false === $id ) { - return ''; - } - return AMP_HTML_Utils::build_tag( - 'amp-imgur', + $amp_node = AMP_DOM_Utils::create_node( + Document::fromNode( $node ), + $this->amp_tag, [ + 'data-imgur-id' => $imgur_id, + 'layout' => 'responsive', 'width' => $this->args['width'], 'height' => $this->args['height'], - 'data-imgur-id' => $id, ] ); - } - - /** - * Filter oEmbed HTML for Imgur to prepare it for AMP. - * - * @param mixed $return The oEmbed HTML. - * @param string $url The attempted embed URL. - * @param array $attr Attributes. - * @return string Embed. - */ - public function filter_embed_oembed_html( $return, $url, $attr ) { - $parsed_url = wp_parse_url( $url ); - if ( false !== strpos( $parsed_url['host'], 'imgur.com' ) ) { - if ( preg_match( '/width=["\']?(\d+)/', $return, $matches ) ) { - $attr['width'] = $matches[1]; - } - if ( preg_match( '/height=["\']?(\d+)/', $return, $matches ) ) { - $attr['height'] = $matches[1]; - } - - if ( empty( $attr['height'] ) ) { - return $return; - } - - $attributes = wp_array_slice_assoc( $attr, [ 'width', 'height' ] ); - - if ( empty( $attr['width'] ) ) { - $attributes['layout'] = 'fixed-height'; - $attributes['width'] = 'auto'; - } - $attributes['data-imgur-id'] = $this->get_imgur_id_from_url( $url ); - if ( false === $attributes['data-imgur-id'] ) { - return $return; - } - - $return = AMP_HTML_Utils::build_tag( - 'amp-imgur', - $attributes - ); - } - return $return; - } - - /** - * Get Imgur ID from URL. - * - * @param string $url URL. - * @return bool|string ID / false. - */ - protected function get_imgur_id_from_url( $url ) { - $parsed_url = wp_parse_url( $url ); - $pieces = explode( '/gallery/', $parsed_url['path'] ); - if ( ! isset( $pieces[1] ) ) { - if ( ! preg_match( '/\/([A-Za-z0-9]+)/', $parsed_url['path'], $matches ) ) { - return false; - } - return $matches[1]; - } + $this->remove_script_sibling( $node, 's.imgur.com/min/embed.js' ); - return $pieces[1]; + $node->parentNode->replaceChild( $amp_node, $node ); } } diff --git a/includes/embeds/class-amp-instagram-embed-handler.php b/includes/embeds/class-amp-instagram-embed-handler.php index 313d455d8fb..1dddaf67d47 100644 --- a/includes/embeds/class-amp-instagram-embed-handler.php +++ b/includes/embeds/class-amp-instagram-embed-handler.php @@ -5,6 +5,7 @@ * @package AMP */ +use AmpProject\AmpWP\Embed\Registerable; use AmpProject\Dom\Document; /** @@ -12,9 +13,9 @@ * * Much of this class is borrowed from Jetpack embeds */ -class AMP_Instagram_Embed_Handler extends AMP_Base_Embed_Handler { - const SHORT_URL_HOST = 'instagr.am'; - const URL_PATTERN = '#https?:\/\/(www\.)?instagr(\.am|am\.com)\/(p|tv)\/([A-Za-z0-9-_]+)#i'; +class AMP_Instagram_Embed_Handler extends AMP_Base_Embed_Handler implements Registerable { + + const URL_PATTERN = '#https?:\/\/(www\.)?instagr(\.am|am\.com)\/(p|tv)\/([A-Za-z0-9-_]+)#i'; /** * Default width. @@ -31,143 +32,52 @@ class AMP_Instagram_Embed_Handler extends AMP_Base_Embed_Handler { protected $DEFAULT_HEIGHT = 600; /** - * Tag. + * Default AMP tag to be used when sanitizing embeds. * - * @var string embed HTML blockquote tag to identify and replace with AMP version. + * @var string */ - protected $sanitize_tag = 'blockquote'; + protected $amp_tag = 'amp-instagram'; /** - * Tag. + * Register the embed. * - * @var string AMP amp-facebook tag - */ - private $amp_tag = 'amp-instagram'; - - /** - * Registers embed. + * @return void */ public function register_embed() { - wp_embed_register_handler( $this->amp_tag, self::URL_PATTERN, [ $this, 'oembed' ], -1 ); - } - - /** - * Unregisters embed. - */ - public function unregister_embed() { - wp_embed_unregister_handler( $this->amp_tag, -1 ); - } - - /** - * WordPress OEmbed rendering callback. - * - * @param array $matches URL pattern matches. - * @param array $attr Matched attributes. - * @param string $url Matched URL. - * @return string HTML markup for rendered embed. - */ - public function oembed( $matches, $attr, $url ) { - return $this->render( - [ - 'url' => $url, - 'instagram_id' => end( $matches ), - ] - ); - } - - /** - * Gets the rendered embed markup. - * - * @param array $args Embed rendering arguments. - * @return string HTML markup for rendered embed. - */ - public function render( $args ) { - $args = wp_parse_args( - $args, - [ - 'url' => false, - 'instagram_id' => false, - ] - ); - - if ( empty( $args['instagram_id'] ) ) { - return AMP_HTML_Utils::build_tag( - 'a', - [ - 'href' => esc_url_raw( $args['url'] ), - 'class' => 'amp-wp-embed-fallback', - ], - esc_html( $args['url'] ) - ); + if ( version_compare( get_bloginfo( 'version' ), '5.1', '>=' ) ) { + return; } - $this->did_convert_elements = true; - - return AMP_HTML_Utils::build_tag( - $this->amp_tag, - [ - 'data-shortcode' => $args['instagram_id'], - 'data-captioned' => '', - 'layout' => 'responsive', - 'width' => $this->args['width'], - 'height' => $this->args['height'], - ] - ); + // The oEmbed provider for Instagram does not accommodate Instagram TV URLs on WP < 5.1. Modifying the provider format + // here will allow for the oEmbed HTML to be fetched, and can then sanitized later below. + wp_oembed_remove_provider( '#https?://(www\.)?instagr(\.am|am\.com)/p/.*#i' ); + wp_oembed_add_provider( self::URL_PATTERN, 'https://api.instagram.com/oembed', true ); } /** - * Get Instagram ID from URL. + * Unregister the embed. * - * @param string $url URL. - * @return string|false The ID parsed from the URL or false if not found. + * @return void */ - private function get_instagram_id_from_url( $url ) { - $found = preg_match( self::URL_PATTERN, $url, $matches ); - - if ( ! $found ) { - return false; - } - - return end( $matches ); + public function unregister_embed() { } /** - * Sanitized
tags to + * Get all raw embeds from the DOM. * - * @param Document $dom DOM. + * @param Document $dom Document. + * @return DOMNodeList A list of DOMElement nodes. */ - public function sanitize_raw_embeds( Document $dom ) { - /** - * Node list. - * - * @var DOMNodeList $nodes - */ - $nodes = $dom->getElementsByTagName( $this->sanitize_tag ); - $num_nodes = $nodes->length; - - if ( 0 === $num_nodes ) { - return; - } - - for ( $i = $num_nodes - 1; $i >= 0; $i-- ) { - $node = $nodes->item( $i ); - if ( ! $node instanceof DOMElement ) { - continue; - } - - if ( $node->hasAttribute( 'data-instgrm-permalink' ) ) { - $this->create_amp_instagram_and_replace_node( $dom, $node ); - } - } + protected function get_raw_embed_nodes( Document $dom ) { + return $dom->xpath->query( '//blockquote[ @data-instgrm-permalink ]' ); } /** - * Make final modifications to DOMNode + * Make embed AMP compatible. * - * @param Document $dom The HTML Document. - * @param DOMElement $node The DOMNode to adjust and replace. + * @param DOMElement $node DOM element. */ - private function create_amp_instagram_and_replace_node( $dom, $node ) { + protected function sanitize_raw_embed( DOMElement $node ) { $instagram_id = $this->get_instagram_id_from_url( $node->getAttribute( 'data-instgrm-permalink' ) ); $node_args = [ @@ -181,47 +91,26 @@ private function create_amp_instagram_and_replace_node( $dom, $node ) { $node_args['data-captioned'] = ''; } - $new_node = AMP_DOM_Utils::create_node( $dom, $this->amp_tag, $node_args ); + $new_node = AMP_DOM_Utils::create_node( Document::fromNode( $node ), $this->amp_tag, $node_args ); - $this->sanitize_embed_script( $node ); + $this->remove_script_sibling( $node, 'instagram.com/embed.js' ); $node->parentNode->replaceChild( $new_node, $node ); - - $this->did_convert_elements = true; } /** - * Removes Instagram's embed #s', '', $cache ); - return null !== $modified_block_content ? $modified_block_content : $cache; + $this->remove_script_sibling( $node, 'v0.wordpress.com/js/next/videopress-iframe.js' ); + $this->unwrap_p_element( $node ); } } diff --git a/includes/embeds/class-amp-youtube-embed-handler.php b/includes/embeds/class-amp-youtube-embed-handler.php index 2970a3ecaba..89467426f02 100644 --- a/includes/embeds/class-amp-youtube-embed-handler.php +++ b/includes/embeds/class-amp-youtube-embed-handler.php @@ -5,6 +5,8 @@ * @package AMP */ +use AmpProject\Dom\Document; + /** * Class AMP_YouTube_Embed_Handler * @@ -12,16 +14,6 @@ */ class AMP_YouTube_Embed_Handler extends AMP_Base_Embed_Handler { - /** - * URL pattern to match YouTube videos. - * - * Only handling single videos. Playlists are handled elsewhere. - * - * @deprecated No longer used. - * @var string - */ - const URL_PATTERN = '#https?://(?:www\.)?(?:youtube.com/(?:v/|e/|embed/|watch[/\#?])|youtu\.be/).*#i'; - /** * Ratio for calculating the default height from the content width. * @@ -43,6 +35,20 @@ class AMP_YouTube_Embed_Handler extends AMP_Base_Embed_Handler { */ protected $DEFAULT_HEIGHT = 338; + /** + * Default AMP tag to be used when sanitizing embeds. + * + * @var string + */ + protected $amp_tag = 'amp-youtube'; + + /** + * List of domains that are applicable for this embed. + * + * @var string[] + */ + protected $applicable_domains = [ 'youtu.be', 'youtube.com', 'youtube-nocookie.com' ]; + /** * AMP_YouTube_Embed_Handler constructor. * @@ -60,119 +66,98 @@ public function __construct( $args = [] ) { } /** - * Register embed. - */ - public function register_embed() { - add_filter( 'embed_oembed_html', [ $this, 'filter_embed_oembed_html' ], 10, 2 ); - add_filter( 'wp_video_shortcode_override', [ $this, 'video_override' ], 10, 2 ); - } - - /** - * Unregister embed. + * Get all raw embeds from the DOM. + * + * @param Document $dom Document. + * @return DOMNodeList A list of DOMElement nodes. */ - public function unregister_embed() { - remove_filter( 'embed_oembed_html', [ $this, 'filter_embed_oembed_html' ], 10 ); + protected function get_raw_embed_nodes( Document $dom ) { + $query_segments = array_map( + static function ( $domain ) { + return sprintf( 'contains( @src, "%s" )', $domain ); + }, + $this->applicable_domains + ); + $query = implode( ' or ', $query_segments ); + return $dom->xpath->query( sprintf( '//iframe[ %s ]', $query ) ); } /** - * Filter oEmbed HTML for YouTube to convert to AMP. + * Make embed AMP compatible. * - * @param string $cache Cache for oEmbed. - * @param string $url Embed URL. - * @return string Embed. + * @param DOMElement $node DOM element. */ - public function filter_embed_oembed_html( $cache, $url ) { - $id = $this->get_video_id_from_url( $url ); - if ( ! $id ) { - return $cache; + protected function sanitize_raw_embed( DOMElement $node ) { + $iframe_src = $node->getAttribute( 'src' ); + $video_id = $this->get_video_id_from_url( $iframe_src ); + + $attributes = [ + 'data-videoid' => $video_id, + 'layout' => 'responsive', + 'width' => $this->args['width'], + 'height' => $this->args['height'], + ]; + + if ( ! empty( $node->getAttribute( 'title' ) ) ) { + $attributes['title'] = $node->getAttribute( 'title' ); } - $props = $this->parse_props( $cache, $url, $id ); - if ( empty( $props ) ) { - return $cache; + if ( ! empty( $node->getAttribute( 'width' ) ) ) { + $attributes['width'] = $node->getAttribute( 'width' ); } - $props['video_id'] = $id; - return $this->render( $props, $url ); + if ( ! empty( $node->getAttribute( 'height' ) ) ) { + $attributes['height'] = $node->getAttribute( 'height' ); + } + + $amp_node = AMP_DOM_Utils::create_node( + Document::fromNode( $node ), + $this->amp_tag, + $attributes + ); + + $this->append_placeholder( $amp_node, $video_id, isset( $attributes['title'] ) ? $attributes['title'] : null ); + + $this->unwrap_p_element( $node ); + + $node->parentNode->replaceChild( $amp_node, $node ); } /** - * Parse AMP component from iframe. + * Append placeholder as a child of the AMP component. * - * @param string $html HTML. - * @param string $url Embed URL, for fallback purposes. - * @param string $video_id YouTube video ID. - * @return array|null Props for rendering the component, or null if unable to parse. + * @param DOMElement $node AMP component. + * @param string $video_id Video ID. + * @param string $video_title Video title. */ - private function parse_props( $html, $url, $video_id ) { - $props = $this->match_element_attributes( $html, 'iframe', [ 'title', 'height', 'width' ] ); - if ( ! isset( $props ) ) { - return null; - } - + private function append_placeholder( DOMElement $node, $video_id, $video_title ) { $img_attributes = [ 'src' => esc_url_raw( sprintf( 'https://i.ytimg.com/vi/%s/hqdefault.jpg', $video_id ) ), 'layout' => 'fill', 'object-fit' => 'cover', ]; - if ( ! empty( $props['title'] ) ) { - $img_attributes['alt'] = $props['title']; + if ( $video_title ) { + $img_attributes['alt'] = $video_title; } - $img = AMP_HTML_Utils::build_tag( 'img', $img_attributes ); - $props['placeholder'] = AMP_HTML_Utils::build_tag( - 'a', - [ - 'placeholder' => '', - 'href' => esc_url_raw( $url ), - ], - $img + $img_node = AMP_DOM_Utils::create_node( + Document::fromNode( $node->ownerDocument ), + 'img', + $img_attributes ); - return $props; - } - - /** - * Render embed. - * - * @param array $args Args. - * @param string $url URL. - * @return string Rendered. - */ - public function render( $args, $url ) { - $args = wp_parse_args( - $args, + $placeholder_node = AMP_DOM_Utils::create_node( + Document::fromNode( $node ), + 'a', [ - 'video_id' => false, - 'layout' => 'responsive', - 'width' => $this->args['width'], - 'height' => $this->args['height'], 'placeholder' => '', + 'href' => esc_url_raw( sprintf( 'https://www.youtube.com/watch?v=%s', $video_id ) ), ] ); - if ( empty( $args['video_id'] ) ) { - return AMP_HTML_Utils::build_tag( - 'a', - [ - 'href' => esc_url_raw( $url ), - 'class' => 'amp-wp-embed-fallback', - ], - esc_html( $url ) - ); - } - - $this->did_convert_elements = true; - - $attributes = array_merge( - [ 'data-videoid' => $args['video_id'] ], - wp_array_slice_assoc( $args, [ 'layout', 'width', 'height' ] ) - ); - if ( ! empty( $args['title'] ) ) { - $attributes['title'] = $args['title']; - } + $placeholder_node->appendChild( $img_node ); - return AMP_HTML_Utils::build_tag( 'amp-youtube', $attributes, $args['placeholder'] ); + $node->appendChild( $placeholder_node ); } /** @@ -189,7 +174,7 @@ private function get_video_id_from_url( $url ) { } $domain = implode( '.', array_slice( explode( '.', $parsed_url['host'] ), -2 ) ); - if ( ! in_array( $domain, [ 'youtu.be', 'youtube.com', 'youtube-nocookie.com' ], true ) ) { + if ( ! in_array( $domain, $this->applicable_domains, true ) ) { return false; } @@ -207,7 +192,8 @@ private function get_video_id_from_url( $url ) { // Support is also included for other query params which don't appear to be supported by YouTube anymore. if ( isset( $query_vars['v'] ) ) { return $query_vars['v']; - } elseif ( isset( $query_vars['vi'] ) ) { + } + if ( isset( $query_vars['vi'] ) ) { return $query_vars['vi']; } } @@ -232,26 +218,4 @@ private function get_video_id_from_url( $url ) { return false; } - - /** - * Override the output of YouTube videos. - * - * This overrides the value in wp_video_shortcode(). - * The pattern matching is copied from WP_Widget_Media_Video::render(). - * - * @param string $html Empty variable to be replaced with shortcode markup. - * @param array $attr The shortcode attributes. - * @return string|null $markup The markup to output. - */ - public function video_override( $html, $attr ) { - if ( ! isset( $attr['src'] ) ) { - return $html; - } - $video_id = $this->get_video_id_from_url( $attr['src'] ); - if ( ! $video_id ) { - return $html; - } - - return $this->render( compact( 'video_id' ), $attr['src'] ); - } } diff --git a/includes/sanitizers/class-amp-embed-sanitizer.php b/includes/sanitizers/class-amp-embed-sanitizer.php index b0da8f73865..26fdc738157 100644 --- a/includes/sanitizers/class-amp-embed-sanitizer.php +++ b/includes/sanitizers/class-amp-embed-sanitizer.php @@ -36,14 +36,12 @@ public function __construct( $dom, $args = [] ) { } /** - * Checks if each embed_handler has sanitize_raw_method and calls it. + * Allow each embed handler sanitize their respective raw embeds. */ public function sanitize() { foreach ( $this->embed_handlers as $embed_handler ) { - if ( method_exists( $embed_handler, 'sanitize_raw_embeds' ) ) { - $embed_handler->sanitize_raw_embeds( $this->dom, $this->args ); - } + $embed_handler->sanitize_raw_embeds( $this->dom ); } } } diff --git a/includes/templates/class-amp-content.php b/includes/templates/class-amp-content.php index 3038d542375..1174abeefeb 100644 --- a/includes/templates/class-amp-content.php +++ b/includes/templates/class-amp-content.php @@ -5,6 +5,8 @@ * @package AMP */ +use AmpProject\AmpWP\Embed\Registerable; + /** * Class AMP_Content * @@ -184,7 +186,9 @@ private function register_embed_handlers( $embed_handler_classes ) { continue; } - $embed_handler->register_embed(); + if ( $embed_handler instanceof Registerable ) { + $embed_handler->register_embed(); + } $embed_handlers[] = $embed_handler; } @@ -198,8 +202,9 @@ private function register_embed_handlers( $embed_handler_classes ) { */ private function unregister_embed_handlers( $embed_handlers ) { foreach ( $embed_handlers as $embed_handler ) { - $this->add_scripts( $embed_handler->get_scripts() ); // @todo Why add_scripts here? Shouldn't it be array_diff()? - $embed_handler->unregister_embed(); + if ( $embed_handler instanceof Registerable ) { + $embed_handler->unregister_embed(); + } } } diff --git a/src/Embed/Registerable.php b/src/Embed/Registerable.php new file mode 100644 index 00000000000..d20d842cd43 --- /dev/null +++ b/src/Embed/Registerable.php @@ -0,0 +1,29 @@ + [ 'https://poll.fm/7012505', - '

', + '' . PHP_EOL, $poll_response, ], 'polldaddy_poll' => [ 'https://polldaddy.com/poll/7012505/', - '

', + '' . PHP_EOL, $poll_response, ], 'polldaddy_survey' => [ 'https://rydk.polldaddy.com/s/test-survey', - '

View Survey

', + '' . PHP_EOL . PHP_EOL, $survey_response, ], - ]; - /* - * There is a bug with WordPress's oEmbed handling for Crowdsignal surveys. - * See . - */ - if ( version_compare( get_bloginfo( 'version' ), '5.2.0', '>=' ) ) { - $data['survey.fm'] = [ + 'survey.fm' => [ 'https://rydk.survey.fm/test-survey', - '

View Survey

', + '' . PHP_EOL . PHP_EOL, $survey_response, - ]; - } + ], + ]; return $data; } @@ -111,11 +105,15 @@ static function ( $pre, $r, $request_url ) use ( $oembed_response ) { $embed = new AMP_Crowdsignal_Embed_Handler(); $embed->register_embed(); + $filtered_content = apply_filters( 'the_content', $url ); + $dom = AMP_DOM_Utils::get_dom_from_content( $filtered_content ); + $embed->sanitize_raw_embeds( $dom ); + $content = AMP_DOM_Utils::get_content_from_dom( $dom ); $expected = $this->adapt_iframe_title( $expected ); - $this->assertEquals( trim( $expected ), trim( $filtered_content ) ); + $this->assertEquals( $expected, $content ); } private function adapt_iframe_title( $html ) { diff --git a/tests/php/test-amp-dailymotion-embed-handler.php b/tests/php/test-amp-dailymotion-embed-handler.php index 0e86c2655c3..906a85f229d 100644 --- a/tests/php/test-amp-dailymotion-embed-handler.php +++ b/tests/php/test-amp-dailymotion-embed-handler.php @@ -4,7 +4,55 @@ class AMP_DailyMotion_Embed_Handler_Test extends WP_UnitTestCase { - use WithoutBlockPreRendering; + use WithoutBlockPreRendering { + setUp as public prevent_block_pre_render; + } + + /** + * Set up. + */ + public function setUp() { + $this->prevent_block_pre_render(); + + // Mock the HTTP request. + add_filter( 'pre_http_request', [ $this, 'mock_http_request' ], 10, 3 ); + } + + /** + * Tear down. + */ + public function tearDown() { + remove_filter( 'pre_http_request', [ $this, 'mock_http_request' ] ); + parent::tearDown(); + } + + /** + * Mock HTTP request. + * + * @param mixed $pre Whether to preempt an HTTP request's return value. Default false. + * @param mixed $r HTTP request arguments. + * @param string $url The request URL. + * @return array Response data. + */ + public function mock_http_request( $pre, $r, $url ) { + if ( in_array( 'external-http', $_SERVER['argv'], true ) ) { + return $pre; + } + + if ( false === strpos( $url, 'dailymotion.com' ) ) { + return $pre; + } + + $body = '{"type":"video","version":"1.0","provider_name":"Dailymotion","provider_url":"https:\/\/www.dailymotion.com","title":"Snatched - Official Trailer 2 (HD)","description":"M\u00e1s info http:\/\/trailersyestrenos.es\/snatched-jonathan-levine\/ - TWITTER: https:\/\/twitter.com\/TrailersyEstren - FACEBOOK: https:\/\/www.facebook.com\/trailersyestrenos - GOOGLE+: https:\/\/www.google.com\/+TrailersyEstrenos Sinopsis: Una madre y una hija se enfrentar\u00e1n a distintos problemas que surgen mientras est\u00e1n de vacaciones Director: Jonathan Levine Reparto: Amy Schumer, Ike Barinholtz, Goldie Hawn, Christopher Meloni, Randall Park, Wanda Sykes, \u00d3scar Jaenada, Colin Quinn, Tom Bateman, Kevin Kane, Sharon M. Bell (El trailer pertenece a la productora y distribuidora de la pel\u00edcula y ha sido subido sin \u00e1nimo de lucro)","author_name":"Trailers y Estrenos","author_url":"https:\/\/www.dailymotion.com\/TrailersyEstrenos","width":500,"height":212,"html":"

' . PHP_EOL, + '' . PHP_EOL, ], ]; @@ -92,7 +92,7 @@ public function get_conversion_data() { if ( version_compare( strtok( get_bloginfo( 'version' ), '-' ), '5.1', '<' ) ) { $data['document_embed'] = [ $this->scribd_doc_url . PHP_EOL, - '

' . PHP_EOL, + '' . PHP_EOL, ]; } @@ -102,8 +102,6 @@ public function get_conversion_data() { /** * Test conversion. * - * @covers AMP_Scribd_Embed_Handler::filter_embed_oembed_html() - * @covers AMP_Scribd_Embed_Handler::sanitize_iframe() * @dataProvider get_conversion_data * * @param $source @@ -111,10 +109,14 @@ public function get_conversion_data() { */ public function test__conversion( $source, $expected ) { $embed = new AMP_Scribd_Embed_Handler(); - $embed->register_embed(); + $filtered_content = apply_filters( 'the_content', $source ); + $dom = AMP_DOM_Utils::get_dom_from_content( $filtered_content ); + $embed->sanitize_raw_embeds( $dom ); + + $content = AMP_DOM_Utils::get_content_from_dom( $dom ); - $this->assertEquals( $expected, $filtered_content ); + $this->assertEquals( $expected, $content ); } /** @@ -146,10 +148,12 @@ public function get_scripts_data() { */ public function test__get_scripts( $source, $expected ) { $embed = new AMP_Scribd_Embed_Handler(); - $embed->register_embed(); - $source = apply_filters( 'the_content', $source ); - $validating_sanitizer = new AMP_Tag_And_Attribute_Sanitizer( AMP_DOM_Utils::get_dom_from_content( $source ) ); + $filtered_content = apply_filters( 'the_content', $source ); + $dom = AMP_DOM_Utils::get_dom_from_content( $filtered_content ); + $embed->sanitize_raw_embeds( $dom ); + + $validating_sanitizer = new AMP_Tag_And_Attribute_Sanitizer( $dom ); $validating_sanitizer->sanitize(); $scripts = array_merge( diff --git a/tests/php/test-amp-soundcloud-embed-handler.php b/tests/php/test-amp-soundcloud-embed-handler.php index 5a26d7f53d4..8504a517072 100644 --- a/tests/php/test-amp-soundcloud-embed-handler.php +++ b/tests/php/test-amp-soundcloud-embed-handler.php @@ -81,7 +81,6 @@ public function mock_http_request( $preempt, $r, $url ) { if ( false === strpos( $url, 'soundcloud.com' ) ) { return $preempt; } - unset( $r ); if ( false !== strpos( $url, 'sets' ) ) { $body = $this->playlist_oembed_response; @@ -115,12 +114,12 @@ public function get_embed_conversion_data() { 'track_simple' => [ $this->track_url . PHP_EOL, - '

' . ( function_exists( 'wp_filter_oembed_iframe_title_attribute' ) ? 'Mozart – Requiem in D minor Complete Full by Jack Villano Villano' : '' ) . '

' . PHP_EOL, + '' . PHP_EOL, ], 'playlist_simple' => [ $this->playlist_url . PHP_EOL, - '

' . ( function_exists( 'wp_filter_oembed_iframe_title_attribute' ) ? 'Classical Music – The Essential Collection by Classical Music' : '' ) . '

' . PHP_EOL, + '' . PHP_EOL, ], ]; } @@ -129,18 +128,20 @@ public function get_embed_conversion_data() { * Test conversion. * * @dataProvider get_embed_conversion_data - * @covers AMP_SoundCloud_Embed_Handler::filter_embed_oembed_html() - * @covers AMP_SoundCloud_Embed_Handler::render() * * @param string $source Source. * @param string $expected Expected. */ public function test_embed_conversion( $source, $expected ) { $embed = new AMP_SoundCloud_Embed_Handler(); - $embed->register_embed(); + $filtered_content = apply_filters( 'the_content', $source ); + $dom = AMP_DOM_Utils::get_dom_from_content( $filtered_content ); + $embed->sanitize_raw_embeds( $dom ); + + $content = AMP_DOM_Utils::get_content_from_dom( $dom ); - $this->assertEquals( $expected, $filtered_content ); + $this->assertEquals( $expected, $content ); } /** @@ -176,10 +177,12 @@ public function get_scripts_data() { */ public function test__get_scripts( $source, $expected ) { $embed = new AMP_SoundCloud_Embed_Handler(); - $embed->register_embed(); - $source = apply_filters( 'the_content', $source ); - $validating_sanitizer = new AMP_Tag_And_Attribute_Sanitizer( AMP_DOM_Utils::get_dom_from_content( $source ) ); + $filtered_content = apply_filters( 'the_content', $source ); + $dom = AMP_DOM_Utils::get_dom_from_content( $filtered_content ); + $embed->sanitize_raw_embeds( $dom ); + + $validating_sanitizer = new AMP_Tag_And_Attribute_Sanitizer( $dom ); $validating_sanitizer->sanitize(); $scripts = array_merge( diff --git a/tests/php/test-amp-tumblr-embed-handler.php b/tests/php/test-amp-tumblr-embed-handler.php new file mode 100644 index 00000000000..83c8e24750f --- /dev/null +++ b/tests/php/test-amp-tumblr-embed-handler.php @@ -0,0 +1,119 @@ +prevent_block_pre_render(); + + // Mock the HTTP request. + add_filter( 'pre_http_request', [ $this, 'mock_http_request' ], 10, 3 ); + } + + /** + * Tear down. + */ + public function tearDown() { + remove_filter( 'pre_http_request', [ $this, 'mock_http_request' ] ); + parent::tearDown(); + } + + /** + * Mock HTTP request. + * + * @param mixed $pre Whether to preempt an HTTP request's return value. Default false. + * @param mixed $r HTTP request arguments. + * @param string $url The request URL. + * @return array Response data. + */ + public function mock_http_request( $pre, $r, $url ) { + if ( in_array( 'external-http', $_SERVER['argv'], true ) ) { + return $pre; + } + + if ( false === strpos( $url, 'tumblr.com' ) ) { + return $pre; + } + + $body = '{"cache_age":3600,"url":"https:\/\/ifpaintingscouldtext.tumblr.com\/post\/92003045635\/grant-wood-american-gothic-1930","provider_url":"https:\/\/www.tumblr.com","provider_name":"Tumblr","author_name":"If Paintings Could Text","version":"1.0","author_url":"https:\/\/ifpaintingscouldtext.tumblr.com\/","type":"rich","html":"\u003Cdiv class=\u0022tumblr-post\u0022 data-href=\u0022https:\/\/embed.tumblr.com\/embed\/post\/2JT2XTaiTxO08wh21dqQrw\/92003045635\u0022 data-did=\u00227ce4825965cbd8bfd208f6aae43de7a528859aee\u0022 \u003E\u003Ca href=\u0022https:\/\/ifpaintingscouldtext.tumblr.com\/post\/92003045635\/grant-wood-american-gothic-1930\u0022\u003Ehttps:\/\/ifpaintingscouldtext.tumblr.com\/post\/92003045635\/grant-wood-american-gothic-1930\u003C\/a\u003E\u003C\/div\u003E\u003Cscript async src=\u0022https:\/\/assets.tumblr.com\/post.js\u0022\u003E\u003C\/script\u003E","height":null,"width":540}'; + + return [ + 'body' => $body, + 'response' => [ + 'code' => 200, + 'message' => 'OK', + ], + ]; + } + + public function get_conversion_data() { + return [ + 'no_embed' => [ + '

Hello world.

', + '

Hello world.

' . PHP_EOL, + ], + + 'url_simple' => [ + 'https://ifpaintingscouldtext.tumblr.com/post/92003045635/grant-wood-american-gothic-1930' . PHP_EOL, + '
See more
https://ifpaintingscouldtext.tumblr.com/post/92003045635/grant-wood-american-gothic-1930
' . PHP_EOL . PHP_EOL, + ], + ]; + } + + /** + * @dataProvider get_conversion_data + */ + public function test__conversion( $source, $expected ) { + $embed = new AMP_Tumblr_Embed_Handler(); + + $filtered_content = apply_filters( 'the_content', $source ); + $dom = AMP_DOM_Utils::get_dom_from_content( $filtered_content ); + $embed->sanitize_raw_embeds( $dom ); + + $content = AMP_DOM_Utils::get_content_from_dom( $dom ); + + $this->assertEquals( $expected, $content ); + } + + public function get_scripts_data() { + return [ + 'not_converted' => [ + '

Hello World.

', + [], + ], + 'converted' => [ + 'https://ifpaintingscouldtext.tumblr.com/post/92003045635/grant-wood-american-gothic-1930' . PHP_EOL, + [ 'amp-iframe' => true ], + ], + ]; + } + + /** + * @dataProvider get_scripts_data + */ + public function test__get_scripts( $source, $expected ) { + $embed = new AMP_Tumblr_Embed_Handler(); + + $filtered_content = apply_filters( 'the_content', $source ); + $dom = AMP_DOM_Utils::get_dom_from_content( $filtered_content ); + $embed->sanitize_raw_embeds( $dom ); + + $validating_sanitizer = new AMP_Tag_And_Attribute_Sanitizer( $dom ); + $validating_sanitizer->sanitize(); + + $scripts = array_merge( + $embed->get_scripts(), + $validating_sanitizer->get_scripts() + ); + + $this->assertEquals( $expected, $scripts ); + } +} diff --git a/tests/php/test-amp-twitter-embed-handler.php b/tests/php/test-amp-twitter-embed-handler.php index d652da70fef..2a3b4450aed 100644 --- a/tests/php/test-amp-twitter-embed-handler.php +++ b/tests/php/test-amp-twitter-embed-handler.php @@ -18,20 +18,6 @@ class AMP_Twitter_Embed_Handler_Test extends WP_UnitTestCase { setUp as public prevent_block_pre_render; } - /** - * oEmbed response for the tweet ID 987437752164737025. - * - * @var string - */ - protected $oembed_response_1 = '{"url":"https:\/\/twitter.com\/WordPress\/status\/987437752164737025","author_name":"WordPress","author_url":"https:\/\/twitter.com\/WordPress","html":"\u003Cblockquote class=\"twitter-tweet\" data-width=\"500\" data-dnt=\"true\"\u003E\u003Cp lang=\"en\" dir=\"ltr\"\u003ECelebrate the WordPress 15th Anniversary on May 27 \u003Ca href=\"https:\/\/t.co\/jv62WkI9lr\"\u003Ehttps:\/\/t.co\/jv62WkI9lr\u003C\/a\u003E \u003Ca href=\"https:\/\/t.co\/4ZECodSK78\"\u003Epic.twitter.com\/4ZECodSK78\u003C\/a\u003E\u003C\/p\u003E— WordPress (@WordPress) \u003Ca href=\"https:\/\/twitter.com\/WordPress\/status\/987437752164737025?ref_src=twsrc%5Etfw\"\u003EApril 20, 2018\u003C\/a\u003E\u003C\/blockquote\u003E\n\u003Cscript async src=\"https:\/\/platform.twitter.com\/widgets.js\" charset=\"utf-8\"\u003E\u003C\/script\u003E\n","width":500,"height":null,"type":"rich","cache_age":"3153600000","provider_name":"Twitter","provider_url":"https:\/\/twitter.com","version":"1.0"}'; - - /** - * oEmbed response for the tweet ID 705219971425574912. - * - * @var string - */ - protected $oembed_response_2 = '{"url":"https:\/\/twitter.com\/sengineland\/status\/705219971425574912","author_name":"Search Engine Land","author_url":"https:\/\/twitter.com\/sengineland","html":"\u003Cblockquote class=\"twitter-tweet\" data-width=\"500\" data-dnt=\"true\"\u003E\u003Cp lang=\"en\" dir=\"ltr\"\u003EOn our way to the \u003Ca href=\"https:\/\/twitter.com\/hashtag\/GoogleDance?src=hash&ref_src=twsrc%5Etfw\"\u003E#GoogleDance\u003C\/a\u003E! \u003Ca href=\"https:\/\/twitter.com\/hashtag\/SMX?src=hash&ref_src=twsrc%5Etfw\"\u003E#SMX\u003C\/a\u003E \uD83D\uDC83\uD83C\uDFFB \u003Ca href=\"https:\/\/t.co\/N8kZ9M3eN4\"\u003Epic.twitter.com\/N8kZ9M3eN4\u003C\/a\u003E\u003C\/p\u003E— Search Engine Land (@sengineland) \u003Ca href=\"https:\/\/twitter.com\/sengineland\/status\/705219971425574912?ref_src=twsrc%5Etfw\"\u003EMarch 3, 2016\u003C\/a\u003E\u003C\/blockquote\u003E\n\u003Cscript async src=\"https:\/\/platform.twitter.com\/widgets.js\" charset=\"utf-8\"\u003E\u003C\/script\u003E\n","width":500,"height":null,"type":"rich","cache_age":"3153600000","provider_name":"Twitter","provider_url":"https:\/\/twitter.com","version":"1.0"}'; - /** * Set up each test. */ @@ -69,13 +55,21 @@ public function mock_http_request( $preempt, $r, $url ) { } if ( false !== strpos( $url, '987437752164737025' ) ) { - $body = $this->oembed_response_1; + $body = '{"url":"https:\/\/twitter.com\/WordPress\/status\/987437752164737025","author_name":"WordPress","author_url":"https:\/\/twitter.com\/WordPress","html":"\u003Cblockquote class=\"twitter-tweet\" data-width=\"500\" data-dnt=\"true\"\u003E\u003Cp lang=\"en\" dir=\"ltr\"\u003ECelebrate the WordPress 15th Anniversary on May 27 \u003Ca href=\"https:\/\/t.co\/jv62WkI9lr\"\u003Ehttps:\/\/t.co\/jv62WkI9lr\u003C\/a\u003E \u003Ca href=\"https:\/\/t.co\/4ZECodSK78\"\u003Epic.twitter.com\/4ZECodSK78\u003C\/a\u003E\u003C\/p\u003E— WordPress (@WordPress) \u003Ca href=\"https:\/\/twitter.com\/WordPress\/status\/987437752164737025?ref_src=twsrc%5Etfw\"\u003EApril 20, 2018\u003C\/a\u003E\u003C\/blockquote\u003E\n\u003Cscript async src=\"https:\/\/platform.twitter.com\/widgets.js\" charset=\"utf-8\"\u003E\u003C\/script\u003E\n","width":500,"height":null,"type":"rich","cache_age":"3153600000","provider_name":"Twitter","provider_url":"https:\/\/twitter.com","version":"1.0"}'; + } elseif ( false !== strpos( $url, '705219971425574912' ) ) { + $body = '{"url":"https:\/\/twitter.com\/sengineland\/status\/705219971425574912","author_name":"Search Engine Land","author_url":"https:\/\/twitter.com\/sengineland","html":"\u003Cblockquote class=\"twitter-tweet\" data-width=\"500\" data-dnt=\"true\"\u003E\u003Cp lang=\"en\" dir=\"ltr\"\u003EOn our way to the \u003Ca href=\"https:\/\/twitter.com\/hashtag\/GoogleDance?src=hash&ref_src=twsrc%5Etfw\"\u003E#GoogleDance\u003C\/a\u003E! \u003Ca href=\"https:\/\/twitter.com\/hashtag\/SMX?src=hash&ref_src=twsrc%5Etfw\"\u003E#SMX\u003C\/a\u003E \uD83D\uDC83\uD83C\uDFFB \u003Ca href=\"https:\/\/t.co\/N8kZ9M3eN4\"\u003Epic.twitter.com\/N8kZ9M3eN4\u003C\/a\u003E\u003C\/p\u003E— Search Engine Land (@sengineland) \u003Ca href=\"https:\/\/twitter.com\/sengineland\/status\/705219971425574912?ref_src=twsrc%5Etfw\"\u003EMarch 3, 2016\u003C\/a\u003E\u003C\/blockquote\u003E\n\u003Cscript async src=\"https:\/\/platform.twitter.com\/widgets.js\" charset=\"utf-8\"\u003E\u003C\/script\u003E\n","width":500,"height":null,"type":"rich","cache_age":"3153600000","provider_name":"Twitter","provider_url":"https:\/\/twitter.com","version":"1.0"}'; + } elseif ( false !== strpos( $url, 'moments%2F625792726546558977' ) ) { + $body = '{"url":"https:\/\/twitter.com\/i\/moments\/625792726546558977","title":"Michelle Obama Opens Special Olympics","html":"\u003Ca class=\"twitter-moment\" data-width=\"500\" data-dnt=\"true\" href=\"https:\/\/twitter.com\/i\/moments\/625792726546558977?ref_src=twsrc%5Etfw\"\u003EMichelle Obama Opens Special Olympics\u003C\/a\u003E\n\u003Cscript async src=\"https:\/\/platform.twitter.com\/widgets.js\" charset=\"utf-8\"\u003E\u003C\/script\u003E\n","width":500,"height":null,"type":"rich","cache_age":"3153600000","provider_name":"Twitter","provider_url":"https:\/\/twitter.com","version":"1.0"}'; + } elseif ( false !== strpos( $url, 'lists%2Fweb-gdes' ) ) { + $body = '{"url":"https:\/\/twitter.com\/robertnyman\/lists\/web-gdes","title":"Web GDEs","html":"\u003Ca class=\"twitter-timeline\" data-width=\"500\" data-height=\"750\" data-dnt=\"true\" href=\"https:\/\/twitter.com\/robertnyman\/lists\/web-gdes?ref_src=twsrc%5Etfw\"\u003EA Twitter List by robertnyman\u003C\/a\u003E\n\u003Cscript async src=\"https:\/\/platform.twitter.com\/widgets.js\" charset=\"utf-8\"\u003E\u003C\/script\u003E\n","width":500,"height":null,"type":"rich","cache_age":"3153600000","provider_name":"Twitter","provider_url":"https:\/\/twitter.com","version":"1.0"}'; + } elseif ( false !== strpos( $url, 'wordpress%2Flikes' ) ) { // phpcs:ignore WordPress.WP.CapitalPDangit.Misspelled + $body = '{"url":"https:\/\/twitter.com\/WordPress\/likes","title":"","html":"\u003Ca class=\"twitter-timeline\" data-width=\"500\" data-height=\"750\" data-dnt=\"true\" href=\"https:\/\/twitter.com\/WordPress\/likes?ref_src=twsrc%5Etfw\"\u003ETweets Liked by @WordPress\u003C\/a\u003E\n\u003Cscript async src=\"https:\/\/platform.twitter.com\/widgets.js\" charset=\"utf-8\"\u003E\u003C\/script\u003E\n","width":500,"height":null,"type":"rich","cache_age":"3153600000","provider_name":"Twitter","provider_url":"https:\/\/twitter.com","version":"1.0"}'; + } elseif ( false !== strpos( $url, 'twitter.com%2Fwordpress' ) ) { + $body = '{"url":"https:\/\/twitter.com\/WordPress","title":"","html":"\u003Ca class=\"twitter-timeline\" data-width=\"500\" data-height=\"750\" data-dnt=\"true\" href=\"https:\/\/twitter.com\/WordPress?ref_src=twsrc%5Etfw\"\u003ETweets by WordPress\u003C\/a\u003E\n\u003Cscript async src=\"https:\/\/platform.twitter.com\/widgets.js\" charset=\"utf-8\"\u003E\u003C\/script\u003E\n","width":500,"height":null,"type":"rich","cache_age":"3153600000","provider_name":"Twitter","provider_url":"https:\/\/twitter.com","version":"1.0"}'; } else { - $body = $this->oembed_response_2; + $body = ''; } - unset( $r ); - return [ 'body' => $body, 'headers' => [], @@ -95,33 +89,64 @@ public function mock_http_request( $preempt, $r, $url ) { */ public function get_conversion_data() { return [ - 'no_embed' => [ + 'no_embed' => [ '

Hello world.

', '

Hello world.

' . PHP_EOL, ], - 'url_simple' => [ - 'https://twitter.com/wordpress/status/987437752164737025' . PHP_EOL, - "
\n

Celebrate the WordPress 15th Anniversary on May 27 https://t.co/jv62WkI9lr pic.twitter.com/4ZECodSK78

\n

— WordPress (@WordPress) April 20, 2018

\n\n", + + 'embed_blockquote_without_twitter' => [ + '
lorem ipsum
', + '

lorem ipsum

' . PHP_EOL, ], - 'url_with_big_tweet_id' => [ + + 'url_simple' => [ + 'https://twitter.com/wordpress/status/987437752164737025', + '' . PHP_EOL . PHP_EOL, + ], + + 'url_with_big_tweet_id' => [ 'https://twitter.com/wordpress/status/705219971425574912' . PHP_EOL, - "
\n

On our way to the #GoogleDance! #SMX 💃🏻 pic.twitter.com/N8kZ9M3eN4

\n

— Search Engine Land (@sengineland) March 3, 2016

\n\n", + '' . PHP_EOL . PHP_EOL, ], - 'timeline_url_with_profile' => [ + + 'timeline_url_with_profile' => [ 'https://twitter.com/wordpress' . PHP_EOL, - "

\n", + '' . PHP_EOL, ], - 'timeline_url_with_likes' => [ + + 'timeline_url_with_likes' => [ 'https://twitter.com/wordpress/likes' . PHP_EOL, - "

\n", - ], - 'timeline_url_with_list' => [ - 'https://twitter.com/wordpress/lists/random_list' . PHP_EOL, - "

\n", + '' . PHP_EOL, ], - 'timeline_url_with_list2' => [ + + 'timeline_url_with_list' => [ 'https://twitter.com/robertnyman/lists/web-gdes' . PHP_EOL, - "

\n", + '' . PHP_EOL, + ], + + 'moment_url' => [ + 'https://twitter.com/i/moments/625792726546558977' . PHP_EOL, + '' . PHP_EOL, + ], + + 'blockquote_embed' => [ + wpautop( ' ' ), // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript, WordPress.Arrays.ArrayDeclarationSpacing.ArrayItemNoNewLine + '' . PHP_EOL . PHP_EOL, + ], + + 'blockquote_embed_with_data_conversation' => [ + wpautop( ' ' ), // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript, WordPress.Arrays.ArrayDeclarationSpacing.ArrayItemNoNewLine + '' . PHP_EOL . PHP_EOL, + ], + + 'blockquote_embed_with_data_theme' => [ + wpautop( ' ' ), // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript, WordPress.Arrays.ArrayDeclarationSpacing.ArrayItemNoNewLine + '' . PHP_EOL . PHP_EOL, + ], + + 'blockquote_embed_not_autop' => [ + ' ', // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript, WordPress.Arrays.ArrayDeclarationSpacing.ArrayItemNoNewLine + '' . PHP_EOL . PHP_EOL, ], ]; } @@ -135,7 +160,6 @@ public function get_conversion_data() { */ public function test__conversion( $source, $expected ) { $embed = new AMP_Twitter_Embed_Handler(); - $embed->register_embed(); $filtered_content = apply_filters( 'the_content', $source ); $dom = AMP_DOM_Utils::get_dom_from_content( $filtered_content ); @@ -169,7 +193,6 @@ public function get_scripts_data() { */ public function test__get_scripts( $source, $expected ) { $embed = new AMP_Twitter_Embed_Handler(); - $embed->register_embed(); $filtered_content = apply_filters( 'the_content', $source ); $dom = AMP_DOM_Utils::get_dom_from_content( $filtered_content ); @@ -185,61 +208,4 @@ public function test__get_scripts( $source, $expected ) { $this->assertEquals( $expected, $scripts ); } - - /** - * Data for test__raw_embed_sanitizer. - * - * @return array Data. - */ - public function get_raw_embed_dataset() { - return [ - 'no_embed' => [ - '

Hello world.

', - '

Hello world.

', - ], - 'embed_blockquote_without_twitter' => [ - '
lorem ipsum
', - '
lorem ipsum
', - ], - - 'blockquote_embed' => [ - wpautop( ' ' ), // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript, WordPress.Arrays.ArrayDeclarationSpacing.ArrayItemNoNewLine - '' . "\n\n", - ], - - 'blockquote_embed_with_data_conversation' => [ - wpautop( ' ' ), // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript, WordPress.Arrays.ArrayDeclarationSpacing.ArrayItemNoNewLine - '' . "\n\n", - ], - - 'blockquote_embed_with_data_theme' => [ - wpautop( ' ' ), // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript, WordPress.Arrays.ArrayDeclarationSpacing.ArrayItemNoNewLine - '' . "\n\n", - ], - - 'blockquote_embed_not_autop' => [ - ' ', // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript, WordPress.Arrays.ArrayDeclarationSpacing.ArrayItemNoNewLine - ' ', - ], - ]; - } - - /** - * Test raw_embed_sanitizer. - * - * @param string $source Content. - * @param string $expected Expected content. - * @dataProvider get_raw_embed_dataset - * @covers AMP_Twitter_Embed_Handler::sanitize_raw_embeds() - */ - public function test__raw_embed_sanitizer( $source, $expected ) { - $dom = AMP_DOM_Utils::get_dom_from_content( $source ); - $embed = new AMP_Twitter_Embed_Handler(); - - $embed->sanitize_raw_embeds( $dom ); - - $content = AMP_DOM_Utils::get_content_from_dom( $dom ); - - $this->assertEquals( $expected, $content ); - } } diff --git a/tests/php/test-amp-vimeo-embed-handler.php b/tests/php/test-amp-vimeo-embed-handler.php index 1da50eadc2c..291d4a3d088 100644 --- a/tests/php/test-amp-vimeo-embed-handler.php +++ b/tests/php/test-amp-vimeo-embed-handler.php @@ -30,17 +30,17 @@ public function get_conversion_data() { 'url_simple' => [ 'https://vimeo.com/172355597' . PHP_EOL, - '

' . PHP_EOL, + '' . PHP_EOL, ], 'url_unlisted' => [ 'https://vimeo.com/172355597/abcdef0123' . PHP_EOL, - '

' . PHP_EOL, + '' . PHP_EOL, ], 'url_player' => [ 'https://player.vimeo.com/video/172355597' . PHP_EOL, - '

' . PHP_EOL, + '' . PHP_EOL, ], ]; } @@ -55,10 +55,14 @@ public function get_conversion_data() { */ public function test__conversion( $source, $expected ) { $embed = new AMP_Vimeo_Embed_Handler(); - $embed->register_embed(); + $filtered_content = apply_filters( 'the_content', $source ); + $dom = AMP_DOM_Utils::get_dom_from_content( $filtered_content ); + $embed->sanitize_raw_embeds( $dom ); + + $content = AMP_DOM_Utils::get_content_from_dom( $dom ); - $this->assertEquals( $expected, $filtered_content ); + $this->assertEquals( $expected, $content ); } /** @@ -90,10 +94,12 @@ public function get_scripts_data() { */ public function test__get_scripts( $source, $expected ) { $embed = new AMP_Vimeo_Embed_Handler(); - $embed->register_embed(); - $source = apply_filters( 'the_content', $source ); - $validating_sanitizer = new AMP_Tag_And_Attribute_Sanitizer( AMP_DOM_Utils::get_dom_from_content( $source ) ); + $filtered_content = apply_filters( 'the_content', $source ); + $dom = AMP_DOM_Utils::get_dom_from_content( $filtered_content ); + $embed->sanitize_raw_embeds( $dom ); + + $validating_sanitizer = new AMP_Tag_And_Attribute_Sanitizer( $dom ); $validating_sanitizer->sanitize(); $scripts = array_merge( @@ -103,63 +109,4 @@ public function test__get_scripts( $source, $expected ) { $this->assertEquals( $expected, $scripts ); } - - /** - * Gets the test data for test_video_override(). - * - * @return array The test data. - */ - public function get_video_override_data() { - return [ - 'no_src_empty_html' => [ - '', - [ 'foo' => 'baz' ], - null, - ], - 'no_src_with_html' => [ - 'Initial HTML here', - [ 'foo' => 'baz' ], - null, - ], - 'non_vimeo_src' => [ - 'Initial HTML here', - [ 'src' => 'https://youtube.com/1234567' ], - null, - ], - 'non_numeric_video_id' => [ - 'Initial HTML here', - [ 'src' => 'https://vimeo.com/abcdefg' ], - '', - ], - 'valid_video_id' => [ - 'Initial HTML here', - [ 'src' => 'https://vimeo.com/1234567' ], - '', - ], - 'http_url' => [ - 'Initial HTML here', - [ 'src' => 'https://vimeo.com/1234567' ], - '', - ], - ]; - } - - /** - * Test video_override(). - * - * @dataProvider get_video_override_data - * @covers AMP_Vimeo_Embed_Handler::video_override() - * - * @param string $html The initial HTML. - * @param array $attr The attributes of the shortcode. - * @param string $expected The expected return value. - */ - public function test_video_override( $html, $attr, $expected ) { - if ( null === $expected ) { - $expected = $html; - } - - $embed = new AMP_Vimeo_Embed_Handler(); - $this->assertEquals( $expected, $embed->video_override( $html, $attr ) ); - } } diff --git a/tests/php/test-amp-vine-embed-handler.php b/tests/php/test-amp-vine-embed-handler.php index 0c2194c101a..a732f9ef3e9 100644 --- a/tests/php/test-amp-vine-embed-handler.php +++ b/tests/php/test-amp-vine-embed-handler.php @@ -14,7 +14,7 @@ public function get_conversion_data() { ], 'simple_url' => [ 'https://vine.co/v/MdKjXez002d' . PHP_EOL, - '

' . PHP_EOL, + '' . PHP_EOL, ], ]; } @@ -25,9 +25,14 @@ public function get_conversion_data() { public function test__conversion( $source, $expected ) { $embed = new AMP_Vine_Embed_Handler(); $embed->register_embed(); + $filtered_content = apply_filters( 'the_content', $source ); + $dom = AMP_DOM_Utils::get_dom_from_content( $filtered_content ); + $embed->sanitize_raw_embeds( $dom ); + + $content = AMP_DOM_Utils::get_content_from_dom( $dom ); - $this->assertEquals( $expected, $filtered_content ); + $this->assertEquals( $expected, $content ); } public function get_scripts_data() { @@ -49,9 +54,12 @@ public function get_scripts_data() { public function test__get_scripts( $source, $expected ) { $embed = new AMP_Vine_Embed_Handler(); $embed->register_embed(); - $source = apply_filters( 'the_content', $source ); - $validating_sanitizer = new AMP_Tag_And_Attribute_Sanitizer( AMP_DOM_Utils::get_dom_from_content( $source ) ); + $filtered_content = apply_filters( 'the_content', $source ); + $dom = AMP_DOM_Utils::get_dom_from_content( $filtered_content ); + $embed->sanitize_raw_embeds( $dom ); + + $validating_sanitizer = new AMP_Tag_And_Attribute_Sanitizer( $dom ); $validating_sanitizer->sanitize(); $scripts = array_merge( diff --git a/tests/php/test-class-amp-gfycat-embed-handler.php b/tests/php/test-class-amp-gfycat-embed-handler.php index bb0db5571ca..d0205f18d04 100644 --- a/tests/php/test-class-amp-gfycat-embed-handler.php +++ b/tests/php/test-class-amp-gfycat-embed-handler.php @@ -35,7 +35,7 @@ static function( $pre, $url ) { if ( false === strpos( $url, 'tautwhoppingcougar' ) ) { return $pre; } - return ''; + return ''; }, 10, 2 @@ -56,17 +56,17 @@ public function get_conversion_data() { 'url_simple' => [ 'https://gfycat.com/tautwhoppingcougar' . PHP_EOL, - '

' . PHP_EOL, + '' . PHP_EOL, ], 'url_with_detail' => [ 'https://gfycat.com/gifs/detail/tautwhoppingcougar' . PHP_EOL, - '

' . PHP_EOL, + '' . PHP_EOL, ], 'url_with_params' => [ 'https://gfycat.com/gifs/detail/tautwhoppingcougar?foo=bar' . PHP_EOL, - '

' . PHP_EOL, + '' . PHP_EOL, ], ]; @@ -81,10 +81,14 @@ public function get_conversion_data() { */ public function test__conversion( $source, $expected ) { $embed = new AMP_Gfycat_Embed_Handler(); - $embed->register_embed(); + $filtered_content = apply_filters( 'the_content', $source ); + $dom = AMP_DOM_Utils::get_dom_from_content( $filtered_content ); + $embed->sanitize_raw_embeds( $dom ); + + $content = AMP_DOM_Utils::get_content_from_dom( $dom ); - $this->assertEquals( $expected, $filtered_content ); + $this->assertEquals( $expected, $content ); } /** @@ -114,10 +118,12 @@ public function get_scripts_data() { */ public function test__get_scripts( $source, $expected ) { $embed = new AMP_Gfycat_Embed_Handler(); - $embed->register_embed(); - $source = apply_filters( 'the_content', $source ); - $validating_sanitizer = new AMP_Tag_And_Attribute_Sanitizer( AMP_DOM_Utils::get_dom_from_content( $source ) ); + $filtered_content = apply_filters( 'the_content', $source ); + $dom = AMP_DOM_Utils::get_dom_from_content( $filtered_content ); + $embed->sanitize_raw_embeds( $dom ); + + $validating_sanitizer = new AMP_Tag_And_Attribute_Sanitizer( $dom ); $validating_sanitizer->sanitize(); $scripts = array_merge( diff --git a/tests/php/test-class-amp-hulu-embed-handler.php b/tests/php/test-class-amp-hulu-embed-handler.php index 69bbaa730dd..1796a2b5111 100644 --- a/tests/php/test-class-amp-hulu-embed-handler.php +++ b/tests/php/test-class-amp-hulu-embed-handler.php @@ -66,12 +66,12 @@ public function get_conversion_data() { return [ 'url_simple' => [ 'https://www.hulu.com/watch/771496', - '

' . PHP_EOL, + '' . PHP_EOL, ], 'url_with_params' => [ 'https://www.hulu.com/watch/771496?foo=bar', - '

' . PHP_EOL, + '' . PHP_EOL, ], ]; @@ -86,14 +86,18 @@ public function get_conversion_data() { */ public function test__conversion( $url, $expected ) { $embed = new AMP_Hulu_Embed_Handler(); - $embed->register_embed(); + $filtered_content = apply_filters( 'the_content', $url ); + $dom = AMP_DOM_Utils::get_dom_from_content( $filtered_content ); + $embed->sanitize_raw_embeds( $dom ); if ( self::is_external_http_test_suite() && "

$url

" === trim( $filtered_content ) ) { $this->markTestSkipped( 'Endpoint is down.' ); } - $this->assertEquals( $expected, $filtered_content ); + $content = AMP_DOM_Utils::get_content_from_dom( $dom ); + + $this->assertEquals( $expected, $content ); } /** @@ -123,14 +127,16 @@ public function get_scripts_data() { */ public function test__get_scripts( $url, $expected ) { $embed = new AMP_Hulu_Embed_Handler(); - $embed->register_embed(); + $filtered_content = apply_filters( 'the_content', $url ); + $dom = AMP_DOM_Utils::get_dom_from_content( $filtered_content ); + $embed->sanitize_raw_embeds( $dom ); if ( self::is_external_http_test_suite() && "

$url

" === trim( $filtered_content ) ) { $this->markTestSkipped( 'Endpoint is down.' ); } - $validating_sanitizer = new AMP_Tag_And_Attribute_Sanitizer( AMP_DOM_Utils::get_dom_from_content( $filtered_content ) ); + $validating_sanitizer = new AMP_Tag_And_Attribute_Sanitizer( $dom ); $validating_sanitizer->sanitize(); $scripts = array_merge( diff --git a/tests/php/test-class-amp-imgur-embed-handler.php b/tests/php/test-class-amp-imgur-embed-handler.php index 7286c876976..dfc149ffd19 100644 --- a/tests/php/test-class-amp-imgur-embed-handler.php +++ b/tests/php/test-class-amp-imgur-embed-handler.php @@ -57,9 +57,6 @@ static function( $pre, $r, $url ) { * @return array */ public function get_conversion_data() { - $width = 500; - $height = 750; - return [ 'no_embed' => [ '

Hello world.

', @@ -68,17 +65,17 @@ public function get_conversion_data() { 'url_simple' => [ 'https://imgur.com/fmHGADZ' . PHP_EOL, - '

' . PHP_EOL, + '' . PHP_EOL . PHP_EOL, ], 'url_with_detail' => [ 'https://imgur.com/gallery/1ApvcWB' . PHP_EOL, - '

' . PHP_EOL, + '' . PHP_EOL . PHP_EOL, ], 'url_with_params' => [ 'https://imgur.com/gallery/1ApvcWB?foo=bar' . PHP_EOL, - '

' . PHP_EOL, + '' . PHP_EOL . PHP_EOL, ], ]; @@ -93,10 +90,14 @@ public function get_conversion_data() { */ public function test__conversion( $source, $expected ) { $embed = new AMP_Imgur_Embed_Handler(); - $embed->register_embed(); + $filtered_content = apply_filters( 'the_content', $source ); + $dom = AMP_DOM_Utils::get_dom_from_content( $filtered_content ); + $embed->sanitize_raw_embeds( $dom ); + + $content = AMP_DOM_Utils::get_content_from_dom( $dom ); - $this->assertEquals( $expected, $filtered_content ); + $this->assertEquals( $expected, $content ); } /** @@ -126,10 +127,12 @@ public function get_scripts_data() { */ public function test__get_scripts( $source, $expected ) { $embed = new AMP_Imgur_Embed_Handler(); - $embed->register_embed(); - $source = apply_filters( 'the_content', $source ); - $validating_sanitizer = new AMP_Tag_And_Attribute_Sanitizer( AMP_DOM_Utils::get_dom_from_content( $source ) ); + $filtered_content = apply_filters( 'the_content', $source ); + $dom = AMP_DOM_Utils::get_dom_from_content( $filtered_content ); + $embed->sanitize_raw_embeds( $dom ); + + $validating_sanitizer = new AMP_Tag_And_Attribute_Sanitizer( $dom ); $validating_sanitizer->sanitize(); $scripts = array_merge( diff --git a/tests/php/test-class-amp-tiktok-embed-handler.php b/tests/php/test-class-amp-tiktok-embed-handler.php index 1439edb1802..8e61fc0a74d 100644 --- a/tests/php/test-class-amp-tiktok-embed-handler.php +++ b/tests/php/test-class-amp-tiktok-embed-handler.php @@ -93,11 +93,10 @@ public function get_conversion_data() { */ public function test_conversion( $source, $expected ) { if ( version_compare( '5.4-alpha', get_bloginfo( 'version' ), '>' ) ) { - $this->markTestSkipped( 'The TikTok embed is only available in 5.4-alpha (until 5.4 is stable)' ); + $this->markTestSkipped( 'The TikTok embed is only available in 5.4-alpha and above.' ); } $embed = new AMP_TikTok_Embed_Handler(); - $embed->register_embed(); $filtered_content = apply_filters( 'the_content', $source ); $dom = AMP_DOM_Utils::get_dom_from_content( $filtered_content ); diff --git a/tests/php/test-class-amp-wordpress-tv-embed-handler.php b/tests/php/test-class-amp-wordpress-tv-embed-handler.php index 4089c50eca7..602bfb5dac1 100644 --- a/tests/php/test-class-amp-wordpress-tv-embed-handler.php +++ b/tests/php/test-class-amp-wordpress-tv-embed-handler.php @@ -47,9 +47,9 @@ public function mock_http_request( $preempt, $r, $url ) { if ( false === strpos( $url, 'wordpress.tv' ) ) { return $preempt; } - unset( $r ); + return [ - 'body' => '{"type":"video","version":"1.0","title":null,"width":500,"height":281,"html":"' . PHP_EOL, ], ]; } /** - * Test filter_oembed_html + * Test conversion. * - * @dataProvider get_filter_oembed_data - * @covers AMP_WordPress_TV_Embed_Handler::filter_oembed_html() + * @dataProvider get_conversion_data * - * @param mixed $cache The cached markup. - * @param string $url The URL of the embed. + * @param string $source Source. * @param string $expected The expected return value. */ - public function test_filter_oembed_html( $cache, $url, $expected ) { - if ( null === $expected ) { - $expected = $cache; - } + public function test_conversion( $source, $expected ) { + $embed = new AMP_WordPress_TV_Embed_Handler(); + + $filtered_content = apply_filters( 'the_content', $source ); + $dom = AMP_DOM_Utils::get_dom_from_content( $filtered_content ); + $embed->sanitize_raw_embeds( $dom ); - $handler = new AMP_WordPress_TV_Embed_Handler(); - $this->assertEquals( - $expected, - $handler->filter_oembed_html( $cache, $url ) - ); + $content = AMP_DOM_Utils::get_content_from_dom( $dom ); + $this->assertEquals( $expected, $content ); } } diff --git a/tests/php/test-class-amp-youtube-embed-handler.php b/tests/php/test-class-amp-youtube-embed-handler.php index 71ef3e825ec..c8560f12bb6 100644 --- a/tests/php/test-class-amp-youtube-embed-handler.php +++ b/tests/php/test-class-amp-youtube-embed-handler.php @@ -87,8 +87,6 @@ public function mock_http_request( $preempt, $r, $url ) { return $preempt; } - unset( $r ); - return [ 'body' => $this->youtube_oembed_response, 'headers' => [], @@ -101,47 +99,7 @@ public function mock_http_request( $preempt, $r, $url ) { ]; } - /** - * Test video_override(). - * - * @covers AMP_YouTube_Embed_Handler::video_override() - */ - public function test_video_override() { - remove_all_filters( 'wp_video_shortcode_override' ); - $this->handler->register_embed(); - $youtube_id = 'XOY3ZUO6P0k'; - $youtube_src = 'https://youtu.be/' . $youtube_id; - $attr_youtube = [ - 'src' => $youtube_src, - ]; - - $youtube_shortcode = $this->handler->video_override( '', $attr_youtube ); - $this->assertStringContains( 'assertStringContains( $youtube_id, $youtube_shortcode ); - - $vimeo_id = '64086087'; - $vimeo_src = 'https://vimeo.com/' . $vimeo_id; - $attr_vimeo = [ - 'src' => $vimeo_src, - ]; - $vimeo_shortcode = $this->handler->video_override( '', $attr_vimeo ); - $this->assertEquals( '', $vimeo_shortcode ); - - $daily_motion_id = 'x6bacgf'; - $daily_motion_src = 'http://www.dailymotion.com/video/' . $daily_motion_id; - $attr_daily_motion = [ - 'src' => $daily_motion_src, - ]; - $daily_motion_shortcode = $this->handler->video_override( '', $attr_daily_motion ); - $this->assertEquals( '', $daily_motion_shortcode ); - $no_attributes = $this->handler->video_override( '', [] ); - $this->assertEquals( '', $no_attributes ); - remove_all_filters( 'wp_video_shortcode_override' ); - } - public function get_conversion_data() { - $loading_attribute = version_compare( get_bloginfo( 'version' ), '5.5-alpha', '>' ) ? 'loading="lazy" ' : ''; - return [ 'no_embed' => [ '

Hello world.

', @@ -150,32 +108,32 @@ public function get_conversion_data() { 'url_simple' => [ 'https://www.youtube.com/watch?v=kfVsfOSbJY0' . PHP_EOL, - '

Rebecca Black - Friday

' . PHP_EOL, - '

' . PHP_EOL, + 'Rebecca Black - Friday' . PHP_EOL, + '' . PHP_EOL, ], 'url_short' => [ 'https://youtu.be/kfVsfOSbJY0' . PHP_EOL, - '

Rebecca Black - Friday

' . PHP_EOL, - '

' . PHP_EOL, + 'Rebecca Black - Friday' . PHP_EOL, + '' . PHP_EOL, ], 'url_with_querystring' => [ 'http://www.youtube.com/watch?v=kfVsfOSbJY0&hl=en&fs=1&w=425&h=349' . PHP_EOL, - '

Rebecca Black - Friday

' . PHP_EOL, - '

' . PHP_EOL, + 'Rebecca Black - Friday' . PHP_EOL, + '' . PHP_EOL, ], // Several reports of invalid URLs that have multiple `?` in the URL. 'url_with_querystring_and_extra_?' => [ 'http://www.youtube.com/watch?v=kfVsfOSbJY0?hl=en&fs=1&w=425&h=349' . PHP_EOL, - '

http://www.youtube.com/watch?v=kfVsfOSbJY0?hl=en&fs=1&w=425&h=349

' . PHP_EOL, + '

http://www.youtube.com/watch?v=kfVsfOSbJY0?hl=en&fs=1&w=425&h=349

' . PHP_EOL, ], 'embed_url' => [ 'https://www.youtube.com/embed/kfVsfOSbJY0' . PHP_EOL, - '

Rebecca Black - Friday

' . PHP_EOL, - '

' . PHP_EOL, + 'Rebecca Black - Friday' . PHP_EOL, + '' . PHP_EOL, ], ]; } @@ -184,16 +142,19 @@ public function get_conversion_data() { * @dataProvider get_conversion_data */ public function test__conversion( $source, $expected, $fallback_for_expected = null ) { - $this->handler->register_embed(); $filtered_content = apply_filters( 'the_content', $source ); + $dom = AMP_DOM_Utils::get_dom_from_content( $filtered_content ); + $this->handler->sanitize_raw_embeds( $dom ); + + $content = AMP_DOM_Utils::get_content_from_dom( $dom ); if ( version_compare( strtok( get_bloginfo( 'version' ), '-' ), '5.1', '<' ) && null !== $fallback_for_expected ) { - $this->assertEquals( $fallback_for_expected, $filtered_content ); + $this->assertEquals( $fallback_for_expected, $content ); } else { - $this->assertEquals( $expected, $filtered_content ); + $this->assertEquals( $expected, $content ); } } @@ -317,10 +278,11 @@ public function get_scripts_data() { * @dataProvider get_scripts_data */ public function test__get_scripts( $source, $expected ) { - $this->handler->register_embed(); - $source = apply_filters( 'the_content', $source ); + $filtered_content = apply_filters( 'the_content', $source ); + $dom = AMP_DOM_Utils::get_dom_from_content( $filtered_content ); + $this->handler->sanitize_raw_embeds( $dom ); - $validating_sanitizer = new AMP_Tag_And_Attribute_Sanitizer( AMP_DOM_Utils::get_dom_from_content( $source ) ); + $validating_sanitizer = new AMP_Tag_And_Attribute_Sanitizer( $dom ); $validating_sanitizer->sanitize(); $scripts = array_merge(