Embeds: Conditionally enqueue wp-embed only if needed and send ready message in case script loads after post embed windows.

* Prevent loading `wp-embed` script unconditionally on every page in favor of conditionally enqueueing when a post embed is detected. The `wp-embed` script is also explicitly marked as being in the footer group. Sites which currently disable post embed scripts from being enqueued via `remove_action( 'wp_head', 'wp_oembed_add_host_js' )` will continue to do so.
* Send a `ready` message from the host page to each post embed window in case the `iframe` loads before the `wp-embed` script does. When the `ready` message is received by the post embed window, it sends the same `height` message as it sends when it loads.
* Eliminate use of `grunt-include` to inject emoji script and the post embed script. Instead obtain the script contents via `file_get_contents()` (as is done elsewhere in core) and utilize `wp_print_inline_script_tag()`/`wp_get_inline_script_tag()` to construct out the script. This simplifies the logic and allows the running of src without `SCRIPT_DEBUG` enabled.
* For the embed code that users are provided to copy for embedding outside of WP, add the `secret` on the `blockquote` and `iframe`. This ensures the `blockquote` will be hidden when the `iframe` loads. The embed code in question is accessed here via `get_post_embed_html()`.

Props westonruter, swissspidy, pento, flixos90, ocean90.
Fixes #44632, #44306.


