Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Leverage URL metrics to reserve space for embeds to reduce CLS #1373

Open
wants to merge 56 commits into
base: trunk
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
0a376c1
Introduce methods to get minumum height of element
westonruter Jul 17, 2024
8aa7e63
Set the min-height of an embed prior to it loading
westonruter Jul 29, 2024
11f98f4
Set min-height on embed-wrapper instead of figure container
westonruter Jul 30, 2024
d7cc7cf
Use 500px as a better representation of an element that could be LCP
westonruter Jul 30, 2024
48e57e8
Add test for existing style manipulation
westonruter Jul 30, 2024
0d285f2
Add helper generator method to get all elements
westonruter Jul 31, 2024
4778a3d
Try using MutationObserve to watch for embed height changes
westonruter Aug 14, 2024
1dbd4a1
Use the more appropriate ResizeObserver instead of MutationObserver
westonruter Aug 14, 2024
a4bab7e
Remove condition that breaks monitoring resizes of post embeds
westonruter Aug 14, 2024
5f0cdbe
Introduce client-side Optimization Detective extensions and move Embe…
westonruter Aug 17, 2024
0ba2d6e
Override clientBoundingRect once embed has loaded
westonruter Aug 17, 2024
5f4189d
Move jsdoc types to types.d.ts for reuse
westonruter Aug 18, 2024
bf2b3c5
Send URL metric when leaving the page
westonruter Aug 18, 2024
b9bad0d
Use boundingClientRect instead of intersectionRect in get_all_element…
westonruter Aug 18, 2024
c6b02ec
Eliminate timeout for disconneccting ResizeObsever
westonruter Aug 18, 2024
52a2260
Move extension initialization after idle callback
westonruter Aug 18, 2024
edc52fa
Fix warning when prematurely applying buffered text replacements, esp…
westonruter Aug 18, 2024
820d66d
Prepend min-height to style attribute instead of appending
westonruter Aug 19, 2024
def2aab
Use object spread
westonruter Aug 22, 2024
cd9a618
Merge branch 'trunk' of https://github.com/WordPress/performance into…
westonruter Aug 22, 2024
02c4fd9
Merge branch 'trunk' into add/embed-optimizer-min-height-reservation
westonruter Sep 13, 2024
1da219f
Use get_json_params() instead of get_params() so _wpnonce query param…
westonruter Sep 17, 2024
e34d9fe
Implement resizedBoundingClientRect extended property in schema
westonruter Sep 17, 2024
5db6f54
Fix testing JSON request
westonruter Sep 18, 2024
0fa263a
Go back to get_params() by ignoring _wpnonce
westonruter Sep 18, 2024
72b285d
Merge branch 'trunk' into add/embed-optimizer-min-height-reservation
westonruter Sep 19, 2024
2a723f7
Fix jsdoc
westonruter Sep 29, 2024
71dd914
Merge branch 'trunk' of https://github.com/WordPress/performance into…
westonruter Oct 3, 2024
29d4383
Eliminate use of deprecated property
westonruter Oct 4, 2024
a529218
Add breakpoint-specific min-heights to account for responsive embeds
westonruter Oct 4, 2024
fa8a34e
Add od_generate_media_query() helper
westonruter Oct 4, 2024
1e40f84
Break up embed tag visitor into separate methods
westonruter Oct 4, 2024
5d4d5b2
Bump alpha versions
westonruter Oct 8, 2024
5f1c2ac
Add missing short-circuit in case EMBED_OPTIMIZER_VERSION is defined
westonruter Oct 8, 2024
915e1e7
Rework bootstrap logic to wait until init priority 9 and add od_init …
westonruter Oct 8, 2024
26ae396
Add test for when resizedBoundingClientRect data not available
westonruter Oct 8, 2024
cd80ed1
Remove obsolete short-circuiting now that OD dependency version is ch…
westonruter Oct 8, 2024
bd008c5
Evolve get_all_url_metrics_groups_elements into get_all_denormalized_…
westonruter Oct 8, 2024
1b5cf13
Add Embed Optimizer tests
westonruter Oct 8, 2024
a70df28
Account for error when passing single-item array to min() or max()
westonruter Oct 8, 2024
4e48d3d
Add test for Image Prioritizer
westonruter Oct 8, 2024
d17cace
Remove now-unused method to get element minimum hights
westonruter Oct 8, 2024
5574081
Improve handling of get_updated_html
westonruter Oct 8, 2024
19c0425
Add test for get_all_denormalized_elements
westonruter Oct 9, 2024
ea36bac
Add tests for new OD code
westonruter Oct 9, 2024
01c083d
Clarify purpose of overridden get_updated_html method
westonruter Oct 9, 2024
c5d6991
Add missing since tags
westonruter Oct 9, 2024
455ef4f
Clarify handling of embed block tags and embed wrapper tags
westonruter Oct 9, 2024
a390e15
Replace tuple with assoc array
westonruter Oct 9, 2024
a760705
Add doc block for detect.js
westonruter Oct 9, 2024
7ca1fbc
Add API functions to pass to finalize callbacks to avoid direct mutat…
westonruter Oct 11, 2024
f66445f
Improve error handling
westonruter Oct 11, 2024
6e0aa8e
Harden types and disallow setting core properties
westonruter Oct 11, 2024
9e99e0d
Reuse sets for reserved property keys
westonruter Oct 11, 2024
46ba7e3
Move functions to root of module
westonruter Oct 11, 2024
0bc521e
Fix TypeScript error related to embedWrapper
westonruter Oct 11, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 64 additions & 8 deletions plugins/embed-optimizer/class-embed-optimizer-tag-visitor.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,26 +26,76 @@ final class Embed_Optimizer_Tag_Visitor {
*/
protected $added_lazy_script = false;

/**
* Determines whether the processor is currently at a figure.wp-block-embed tag.
*
* @since n.e.x.t
*
* @param OD_HTML_Tag_Processor $processor Processor.
* @return bool Whether at the tag.
*/
private function is_embed_figure( OD_HTML_Tag_Processor $processor ): bool {
return (
'FIGURE' === $processor->get_tag()
&&
true === $processor->has_class( 'wp-block-embed' )
);
}

/**
* Determines whether the processor is currently at a div.wp-block-embed__wrapper tag.
*
* @since n.e.x.t
*
* @param OD_HTML_Tag_Processor $processor Processor.
* @return bool Whether the tag should be measured and stored in URL metrics
*/
private function is_embed_wrapper( OD_HTML_Tag_Processor $processor ): bool {
return (
'DIV' === $processor->get_tag()
&&
true === $processor->has_class( 'wp-block-embed__wrapper' )
);
}

/**
* Visits a tag.
*
* @since 0.2.0
*
* @param OD_Tag_Visitor_Context $context Tag visitor context.
* @return bool Whether the visit or visited the tag.
* @return bool Whether the tag should be measured and stored in URL metrics.
*/
public function __invoke( OD_Tag_Visitor_Context $context ): bool {
$processor = $context->processor;
if ( ! (
'FIGURE' === $processor->get_tag()
&&
true === $processor->has_class( 'wp-block-embed' )
) ) {

/*
* The only thing we need to do if it is a div.wp-block-embed__wrapper tag is return true so that the tag
* will get measured and stored in the URL Metrics.
*/
if ( $this->is_embed_wrapper( $processor ) ) {
return true;
}

// Short-circuit if not a figure.wp-block-embed tag.
if ( ! $this->is_embed_figure( $processor ) ) {
return false;
}

$max_intersection_ratio = $context->url_metrics_group_collection->get_element_max_intersection_ratio( $processor->get_xpath() );
$embed_wrapper_xpath = $processor->get_xpath() . '/*[1][self::DIV]';
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not ideal to be constructing this XPath manually.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've opened #1407 to explore this, but it's not necessary for this PR to move forward.

$minimum_height = $context->url_metrics_group_collection->get_element_minimum_height( $embed_wrapper_xpath );
if ( is_float( $minimum_height ) ) {
$min_height_style = sprintf( 'min-height: %dpx;', $minimum_height );
$style = $processor->get_attribute( 'style' );
if ( is_string( $style ) ) {
$style = $min_height_style . ' ' . $style;
} else {
$style = $min_height_style;
}
$processor->set_attribute( 'style', $style );
}

$max_intersection_ratio = $context->url_metrics_group_collection->get_element_max_intersection_ratio( $embed_wrapper_xpath );
if ( $max_intersection_ratio > 0 ) {
/*
* The following embeds have been chosen for optimization due to their relative popularity among all embed types.
Expand Down Expand Up @@ -119,6 +169,12 @@ public function __invoke( OD_Tag_Visitor_Context $context ): bool {
$this->added_lazy_script = true;
}

return true;
/*
* At this point the tag is a figure.wp-block-embed, and we can return false because this does not need to be
* measured and stored in URL Metrics. Only the child div.wp-block-embed__wrapper tag is measured and stored
* so that this visitor can look up the height to set as a min-height on the figure.wp-block-embed. For more
* information on what the return values mean for tag visitors, see <https://github.com/WordPress/performance/issues/1342>.
*/
return false;
}
}
91 changes: 91 additions & 0 deletions plugins/embed-optimizer/detect.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
const consoleLogPrefix = '[Embed Optimizer]';
felixarntz marked this conversation as resolved.
Show resolved Hide resolved

/**
* @typedef {import("../optimization-detective/types.d.ts").ElementMetrics} ElementMetrics
* @typedef {import("../optimization-detective/types.d.ts").URLMetric} URLMetric
*/

/**
* Log a message.
*
* @param {...*} message
*/
function log( ...message ) {
// eslint-disable-next-line no-console
console.log( consoleLogPrefix, ...message );
}

/**
* Embed element heights.
*
* @type {Map<string, DOMRectReadOnly>}
*/
const loadedElementContentRects = new Map();

/**
* Initialize.
*
* @param {Object} args Args.
* @param {boolean} args.isDebug Whether to show debug messages.
*/
export async function initialize( { isDebug } ) {
const embedWrappers =
/** @type NodeListOf<HTMLDivElement> */ document.querySelectorAll(
'.wp-block-embed > .wp-block-embed__wrapper[data-od-xpath]'
);

for ( const embedWrapper of embedWrappers ) {
monitorEmbedWrapperForResizes( embedWrapper );
}

if ( isDebug ) {
log( 'Loaded embed content rects:', loadedElementContentRects );
}
}

/**
* Initialize.
westonruter marked this conversation as resolved.
Show resolved Hide resolved
*
* @param {Object} args Args.
* @param {boolean} args.isDebug Whether to show debug messages.
* @param {URLMetric} args.urlMetric Pending URL metric.
*/
export async function finalize( { urlMetric, isDebug } ) {
if ( isDebug ) {
log( 'URL metric to be sent:', urlMetric );
}

for ( const element of urlMetric.elements ) {
if ( loadedElementContentRects.has( element.xpath ) ) {
if ( isDebug ) {
log(
`Overriding boundingClientRect for ${ element.xpath }:`,
element.boundingClientRect,
'=>',
loadedElementContentRects.get( element.xpath )
);
}
// TODO: Maybe element.boundingClientRect should rather be element.initialBoundingClientRect and the schema is extended by Embed Optimizer to add an element.finalBoundingClientRect (same goes for intersectionRect and intersectionRatio).
element.boundingClientRect = loadedElementContentRects.get(
element.xpath
);
}
}
}

/**
* Monitors embed wrapper for resizes.
*
* @param {HTMLDivElement} embedWrapper Embed wrapper DIV.
*/
function monitorEmbedWrapperForResizes( embedWrapper ) {
if ( ! ( 'odXpath' in embedWrapper.dataset ) ) {
throw new Error( 'Embed wrapper missing data-od-xpath attribute.' );
}
const xpath = embedWrapper.dataset.odXpath;
const observer = new ResizeObserver( ( entries ) => {
const [ entry ] = entries;
loadedElementContentRects.set( xpath, entry.contentRect );
} );
observer.observe( embedWrapper, { box: 'content-box' } );
}
46 changes: 42 additions & 4 deletions plugins/embed-optimizer/hooks.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@ function embed_optimizer_add_hooks(): void {

if ( defined( 'OPTIMIZATION_DETECTIVE_VERSION' ) ) {
add_action( 'od_register_tag_visitors', 'embed_optimizer_register_tag_visitors' );
add_filter( 'embed_oembed_html', 'embed_optimizer_filter_oembed_html_to_detect_embed_presence' );
} else {
add_filter( 'embed_oembed_html', 'embed_optimizer_filter_oembed_html' );
add_filter( 'embed_oembed_html', 'embed_optimizer_filter_oembed_html_to_lazy_load' );
}
}
add_action( 'init', 'embed_optimizer_add_hooks' );
Expand All @@ -40,17 +41,54 @@ function embed_optimizer_register_tag_visitors( OD_Tag_Visitor_Registry $registr
}

/**
* Filter the oEmbed HTML.
* Filters the list of Optimization Detective extension module URLs to include the extension for Embed Optimizer.
*
* @since n.e.x.t
*
* @param string[]|mixed $extension_module_urls Extension module URLs.
* @return string[] Extension module URLs.
*/
function embed_optimizer_filter_extension_module_urls( $extension_module_urls ): array {
if ( ! is_array( $extension_module_urls ) ) {
$extension_module_urls = array();
}
$extension_module_urls[] = add_query_arg( 'ver', EMBED_OPTIMIZER_VERSION, plugin_dir_url( __FILE__ ) . 'detect.js' );
return $extension_module_urls;
}

/**
* Filter the oEmbed HTML to detect when an embed is present so that the Optimization Detective extension module can be enqueued.
*
* This ensures that the module for handling embeds is only loaded when there is an embed on the page.
*
* @since n.e.x.t
*
* @param string|mixed $html The oEmbed HTML.
* @return string Unchanged oEmbed HTML.
*/
function embed_optimizer_filter_oembed_html_to_detect_embed_presence( $html ): string {
if ( ! is_string( $html ) ) {
$html = '';
}
add_filter( 'od_extension_module_urls', 'embed_optimizer_filter_extension_module_urls' );
return $html;
}

/**
* Filter the oEmbed HTML to lazy load the embed.
*
* Add loading="lazy" to any iframe tags.
* Lazy load any script tags.
*
* @since 0.1.0
*
* @param string $html The oEmbed HTML.
* @param string|mixed $html The oEmbed HTML.
* @return string Filtered oEmbed HTML.
*/
function embed_optimizer_filter_oembed_html( string $html ): string {
function embed_optimizer_filter_oembed_html_to_lazy_load( $html ): string {
if ( ! is_string( $html ) ) {
$html = '';
}
$html_processor = new WP_HTML_Tag_Processor( $html );
if ( embed_optimizer_update_markup( $html_processor, true ) ) {
add_action( 'wp_footer', 'embed_optimizer_lazy_load_scripts' );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
$test_case->populate_url_metrics(
array(
array(
'xpath' => '/*[1][self::HTML]/*[2][self::BODY]/*[1][self::FIGURE]',
'xpath' => '/*[1][self::HTML]/*[2][self::BODY]/*[1][self::FIGURE]/*[1][self::DIV]',
'isLCP' => false,
'intersectionRatio' => 1,
),
Expand All @@ -14,7 +14,7 @@
'intersectionRatio' => 1,
),
array(
'xpath' => '/*[1][self::HTML]/*[2][self::BODY]/*[2][self::FIGURE]',
'xpath' => '/*[1][self::HTML]/*[2][self::BODY]/*[2][self::FIGURE]/*[1][self::DIV]',
'isLCP' => false,
'intersectionRatio' => 0,
),
Expand Down Expand Up @@ -74,12 +74,12 @@ static function ( OD_Tag_Visitor_Context $context ) use ( $test_case ): bool {
<title>...</title>
</head>
<body>
<figure class="wp-block-embed is-type-video">
<figure style="background: black; color:gray" class="wp-block-embed is-type-video">
<div class="wp-block-embed__wrapper">
<video src="https://example.com/video1.mp4" poster="https://example.com/poster1.jpg" width="640" height="480"></video>
</div>
</figure>
<figure class="wp-block-embed is-type-rich is-provider-figurine wp-block-embed-figurine">
<figure style="background: black; color: white;" class="wp-block-embed is-type-rich is-provider-figurine wp-block-embed-figurine">
<div class="wp-block-embed__wrapper">
<figure>
<p>So I heard you like <code>FIGURE</code>?</p>
Expand All @@ -101,13 +101,13 @@ static function ( OD_Tag_Visitor_Context $context ) use ( $test_case ): bool {
<link data-od-added-tag rel="preload" as="image" href="https://example.com/poster1.jpg">
</head>
<body>
<figure data-od-xpath="/*[1][self::HTML]/*[2][self::BODY]/*[1][self::FIGURE]" class="wp-block-embed is-type-video">
<div class="wp-block-embed__wrapper">
<figure data-od-replaced-style="background: black; color:gray" style="min-height: 500px; background: black; color:gray" class="wp-block-embed is-type-video">
<div data-od-xpath="/*[1][self::HTML]/*[2][self::BODY]/*[1][self::FIGURE]/*[1][self::DIV]" class="wp-block-embed__wrapper">
<video data-od-added-preload data-od-xpath="/*[1][self::HTML]/*[2][self::BODY]/*[1][self::FIGURE]/*[1][self::DIV]/*[1][self::VIDEO]" preload="auto" src="https://example.com/video1.mp4" poster="https://example.com/poster1.jpg" width="640" height="480"></video>
</div>
</figure>
<figure data-od-xpath="/*[1][self::HTML]/*[2][self::BODY]/*[2][self::FIGURE]" class="wp-block-embed is-type-rich is-provider-figurine wp-block-embed-figurine">
<div class="wp-block-embed__wrapper">
<figure data-od-replaced-style="background: black; color: white;" style="min-height: 500px; background: black; color: white;" class="wp-block-embed is-type-rich is-provider-figurine wp-block-embed-figurine">
<div data-od-xpath="/*[1][self::HTML]/*[2][self::BODY]/*[2][self::FIGURE]/*[1][self::DIV]" class="wp-block-embed__wrapper">
<figure>
<p>So I heard you like <code>FIGURE</code>?</p>
<video data-od-added-preload data-od-xpath="/*[1][self::HTML]/*[2][self::BODY]/*[2][self::FIGURE]/*[1][self::DIV]/*[1][self::FIGURE]/*[2][self::VIDEO]" preload="none" src="https://example.com/video2.mp4" poster="https://example.com/poster2.jpg" width="640" height="480"></video>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
$test_case->populate_url_metrics(
array(
array(
'xpath' => '/*[1][self::HTML]/*[2][self::BODY]/*[1][self::FIGURE]',
'xpath' => '/*[1][self::HTML]/*[2][self::BODY]/*[1][self::FIGURE]/*[1][self::DIV]',
'isLCP' => false,
'intersectionRatio' => 0,
),
Expand Down Expand Up @@ -35,8 +35,8 @@
<title>...</title>
</head>
<body>
<figure data-od-xpath="/*[1][self::HTML]/*[2][self::BODY]/*[1][self::FIGURE]" class="wp-block-embed is-type-rich is-provider-spotify wp-block-embed-spotify wp-embed-aspect-21-9 wp-has-aspect-ratio">
<div class="wp-block-embed__wrapper">
<figure data-od-added-style style="min-height: 500px;" class="wp-block-embed is-type-rich is-provider-spotify wp-block-embed-spotify wp-embed-aspect-21-9 wp-has-aspect-ratio">
<div data-od-xpath="/*[1][self::HTML]/*[2][self::BODY]/*[1][self::FIGURE]/*[1][self::DIV]" class="wp-block-embed__wrapper">
<iframe data-od-added-loading loading="lazy" title="Spotify Embed: Deep Focus" style="border-radius: 12px" width="100%" height="352" frameborder="0" allowfullscreen allow="autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture" src="https://open.spotify.com/embed/playlist/37i9dQZF1DWZeKCadgRdKQ?utm_source=oembed"></iframe>
</div>
</figure>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
$test_case->populate_url_metrics(
array(
array(
'xpath' => '/*[1][self::HTML]/*[2][self::BODY]/*[1][self::FIGURE]',
'xpath' => '/*[1][self::HTML]/*[2][self::BODY]/*[1][self::FIGURE]/*[1][self::DIV]',
'isLCP' => true,
'intersectionRatio' => 1,
),
Expand Down Expand Up @@ -36,7 +36,7 @@
<link data-od-added-tag rel="preconnect" href="https://pbs.twimg.com">
</head>
<body>
<figure class="wp-block-embed is-type-rich is-provider-twitter wp-block-embed-twitter">
<figure data-od-added-style style="min-height: 500px;" class="wp-block-embed is-type-rich is-provider-twitter wp-block-embed-twitter">
<div class="wp-block-embed__wrapper">
<blockquote class="twitter-tweet" data-width="550" data-dnt="true"><p lang="en" dir="ltr">We want your feedback for the Privacy Sandbox 📨<br><br>Learn why your feedback is critical through real examples and learn how to provide it ↓ <a href="https://t.co/anGk6gWkbc">https://t.co/anGk6gWkbc</a></p>&mdash; Chrome for Developers (@ChromiumDev) <a href="https://twitter.com/ChromiumDev/status/1636796541368139777?ref_src=twsrc%5Etfw">March 17, 2023</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
$test_case->populate_url_metrics(
array(
array(
'xpath' => '/*[1][self::HTML]/*[2][self::BODY]/*[1][self::FIGURE]',
'xpath' => '/*[1][self::HTML]/*[2][self::BODY]/*[1][self::FIGURE]/*[1][self::DIV]',
'isLCP' => false,
'intersectionRatio' => 0,
),
Expand Down Expand Up @@ -34,7 +34,7 @@
<title>...</title>
</head>
<body>
<figure class="wp-block-embed is-type-rich is-provider-twitter wp-block-embed-twitter">
<figure data-od-added-style style="min-height: 500px;" class="wp-block-embed is-type-rich is-provider-twitter wp-block-embed-twitter">
<div class="wp-block-embed__wrapper">
<blockquote class="twitter-tweet" data-width="550" data-dnt="true"><p lang="en" dir="ltr">We want your feedback for the Privacy Sandbox 📨<br><br>Learn why your feedback is critical through real examples and learn how to provide it ↓ <a href="https://t.co/anGk6gWkbc">https://t.co/anGk6gWkbc</a></p>&mdash; Chrome for Developers (@ChromiumDev) <a href="https://twitter.com/ChromiumDev/status/1636796541368139777?ref_src=twsrc%5Etfw">March 17, 2023</a></blockquote>
<script data-od-added-type type="application/vnd.embed-optimizer.javascript" async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
$test_case->populate_url_metrics(
array(
array(
'xpath' => '/*[1][self::HTML]/*[2][self::BODY]/*[1][self::FIGURE]',
'xpath' => '/*[1][self::HTML]/*[2][self::BODY]/*[1][self::FIGURE]/*[1][self::DIV]',
'isLCP' => true,
'intersectionRatio' => 1,
),
Expand Down Expand Up @@ -39,8 +39,8 @@
<link data-od-added-tag rel="preconnect" href="https://v0.wordpress.com">
</head>
<body>
<figure data-od-xpath="/*[1][self::HTML]/*[2][self::BODY]/*[1][self::FIGURE]" class="wp-block-embed is-type-video is-provider-wordpress-tv wp-block-embed-wordpress-tv wp-embed-aspect-16-9 wp-has-aspect-ratio">
<div class="wp-block-embed__wrapper">
<figure data-od-added-style style="min-height: 500px;" class="wp-block-embed is-type-video is-provider-wordpress-tv wp-block-embed-wordpress-tv wp-embed-aspect-16-9 wp-has-aspect-ratio">
<div data-od-xpath="/*[1][self::HTML]/*[2][self::BODY]/*[1][self::FIGURE]/*[1][self::DIV]" class="wp-block-embed__wrapper">
<iframe title="VideoPress Video Player" aria-label=\'VideoPress Video Player\' width=\'750\' height=\'422\' src=\'https://video.wordpress.com/embed/vaWm9zO6?hd=1&amp;cover=1\' frameborder=\'0\' allowfullscreen allow=\'clipboard-write\'></iframe>
<script src=\'https://v0.wordpress.com/js/next/videopress-iframe.js?m=1674852142\'></script>
</div>
Expand Down
Loading