diff --git a/includes/embeds/class-amp-tiktok-embed-handler.php b/includes/embeds/class-amp-tiktok-embed-handler.php index 9cfbb3fb463..f399483ab51 100644 --- a/includes/embeds/class-amp-tiktok-embed-handler.php +++ b/includes/embeds/class-amp-tiktok-embed-handler.php @@ -5,7 +5,12 @@ * @package AMP */ +use AmpProject\Attribute; use AmpProject\Dom\Document; +use AmpProject\Dom\Element; +use AmpProject\Extension; +use AmpProject\Layout; +use AmpProject\Tag; /** * Class AMP_TikTok_Embed_Handler @@ -34,95 +39,69 @@ public function unregister_embed() { * @param Document $dom DOM. */ public function sanitize_raw_embeds( Document $dom ) { - $nodes = $dom->xpath->query( '//blockquote[ contains( @class, "tiktok-embed" ) ]' ); + $nodes = $dom->xpath->query( + sprintf( '//blockquote[ @cite and @data-video-id and contains( @class, "tiktok-embed" ) and not( parent::%s ) ]', Extension::TIKTOK ) + ); foreach ( $nodes as $node ) { - if ( ! $this->is_raw_embed( $node ) ) { - continue; - } - $this->make_embed_amp_compatible( $node ); } } - /** - * Determine if the node has already been sanitized. - * - * @param DOMElement $node The DOMNode. - * @return bool Whether the node is a raw embed. - */ - protected function is_raw_embed( DOMElement $node ) { - return ! $node->firstChild || ( $node->firstChild && 'amp-embedly-card' !== $node->firstChild->nodeName ); - } - /** * Make TikTok embed AMP compatible. * - * @param DOMElement $blockquote_node The
node to make AMP compatible. + * @param Element $blockquote The
node to make AMP compatible. */ - protected function make_embed_amp_compatible( DOMElement $blockquote_node ) { - $dom = $blockquote_node->ownerDocument; - $video_url = $blockquote_node->getAttribute( 'cite' ); + protected function make_embed_amp_compatible( Element $blockquote ) { + $dom = $blockquote->ownerDocument; + $video_url = $blockquote->getAttribute( Attribute::CITE ); - // If there is no video ID, stop here as its needed for the `data-url` parameter. + // If there is no video ID, stop here as its needed for the `data-src` parameter. if ( empty( $video_url ) ) { return; } - $this->remove_embed_script( $blockquote_node ); + $this->remove_embed_script( $blockquote ); - $amp_node = AMP_DOM_Utils::create_node( + $amp_tiktok = AMP_DOM_Utils::create_node( Document::fromNode( $dom ), - 'amp-embedly-card', + Extension::TIKTOK, [ - 'layout' => 'responsive', - 'height' => 700, - 'width' => 340, - 'data-card-controls' => 0, - 'data-url' => $video_url, + Attribute::LAYOUT => Layout::RESPONSIVE, + Attribute::HEIGHT => 575, + Attribute::WIDTH => 325, + Attribute::DATA_SRC => $video_url, ] ); - // Find existing
node to use as the placeholder. - foreach ( iterator_to_array( $blockquote_node->childNodes ) as $child ) { - if ( ! ( $child instanceof DOMElement ) ) { - continue; - } - - // Append the placeholder if it was found. - if ( 'section' === $child->nodeName ) { - /** - * Placeholder to append to the AMP component. - * - * @var DOMElement $placeholder_node - */ - $placeholder_node = $blockquote_node->removeChild( $child ); - $placeholder_node->setAttribute( 'placeholder', '' ); - $amp_node->appendChild( $placeholder_node ); - break; - } - } - - $blockquote_node->parentNode->replaceChild( $amp_node, $blockquote_node ); + $blockquote->parentNode->replaceChild( $amp_tiktok, $blockquote ); + $amp_tiktok->appendChild( $blockquote ); + $blockquote->setAttributeNode( $dom->createAttribute( Attribute::PLACEHOLDER ) ); + $blockquote->removeAttribute( Attribute::STYLE ); } /** * Remove the TikTok embed script if it exists. * - * @param DOMElement $node The DOMNode to make AMP compatible. + * @param Element $blockquote The blockquote element being made AMP-compatible. */ - protected function remove_embed_script( DOMElement $node ) { - $next_element_sibling = $node->nextSibling; - while ( $next_element_sibling && ! ( $next_element_sibling instanceof DOMElement ) ) { + protected function remove_embed_script( Element $blockquote ) { + $next_element_sibling = $blockquote->nextSibling; + while ( $next_element_sibling && ! ( $next_element_sibling instanceof Element ) ) { $next_element_sibling = $next_element_sibling->nextSibling; } $script_src = 'tiktok.com/embed.js'; // Handle case where script is wrapped in paragraph by wpautop. - if ( $next_element_sibling instanceof DOMElement && 'p' === $next_element_sibling->nodeName ) { - $children = $next_element_sibling->getElementsByTagName( '*' ); - if ( 1 === $children->length && 'script' === $children->item( 0 )->nodeName && false !== strpos( $children->item( 0 )->getAttribute( 'src' ), $script_src ) ) { + if ( $next_element_sibling instanceof Element && Tag::P === $next_element_sibling->nodeName ) { + $script = $next_element_sibling->getElementsByTagName( Tag::SCRIPT )->item( 0 ); + if ( + $script instanceof Element + && + false !== strpos( $script->getAttribute( Attribute::SRC ), $script_src ) + ) { $next_element_sibling->parentNode->removeChild( $next_element_sibling ); return; } @@ -130,11 +109,11 @@ protected function remove_embed_script( DOMElement $node ) { // Handle case where script is immediately following. $is_embed_script = ( - $next_element_sibling instanceof DOMElement + $next_element_sibling instanceof Element && - 'script' === strtolower( $next_element_sibling->nodeName ) + Tag::SCRIPT === strtolower( $next_element_sibling->nodeName ) && - false !== strpos( $next_element_sibling->getAttribute( 'src' ), $script_src ) + false !== strpos( $next_element_sibling->getAttribute( Attribute::SRC ), $script_src ) ); if ( $is_embed_script ) { $next_element_sibling->parentNode->removeChild( $next_element_sibling ); diff --git a/tests/php/test-class-amp-tiktok-embed-handler.php b/tests/php/test-class-amp-tiktok-embed-handler.php index f052a76855b..c7fdd8689db 100644 --- a/tests/php/test-class-amp-tiktok-embed-handler.php +++ b/tests/php/test-class-amp-tiktok-embed-handler.php @@ -5,6 +5,7 @@ * @package AMP. */ +use AmpProject\AmpWP\Tests\Helpers\MarkupComparison; use AmpProject\AmpWP\Tests\Helpers\WithoutBlockPreRendering; use AmpProject\AmpWP\Tests\TestCase; @@ -13,6 +14,8 @@ */ class Test_AMP_TikTok_Embed_Handler extends TestCase { + use MarkupComparison; + use WithoutBlockPreRendering { setUp as public prevent_block_pre_render; } @@ -70,17 +73,77 @@ public function mock_http_request( $pre, $r, $url ) { */ public function get_conversion_data() { return [ - 'no_embed' => [ + 'no_embed' => [ '

Hello world.

', '

Hello world.

' . PHP_EOL, ], - 'url_simple' => [ + 'url_simple' => [ 'https://www.tiktok.com/@scout2015/video/6718335390845095173' . PHP_EOL, - '
@scout2015 ' . PHP_EOL . - '

Scramble up ur name & I’ll try to guess it😍❤️ #foryoupage #petsoftiktok #aesthetic

' . PHP_EOL . - '

♬ original sound – tiff

' . PHP_EOL . PHP_EOL, + ' + +
+
@scout2015 +

Scramble up ur name & I’ll try to guess it😍❤️ #foryoupage #petsoftiktok #aesthetic

+

♬ original sound – tiff

+
+
+ ', + ], + + 'tiktok-embed-code-with-wpautop' => [ + ' +
@countingprimes

You can now embed TikTok\'s in AMP

♬ original sound - countingprimes
+ ', + ' + +
+
+ @countingprimes +

You can now embed TikTok’s in AMP

+

♬ original sound – countingprimes

+
+
+
+ ', + ], + + 'tiktok-embed-code-without-wpautop' => [ + ' + +
@countingprimes

You can now embed TikTok\'s in AMP

♬ original sound - countingprimes
+ + ', + ' + +
+
+ @countingprimes +

You can now embed TikTok’s in AMP

+ ♬ original sound – countingprimes +
+
+
+ ', + ], + + 'amp-tiktok-passthrough' => [ + ' + + +
+
+ @countingprimes +

You can now embed TikTok’s in AMP

+ ♬ original sound — countingprimes +
+
+
+ + ', + + null, ], ]; } @@ -92,10 +155,15 @@ public function get_conversion_data() { * @param string $expected Expected. * @dataProvider get_conversion_data */ - public function test_conversion( $source, $expected ) { + public function test_conversion( $source, $expected = null ) { 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 oEmbed provider is only available in 5.4-alpha and later' ); } + if ( ! $expected ) { + $expected = $source; + } + + $expected = preg_replace( '//s', '', $expected ); $embed = new AMP_TikTok_Embed_Handler(); $embed->register_embed(); @@ -104,8 +172,8 @@ public function test_conversion( $source, $expected ) { $dom = AMP_DOM_Utils::get_dom_from_content( $filtered_content ); $embed->sanitize_raw_embeds( $dom ); - $content = AMP_DOM_Utils::get_content_from_dom( $dom ); + $actual = AMP_DOM_Utils::get_content_from_dom( $dom ); - $this->assertEquals( $expected, $content ); + $this->assertSimilarMarkup( $expected, $actual ); } }