Skip to content

Commit

Permalink
Merge pull request #6665 from ampproject/fix/809-handle-wp-post-embeds
Browse files Browse the repository at this point in the history
Improve handling of WordPress post embeds
  • Loading branch information
westonruter authored Mar 3, 2022
2 parents 398c5a6 + 73b4305 commit 6035d35
Show file tree
Hide file tree
Showing 7 changed files with 595 additions and 12 deletions.
1 change: 1 addition & 0 deletions includes/amp-helper-functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -1407,6 +1407,7 @@ function amp_get_content_embed_handlers( $post = null ) {
AMP_Gfycat_Embed_Handler::class => [],
AMP_Imgur_Embed_Handler::class => [],
AMP_Scribd_Embed_Handler::class => [],
AMP_WordPress_Embed_Handler::class => [],
AMP_WordPress_TV_Embed_Handler::class => [],
],
$post
Expand Down
3 changes: 0 additions & 3 deletions includes/class-amp-theme-support.php
Original file line number Diff line number Diff line change
Expand Up @@ -845,9 +845,6 @@ public static function get_supportable_templates( $options = [] ) {
*/
public static function add_hooks() {

// This is not needed when post embeds are embedded via <amp-wordpress-embed>. See <https://github.com/ampproject/amp-wp/issues/809>.
remove_action( 'wp_head', 'wp_oembed_add_host_js' );

// Prevent emoji detection and emoji loading since platforms/browsers now support emoji natively (and Twemoji is not AMP-compatible).
add_filter( 'wp_resource_hints', [ __CLASS__, 'filter_resource_hints_to_remove_emoji_dns_prefetch' ], 10, 2 );
remove_action( 'wp_head', 'print_emoji_detection_script', 7 );
Expand Down
144 changes: 144 additions & 0 deletions includes/embeds/class-amp-wordpress-embed-handler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
<?php
/**
* Class AMP_WordPress_Embed_Handler
*
* @package AMP
*/

use AmpProject\Extension;
use AmpProject\Dom\Document;
use AmpProject\Dom\Element;
use AmpProject\Html\Attribute;
use AmpProject\Html\Tag;
use AmpProject\Layout;

/**
* Class AMP_WordPress_Embed_Handler
*
* @since 2.2.2
*/
class AMP_WordPress_Embed_Handler extends AMP_Base_Embed_Handler {

/**
* Default height.
*
* Note that 200px is the minimum that WordPress allows for a post embed. This minimum height is enforced by
* WordPress in the wp.receiveEmbedMessage() function, and the <amp-wordpress-embed> also enforces that same
* minimum height. It is important for the minimum height to be initially used because if the actual post embed
* window is _less_ than the initial, then no overflow button will be presented to resize the iframe to be
* _smaller_. So this ensures that the iframe will only ever overflow to grow in height.
*
* @var int
*/
protected $DEFAULT_HEIGHT = 200;

/**
* Tag.
*
* @var string AMP amp-wordpress-embed tag
*/
private $amp_tag = Extension::WORDPRESS_EMBED;

/**
* Register embed.
*/
public function register_embed() {
remove_action( 'wp_head', 'wp_oembed_add_host_js' );
}

/**
* Unregister embed.
*/
public function unregister_embed() {
add_action( 'wp_head', 'wp_oembed_add_host_js' );
}

/**
* Sanitize WordPress embed raw embeds.
*
* @param Document $dom Document.
*
* @return void
*/
public function sanitize_raw_embeds( Document $dom ) {

$embed_iframes = $dom->xpath->query( '//iframe[ @src and contains( concat( " ", normalize-space( @class ), " " ), " wp-embedded-content " ) ]', $dom->body );
foreach ( $embed_iframes as $embed_iframe ) {
/** @var Element $embed_iframe */

// Remove embed script included when user copies HTML Embed code, per get_post_embed_html().
$embed_script = $dom->xpath->query( './following-sibling::script[ contains( text(), "wp.receiveEmbedMessage" ) ]', $embed_iframe )->item( 0 );
if ( $embed_script instanceof Element ) {
$embed_script->parentNode->removeChild( $embed_script );
}

// If the post embed iframe got wrapped in a paragraph by `wpautop()`, unwrap it. This happens not with
// the Embed block but it does with the [embed] shortcode.
$is_wrapped_in_paragraph = (
$embed_iframe->parentNode instanceof Element
&&
Tag::P === $embed_iframe->parentNode->tagName
);

// If the iframe is wrapped in a paragraph, but it's not the only node, then abort.
if ( $is_wrapped_in_paragraph && 1 !== $embed_iframe->parentNode->childNodes->length ) {
continue;
}

$embed_blockquote = $dom->xpath->query(
'./preceding-sibling::blockquote[ contains( concat( " ", normalize-space( @class ), " " ), " wp-embedded-content " ) ]',
$is_wrapped_in_paragraph ? $embed_iframe->parentNode : $embed_iframe
)->item( 0 );
if ( $embed_blockquote instanceof Element ) {

// Note that unwrap_p_element() is not being used here because it will do nothing if the paragraph
// happens to have an attribute on it, which is possible with the_content filters.
if ( $is_wrapped_in_paragraph && $embed_iframe->parentNode->parentNode instanceof Element ) {
$embed_iframe->parentNode->parentNode->replaceChild( $embed_iframe, $embed_iframe->parentNode );
}

$this->create_amp_wordpress_embed_and_replace_node( $dom, $embed_blockquote, $embed_iframe );
}
}
}

/**
* Make final modifications to DOMNode
*
* @param Document $dom The HTML Document.
* @param Element $blockquote The blockquote to be moved inside <amp-wordpress-embed>.
* @param Element $iframe The iframe to be replaced with <amp-wordpress-embed>.
*/
private function create_amp_wordpress_embed_and_replace_node( Document $dom, Element $blockquote, Element $iframe ) {

$attributes = [
Attribute::HEIGHT => $this->args['height'],
Attribute::LAYOUT => Layout::FIXED_HEIGHT,
];
if ( $iframe->hasAttribute( Attribute::TITLE ) ) {
$attributes[ Attribute::TITLE ] = $iframe->getAttribute( Attribute::TITLE );
}

$src = $iframe->getAttribute( Attribute::SRC );

// Remove the secret which will be handled by amp-wordpress-embed.
$src = preg_replace( '/#\?secret=.+/', '', $src );
$blockquote->removeAttribute( 'data-secret' );

$attributes[ Attribute::DATA_URL ] = $src;

$amp_wordpress_embed_node = AMP_DOM_Utils::create_node(
$dom,
$this->amp_tag,
$attributes
);

$blockquote->setAttributeNode( $dom->createAttribute( Attribute::PLACEHOLDER ) );
$amp_wordpress_embed_node->appendChild( $blockquote );
$amp_wordpress_embed_node->appendChild( $this->create_overflow_button_element( $dom ) );

$iframe->parentNode->replaceChild( $amp_wordpress_embed_node, $iframe );

$this->did_convert_elements = true;
}
}
Loading

0 comments on commit 6035d35

Please sign in to comment.