git-svn-id: https://develop.svn.wordpress.org/trunk@52132 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
Weston Ruter
2021-11-11 02:47:10 +00:00
parent 1e785fa0c3
commit 02a2f9c9f5
10 changed files with 160 additions and 86 deletions
+40 -7
View File
@@ -18,6 +18,13 @@
}, '*' );
}
/**
* Send the height message to the parent window.
*/
function sendHeightMessage() {
sendEmbedMessage( 'height', Math.ceil( document.body.getBoundingClientRect().height ) );
}
function onLoad() {
if ( loaded ) {
return;
@@ -138,13 +145,11 @@
}
// Send this document's height to the parent (embedding) site.
sendEmbedMessage( 'height', Math.ceil( document.body.getBoundingClientRect().height ) );
sendHeightMessage();
// Send the document's height again after the featured image has been loaded.
if ( featured_image ) {
featured_image.addEventListener( 'load', function() {
sendEmbedMessage( 'height', Math.ceil( document.body.getBoundingClientRect().height ) );
} );
featured_image.addEventListener( 'load', sendHeightMessage );
}
/**
@@ -184,9 +189,36 @@
clearTimeout( resizing );
resizing = setTimeout( function () {
sendEmbedMessage( 'height', Math.ceil( document.body.getBoundingClientRect().height ) );
}, 100 );
resizing = setTimeout( sendHeightMessage, 100 );
}
/**
* Message handler.
*
* @param {MessageEvent} event
*/
function onMessage( event ) {
var data = event.data;
if ( ! data ) {
return;
}
if ( event.source !== window.parent ) {
return;
}
if ( ! ( data.secret || data.message ) ) {
return;
}
if ( data.secret !== secret ) {
return;
}
if ( 'ready' === data.message ) {
sendHeightMessage();
}
}
/**
@@ -212,5 +244,6 @@
document.addEventListener( 'DOMContentLoaded', onLoad, false );
window.addEventListener( 'load', onLoad, false );
window.addEventListener( 'resize', onResize, false );
window.addEventListener( 'message', onMessage, false );
}
})( window, document );
+18 -1
View File
@@ -27,6 +27,11 @@
return;
}
/**
* Receive embed message.
*
* @param {MessageEvent} e
*/
window.wp.receiveEmbedMessage = function( e ) {
var data = e.data;
@@ -102,9 +107,11 @@
iframeClone, i, source, secret;
for ( i = 0; i < iframes.length; i++ ) {
/** @var {IframeElement} */
source = iframes[ i ];
if ( ! source.getAttribute( 'data-secret' ) ) {
secret = source.getAttribute( 'data-secret' );
if ( ! secret ) {
/* Add secret to iframe */
secret = Math.random().toString( 36 ).substr( 2, 10 );
source.src += '#?secret=' + secret;
@@ -117,6 +124,16 @@
iframeClone.removeAttribute( 'security' );
source.parentNode.replaceChild( iframeClone, source );
}
/*
* Let post embed window know that the parent is ready for receiving the height message, in case the iframe
* loaded before wp-embed.js was loaded. When the ready message is received by the post embed window, the
* window will then (re-)send the height message right away.
*/
source.contentWindow.postMessage( {
message: 'ready',
secret: secret
}, '*' );
}
}
+34 -25
View File
@@ -359,7 +359,25 @@ function wp_oembed_add_discovery_links() {
* @since 4.4.0
*/
function wp_oembed_add_host_js() {
wp_enqueue_script( 'wp-embed' );
add_filter( 'embed_oembed_html', 'wp_maybe_enqueue_oembed_host_js' );
}
/**
* Enqueue the wp-embed script if the provided oEmbed HTML contains a post embed.
*
* In order to only enqueue the wp-embed script on pages that actually contain post embeds, this function checks if the
* provided HTML contains post embed markup and if so enqueues the script so that it will get printed in the footer.
*
* @since 5.9.0
*
* @param string $html Embed markup.
* @return string Embed markup (without modifications).
*/
function wp_maybe_enqueue_oembed_host_js( $html ) {
if ( preg_match( '/<blockquote\s[^>]*wp-embedded-content/', $html ) ) {
wp_enqueue_script( 'wp-embed' );
}
return $html;
}
/**
@@ -450,32 +468,22 @@ function get_post_embed_html( $width, $height, $post = null ) {
$embed_url = get_post_embed_url( $post );
$output = '<blockquote class="wp-embedded-content"><a href="' . esc_url( get_permalink( $post ) ) . '">' . get_the_title( $post ) . "</a></blockquote>\n";
$secret = wp_generate_password( 10, false );
$embed_url .= "#?secret={$secret}";
$output .= "<script type='text/javascript'>\n";
$output .= "<!--//--><![CDATA[//><!--\n";
if ( SCRIPT_DEBUG ) {
$output .= file_get_contents( ABSPATH . WPINC . '/js/wp-embed.js' );
} else {
/*
* If you're looking at a src version of this file, you'll see an "include"
* statement below. This is used by the `npm run build` process to directly
* include a minified version of wp-embed.js, instead of using the
* file_get_contents() method from above.
*
* If you're looking at a build version of this file, you'll see a string of
* minified JavaScript. If you need to debug it, please turn on SCRIPT_DEBUG
* and edit wp-embed.js directly.
*/
$output .= <<<JS
include "js/wp-embed.min.js"
JS;
}
$output .= "\n//--><!]]>";
$output .= "\n</script>";
$output = wp_get_inline_script_tag(
file_get_contents( sprintf( ABSPATH . WPINC . '/js/wp-embed' . wp_scripts_get_suffix() . '.js' ) )
);
$output .= sprintf(
'<iframe sandbox="allow-scripts" security="restricted" src="%1$s" width="%2$d" height="%3$d" title="%4$s" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" class="wp-embedded-content"></iframe>',
'<blockquote class="wp-embedded-content" data-secret="%1$s"><a href="%2$s">%3$s</a></blockquote>',
esc_attr( $secret ),
esc_url( get_permalink( $post ) ),
get_the_title( $post )
);
$output .= sprintf(
'<iframe sandbox="allow-scripts" security="restricted" src="%1$s" width="%2$d" height="%3$d" title="%4$s" data-secret="%5$s" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" class="wp-embedded-content"></iframe>',
esc_url( $embed_url ),
absint( $width ),
absint( $height ),
@@ -486,7 +494,8 @@ JS;
get_the_title( $post ),
get_bloginfo( 'name' )
)
)
),
esc_attr( $secret )
);
/**
+6 -26
View File
@@ -5756,8 +5756,7 @@ function _print_emoji_detection_script() {
'svgExt' => apply_filters( 'emoji_svg_ext', '.svg' ),
);
$version = 'ver=' . get_bloginfo( 'version' );
$type_attr = current_theme_supports( 'html5', 'style' ) ? '' : ' type="text/javascript"';
$version = 'ver=' . get_bloginfo( 'version' );
if ( SCRIPT_DEBUG ) {
$settings['source'] = array(
@@ -5766,36 +5765,17 @@ function _print_emoji_detection_script() {
/** This filter is documented in wp-includes/class.wp-scripts.php */
'twemoji' => apply_filters( 'script_loader_src', includes_url( "js/twemoji.js?$version" ), 'twemoji' ),
);
?>
<script<?php echo $type_attr; ?>>
window._wpemojiSettings = <?php echo wp_json_encode( $settings ); ?>;
<?php readfile( ABSPATH . WPINC . '/js/wp-emoji-loader.js' ); ?>
</script>
<?php
} else {
$settings['source'] = array(
/** This filter is documented in wp-includes/class.wp-scripts.php */
'concatemoji' => apply_filters( 'script_loader_src', includes_url( "js/wp-emoji-release.min.js?$version" ), 'concatemoji' ),
);
/*
* If you're looking at a src version of this file, you'll see an "include"
* statement below. This is used by the `npm run build` process to directly
* include a minified version of wp-emoji-loader.js, instead of using the
* readfile() method from above.
*
* If you're looking at a build version of this file, you'll see a string of
* minified JavaScript. If you need to debug it, please turn on SCRIPT_DEBUG
* and edit wp-emoji-loader.js directly.
*/
?>
<script<?php echo $type_attr; ?>>
window._wpemojiSettings = <?php echo wp_json_encode( $settings ); ?>;
include "js/wp-emoji-loader.min.js"
</script>
<?php
}
wp_print_inline_script_tag(
sprintf( 'window._wpemojiSettings = %s;', wp_json_encode( $settings ) ) .
file_get_contents( sprintf( ABSPATH . WPINC . '/js/wp-emoji-loader' . wp_scripts_get_suffix() . '.js' ) )
);
}
/**
+1 -1
View File
@@ -1247,7 +1247,7 @@ function wp_default_scripts( $scripts ) {
)
);
$scripts->add( 'wp-embed', "/wp-includes/js/wp-embed$suffix.js" );
$scripts->add( 'wp-embed', "/wp-includes/js/wp-embed$suffix.js", array(), false, 1 );
// To enqueue media-views or media-editor, call wp_enqueue_media().
// Both rely on numerous settings, styles, and templates to operate correctly.