Skip to content

Prepare 2026-02-27 release#2405

Merged
westonruter merged 8 commits intorelease/2026-02-27from
publish/2026-02-27
Feb 27, 2026
Merged

Prepare 2026-02-27 release#2405
westonruter merged 8 commits intorelease/2026-02-27from
publish/2026-02-27

Conversation

@westonruter
Copy link
Copy Markdown
Member

  • Bump versions
  • Bump tested up to 7.0
  • Add changelogs and include Image Placeholders
  • Revert erroneous bump to webp-uploads
  • Add changelog entry to Optimization Detective

@westonruter westonruter added [Type] Documentation Documentation to be added or enhanced Infrastructure Issues for the overall performance plugin infrastructure no milestone PRs that do not have a defined milestone for release skip changelog PRs that should not be mentioned in changelogs labels Feb 27, 2026
@westonruter
Copy link
Copy Markdown
Member Author

westonruter commented Feb 27, 2026

Pending Release Diffs

auto-sizes

Warning

Stable tag is unchanged at 1.7.0, so no plugin release will occur.

svn status:

M       includes/improve-calculate-sizes.php
M       readme.txt
svn diff
Index: includes/improve-calculate-sizes.php
===================================================================
--- includes/improve-calculate-sizes.php	(revision 3470885)
+++ includes/improve-calculate-sizes.php	(working copy)
@@ -6,6 +6,12 @@
  * @since 1.4.0
  */
 
+// @codeCoverageIgnoreStart
+if ( ! defined( 'ABSPATH' ) ) {
+	exit; // Exit if accessed directly.
+}
+// @codeCoverageIgnoreEnd
+
 /*
  * Map alignment values to a weighting value so they can be compared.
  * Note that 'left' and 'right' alignments are only constrained by max alignment.
Index: readme.txt
===================================================================
--- readme.txt	(revision 3470885)
+++ readme.txt	(working copy)
@@ -1,7 +1,7 @@
 === Enhanced Responsive Images ===
 
 Contributors: wordpressdotorg
-Tested up to: 6.9
+Tested up to: 7.0
 Stable tag:   1.7.0
 License:      GPLv2 or later
 License URI:  https://www.gnu.org/licenses/gpl-2.0.html

dominant-color-images

Important

Stable tag change: 1.2.0 → 1.2.1

svn status:

M       helper.php
M       hooks.php
M       load.php
M       readme.txt
svn diff
Index: helper.php
===================================================================
--- helper.php	(revision 3470885)
+++ helper.php	(working copy)
@@ -7,6 +7,12 @@
  * @since 1.0.0
  */
 
+// @codeCoverageIgnoreStart
+if ( ! defined( 'ABSPATH' ) ) {
+	exit; // Exit if accessed directly.
+}
+// @codeCoverageIgnoreEnd
+
 /**
  * Overloads wp_image_editors() to load the extended classes.
  *
@@ -17,10 +23,10 @@
  */
 function dominant_color_set_image_editors( array $editors ): array {
 	if ( ! class_exists( 'Dominant_Color_Image_Editor_GD' ) ) {
-		require_once __DIR__ . '/class-dominant-color-image-editor-gd.php';
+		require_once __DIR__ . '/class-dominant-color-image-editor-gd.php';// @codeCoverageIgnore
 	}
 	if ( ! class_exists( 'Dominant_Color_Image_Editor_Imagick' ) ) {
-		require_once __DIR__ . '/class-dominant-color-image-editor-imagick.php';
+		require_once __DIR__ . '/class-dominant-color-image-editor-imagick.php';// @codeCoverageIgnore
 	}
 
 	$replaces = array(
@@ -41,6 +47,13 @@
 /**
  * Computes the dominant color of the given attachment image and whether it has transparency.
  *
+ * The image types jpeg, png, gif, webp, and avif are supported for determining the dominant color.
+ *
+ * Animated GIFs are supported, but when the GD-based editor is used only the first frame is
+ * processed to determine the dominant color. This may not represent the dominant color of the
+ * entire animation. This behavior is intentional and can be customized via the
+ * {@see 'dominant_color_supported_mime_types'} filter if needed.
+ *
  * @since 1.0.0
  *
  * @access private
@@ -49,10 +62,31 @@
  * @return array{ has_transparency?: bool, dominant_color?: string }|WP_Error Array with the dominant color and has transparency values or WP_Error on error.
  */
 function dominant_color_get_dominant_color_data( int $attachment_id ) {
-	$mime_type = get_post_mime_type( $attachment_id );
-	if ( 'application/pdf' === $mime_type ) {
-		return new WP_Error( 'no_image_found', __( 'Unable to load image.', 'dominant-color-images' ) );
+	$mime_type            = get_post_mime_type( $attachment_id );
+	$supported_mime_types = array(
+		'image/jpeg',
+		'image/png',
+		'image/gif',
+		'image/webp',
+		'image/avif',
+	);
+
+	/**
+	 * Filters supported mime types for dominant color extraction.
+	 *
+	 * Filter the array of supported mime types for dominant color extraction, by default the plugin
+	 * supports image types supported by WordPress Core.
+	 *
+	 * @since 1.2.1
+	 *
+	 * @param string[] $supported_mime_types Array of supported mime types. Defaults are 'image/jpeg', 'image/png', 'image/gif', 'image/webp', 'image/avif'.
+	 */
+	$supported_mime_types = (array) apply_filters( 'dominant_color_supported_mime_types', $supported_mime_types );
+
+	if ( ! in_array( $mime_type, $supported_mime_types, true ) ) {
+		return new WP_Error( 'unsupported_attachment_type', __( 'Unsupported attachment type.', 'dominant-color-images' ) );
 	}
+
 	$file = dominant_color_get_attachment_file_path( $attachment_id );
 	if ( false === $file ) {
 		$file = get_attached_file( $attachment_id );
Index: hooks.php
===================================================================
--- hooks.php	(revision 3470885)
+++ hooks.php	(working copy)
@@ -7,9 +7,11 @@
  * @since 1.0.0
  */
 
+// @codeCoverageIgnoreStart
 if ( ! defined( 'ABSPATH' ) ) {
 	exit; // Exit if accessed directly.
 }
+// @codeCoverageIgnoreEnd
 
 /**
  * Add the dominant color metadata to the attachment.
@@ -63,16 +65,17 @@
 		$attr['data-has-transparency'] = $image_meta['has_transparency'] ? 'true' : 'false';
 
 		$class = $image_meta['has_transparency'] ? 'has-transparency' : 'not-transparent';
-		if ( empty( $attr['class'] ) ) {
+
+		if ( isset( $attr['class'] ) && is_string( $attr['class'] ) && '' !== $attr['class'] ) {
+			$attr['class'] .= ' ' . $class;
+		} else {
 			$attr['class'] = $class;
-		} else {
-			$attr['class'] .= ' ' . $class;
 		}
 	}
 
-	if ( ! empty( $image_meta['dominant_color'] ) ) {
+	if ( isset( $image_meta['dominant_color'] ) && is_string( $image_meta['dominant_color'] ) && '' !== $image_meta['dominant_color'] ) {
 		$attr['data-dominant-color'] = esc_attr( $image_meta['dominant_color'] );
-		$style_attribute             = empty( $attr['style'] ) ? '' : $attr['style'];
+		$style_attribute             = isset( $attr['style'] ) && is_string( $attr['style'] ) ? $attr['style'] : '';
 		$attr['style']               = '--dominant-color: #' . esc_attr( $image_meta['dominant_color'] ) . ';' . $style_attribute;
 	}
 
@@ -138,7 +141,7 @@
 		return $filtered_image;
 	}
 
-	if ( ! empty( $image_meta['dominant_color'] ) ) {
+	if ( isset( $image_meta['dominant_color'] ) && is_string( $image_meta['dominant_color'] ) && '' !== $image_meta['dominant_color'] ) {
 		$processor->set_attribute( 'data-dominant-color', $image_meta['dominant_color'] );
 
 		$style_attribute = '--dominant-color: #' . $image_meta['dominant_color'] . '; ';
Index: load.php
===================================================================
--- load.php	(revision 3470885)
+++ load.php	(working copy)
@@ -5,7 +5,7 @@
  * Description: Displays placeholders based on an image's dominant color while the image is loading.
  * Requires at least: 6.6
  * Requires PHP: 7.2
- * Version: 1.2.0
+ * Version: 1.2.1
  * Author: WordPress Performance Team
  * Author URI: https://make.wordpress.org/performance/
  * License: GPLv2 or later
@@ -15,17 +15,19 @@
  * @package dominant-color-images
  */
 
-// Exit if accessed directly.
+// @codeCoverageIgnoreStart
 if ( ! defined( 'ABSPATH' ) ) {
-	exit;
+	exit; // Exit if accessed directly.
 }
 
+
 // Define required constants.
 if ( defined( 'DOMINANT_COLOR_IMAGES_VERSION' ) ) {
 	return;
 }
 
-define( 'DOMINANT_COLOR_IMAGES_VERSION', '1.2.0' );
+define( 'DOMINANT_COLOR_IMAGES_VERSION', '1.2.1' );
 
 require_once __DIR__ . '/helper.php';
 require_once __DIR__ . '/hooks.php';
+// @codeCoverageIgnoreEnd
Index: readme.txt
===================================================================
--- readme.txt	(revision 3470885)
+++ readme.txt	(working copy)
@@ -1,8 +1,8 @@
 === Image Placeholders ===
 
 Contributors: wordpressdotorg
-Tested up to: 6.9
-Stable tag:   1.2.0
+Tested up to: 7.0
+Stable tag:   1.2.1
 License:      GPLv2 or later
 License URI:  https://www.gnu.org/licenses/gpl-2.0.html
 Tags:         performance, images, dominant color
@@ -47,6 +47,12 @@
 
 == Changelog ==
 
+= 1.2.1 =
+
+**Bug Fixes**
+
+* Only attempt to get dominant colour for image mime types. ([2264](https://github.com/WordPress/performance/pull/2264))
+
 = 1.2.0 =
 
 **Enhancements**

embed-optimizer

Important

Stable tag change: 1.0.0-beta4 → 1.0.0-beta5

svn status:

M       class-embed-optimizer-tag-visitor.php
M       load.php
M       readme.txt
svn diff
Index: class-embed-optimizer-tag-visitor.php
===================================================================
--- class-embed-optimizer-tag-visitor.php	(revision 3470885)
+++ class-embed-optimizer-tag-visitor.php	(working copy)
@@ -78,11 +78,12 @@
 	 * Metrics (by returning true). When visiting the parent `figure.wp-block-embed` tag, it does all the actual
 	 * processing. In particular, it will use the element metrics gathered for the child `div.wp-block-embed__wrapper`
 	 * element to set the min-height style on the `figure.wp-block-embed` to avoid layout shifts. Additionally, when
-	 * the embed is in the initial viewport for any breakpoint, it will add preconnect links for key resources.
+	 * the embed is in the initial viewport for any breakpoint, it will add dns-prefetch links for key resources.
 	 * Otherwise, if the embed is not in any initial viewport, it will add lazy-loading logic.
 	 *
 	 * @since 0.2.0
 	 * @since 0.4.0 Adds preconnect links for each viewport group and skips if the element is not in the viewport for that group.
+	 * @since 1.0.0 Switches from preconnect links to dns-prefetch links.
 	 *
 	 * @param OD_Tag_Visitor_Context $context Tag visitor context.
 	 * @return bool Whether the tag should be tracked in URL Metrics.
@@ -104,7 +105,7 @@
 		}
 
 		$this->reduce_layout_shifts( $context );
-		$this->add_preconnect_links( $context );
+		$this->add_dns_prefetch_links( $context );
 		$this->lazy_load_embeds( $context );
 
 		/*
@@ -280,24 +281,25 @@
 	}
 
 	/**
-	 * Gets preconnect URLs based on embed type.
+	 * Gets dns-prefetch URLs based on embed type.
 	 *
 	 * The following embeds have been chosen for optimization due to their relative popularity among all embed types.
-	 * The list of hosts being preconnected to was obtained by inserting an embed into a post and then looking
+	 * The list of hosts being dns-prefetched to was obtained by inserting an embed into a post and then looking
 	 * at the network log on the frontend as the embed renders. Each should include the host of the iframe src
 	 * as well as URLs for assets used by the embed, _if_ the URL looks like it is not geotargeted (e.g. '-us')
 	 * or load-balanced (e.g. 's0.example.com'). For the load balancing case, attempt to load the asset by
 	 * incrementing the number appearing in the subdomain (e.g. s1.example.com). If the asset still loads, then
-	 * it is a likely case of a load balancing domain name which cannot be safely preconnected since it could
+	 * it is a likely case of a load balancing domain name which cannot be effectively dns-prefetched since it could
 	 * not end up being the load balanced domain used for the embed. Lastly, these domains are only for the URLs
 	 * for GET requests, as POST requests are not likely to be part of the critical rendering path.
 	 *
 	 * @since 0.4.1
+	 * @since 1.0.0 This was originally the ::get_preconnect_urls() method, renamed to use dns-prefetch.
 	 *
 	 * @param OD_HTML_Tag_Processor $processor Processor, with the cursor currently at an embed block.
-	 * @return array<non-empty-string> Array of URLs to preconnect to.
+	 * @return array<non-empty-string> Array of URLs to dns-prefetch.
 	 */
-	private function get_preconnect_urls( OD_HTML_Tag_Processor $processor ): array {
+	private function get_dns_prefetch_urls( OD_HTML_Tag_Processor $processor ): array {
 		$urls      = array();
 		$has_class = static function ( string $wanted_class ) use ( $processor ): bool {
 			return true === $processor->has_class( $wanted_class );
@@ -332,7 +334,7 @@
 			// Note: The other domains used for TikTok embeds include https://lf16-tiktok-web.tiktokcdn-us.com,
 			// https://lf16-cdn-tos.tiktokcdn-us.com, and https://lf16-tiktok-common.tiktokcdn-us.com among others
 			// which either appear to be geo-targeted ('-us') _or_ load-balanced ('lf16'). So these are not added
-			// to the preconnected hosts.
+			// to the dns-prefetched hosts.
 		} elseif ( $has_class( 'wp-block-embed-amazon' ) ) {
 			$urls[] = 'https://read.amazon.com';
 			$urls[] = 'https://m.media-amazon.com';
@@ -350,17 +352,18 @@
 	}
 
 	/**
-	 * Adds preconnect links for embed resources.
+	 * Adds dns-prefetch links for embed resources.
 	 *
 	 * @since 0.4.1
+	 * @since 1.0.0 This was originally the ::add_preconnect_links() method, renamed to use dns-prefetch.
 	 *
 	 * @param OD_Tag_Visitor_Context $context Tag visitor context, with the cursor currently at an embed block.
 	 */
-	private function add_preconnect_links( OD_Tag_Visitor_Context $context ): void {
+	private function add_dns_prefetch_links( OD_Tag_Visitor_Context $context ): void {
 		$processor           = $context->processor;
 		$embed_wrapper_xpath = self::get_embed_wrapper_xpath( $processor->get_xpath() );
 
-		foreach ( $this->get_preconnect_urls( $processor ) as $preconnect_url ) {
+		foreach ( $this->get_dns_prefetch_urls( $processor ) as $dns_prefetch_url ) {
 			foreach ( $context->url_metric_group_collection as $group ) {
 				if ( $group->get_element_max_intersection_ratio( $embed_wrapper_xpath ) < PHP_FLOAT_EPSILON ) {
 					continue;
@@ -368,8 +371,8 @@
 
 				$context->link_collection->add_link(
 					array(
-						'rel'  => 'preconnect',
-						'href' => $preconnect_url,
+						'rel'  => 'dns-prefetch',
+						'href' => $dns_prefetch_url,
 					),
 					$group->get_minimum_viewport_width(),
 					$group->get_maximum_viewport_width()
Index: load.php
===================================================================
--- load.php	(revision 3470885)
+++ load.php	(working copy)
@@ -2,10 +2,10 @@
 /**
  * Plugin Name: Embed Optimizer
  * Plugin URI: https://github.com/WordPress/performance/tree/trunk/plugins/embed-optimizer
- * Description: Optimizes the performance of embeds through lazy-loading, preconnecting, and reserving space to reduce layout shifts.
+ * Description: Optimizes the performance of embeds through lazy-loading, adding dns-prefetch links, and reserving space to reduce layout shifts.
  * Requires at least: 6.6
  * Requires PHP: 7.2
- * Version: 1.0.0-beta4
+ * Version: 1.0.0-beta5
  * Author: WordPress Performance Team
  * Author URI: https://make.wordpress.org/performance/
  * License: GPLv2 or later
@@ -71,7 +71,7 @@
 	}
 )(
 	'embed_optimizer_pending_plugin',
-	'1.0.0-beta4',
+	'1.0.0-beta5',
 	static function ( string $version ): void {
 		if ( defined( 'EMBED_OPTIMIZER_VERSION' ) ) {
 			return;
Index: readme.txt
===================================================================
--- readme.txt	(revision 3470885)
+++ readme.txt	(working copy)
@@ -1,13 +1,13 @@
 === Embed Optimizer ===
 
 Contributors: wordpressdotorg
-Tested up to: 6.9
-Stable tag:   1.0.0-beta4
+Tested up to: 7.0
+Stable tag:   1.0.0-beta5
 License:      GPLv2 or later
 License URI:  https://www.gnu.org/licenses/gpl-2.0.html
 Tags:         performance, embeds, optimization-detective
 
-Optimizes the performance of embeds through lazy-loading, preconnecting, and reserving space to reduce layout shifts.
+Optimizes the performance of embeds through lazy-loading, adding dns-prefetch links, and reserving space to reduce layout shifts.
 
 == Description ==
 
@@ -16,7 +16,7 @@
 The current optimizations include:
 
 1. Lazy loading embeds just before they come into view.
-2. Adding preconnect links for embeds in the initial viewport.
+2. Adding dns-prefetch links for embeds in the initial viewport.
 3. Reserving space for embeds that resize to reduce layout shifting.
 
 **Lazy loading embeds** improves performance because embeds are generally very resource-intensive, so lazy loading them ensures that they don't compete with resources when the page is loading. Lazy loading of `IFRAME`\-based embeds is handled simply by adding the `loading=lazy` attribute. Lazy loading embeds that include `SCRIPT` tags is handled by using an Intersection Observer to watch for when the embed’s `FIGURE` container is going to enter the viewport, and then it dynamically inserts the `SCRIPT` tag.
@@ -23,7 +23,7 @@
 
 **This plugin also recommends that you install and activate the [Optimization Detective](https://wordpress.org/plugins/optimization-detective/) plugin**, which unlocks several optimizations beyond just lazy loading. Without Optimization Detective, lazy loading can actually degrade performance *when an embed is positioned in the initial viewport*. This is because lazy loading such viewport-initial elements can degrade LCP since rendering is delayed by the logic to determine whether the element is visible. This is why WordPress Core tries its best to [avoid](https://make.wordpress.org/core/2021/07/15/refining-wordpress-cores-lazy-loading-implementation/) [lazy loading](https://make.wordpress.org/core/2021/07/15/refining-wordpress-cores-lazy-loading-implementation/) `IMG` tags which appear in the initial viewport, although the server-side heuristics aren’t perfect. This is where Optimization Detective comes in since it detects whether an embed appears in any breakpoint-specific viewports, like mobile, tablet, and desktop. (See also the [Image Prioritizer](https://wordpress.org/plugins/image-prioritizer/) plugin which extends Optimization Detective to ensure lazy loading is correctly applied based on whether an IMG is in the initial viewport.)
 
-When Optimization Detective is active, it will start keeping track of which embeds appear in the initial viewport based on actual visits to your site. With this information in hand, Embed Optimizer will then avoid lazy loading embeds which appear in the initial viewport. Furthermore, for such above-the-fold embeds Embed Optimizer will also **add preconnect links** for resources known to be used by those embeds. For example, if a YouTube embed appears in the initial viewport, Embed Optimizer with Optimization Detective will omit `loading=lazy` while also adding a preconnect link for `https://i.ytimg.com` which is the domain from which YouTube video poster images are served. Such preconnect links cause the initial-viewport embeds to load even faster.
+When Optimization Detective is active, it will start keeping track of which embeds appear in the initial viewport based on actual visits to your site. With this information in hand, Embed Optimizer will then avoid lazy loading embeds which appear in the initial viewport. Furthermore, for such above-the-fold embeds Embed Optimizer will also **add dns-prefetch links** for resources known to be used by those embeds. For example, if a YouTube embed appears in the initial viewport, Embed Optimizer with Optimization Detective will omit `loading=lazy` while also adding a `dns-prefetch` link for `https://i.ytimg.com` which is the domain from which YouTube video poster images are served. Such links cause the initial-viewport embeds to load even faster.
 
 The other major feature in Embed Optimizer enabled by Optimization Detective is the **reduction of layout shifts** caused by embeds that resize when they load. This is seen commonly in WordPress post embeds or Tweet embeds. Embed Optimizer keeps track of the resized heights of these embeds. With these resized heights stored, Embed Optimizer sets the appropriate height on the container FIGURE element as the viewport-specific `min-height` so that when the embed loads it does not cause a layout shift.
 
@@ -67,6 +67,12 @@
 
 == Changelog ==
 
+= 1.0.0-beta5 =
+
+**Bug Fixes**
+
+* Switch initial viewport embeds from preconnect to dns-prefetch links. ([2256](https://github.com/WordPress/performance/pull/2256))
+
 = 1.0.0-beta4 =
 
 **Security**

image-prioritizer

Warning

Stable tag is unchanged at 1.0.0-beta3, so no plugin release will occur.

svn status:

M       readme.txt
svn diff
Index: readme.txt
===================================================================
--- readme.txt	(revision 3470885)
+++ readme.txt	(working copy)
@@ -1,7 +1,7 @@
 === Image Prioritizer ===
 
 Contributors: wordpressdotorg
-Tested up to: 6.9
+Tested up to: 7.0
 Stable tag:   1.0.0-beta3
 License:      GPLv2 or later
 License URI:  https://www.gnu.org/licenses/gpl-2.0.html

optimization-detective

Important

Stable tag change: 1.0.0-beta4 → 1.0.0-beta5

svn status:

M       class-od-link-collection.php
M       helper.php
M       readme.txt
M       storage/data.php
svn diff
Index: class-od-link-collection.php
===================================================================
--- class-od-link-collection.php	(revision 3470885)
+++ class-od-link-collection.php	(working copy)
@@ -22,7 +22,7 @@
  *               }
  *
  * @phpstan-type LinkAttributes array{
- *                   rel: 'preload'|'modulepreload'|'preconnect',
+ *                   rel: 'preload'|'modulepreload'|'preconnect'|'dns-prefetch',
  *                   href?: non-empty-string,
  *                   imagesrcset?: non-empty-string,
  *                   imagesizes?: non-empty-string,
@@ -37,6 +37,7 @@
  *
  * @since 0.3.0
  * @since 0.4.0 Renamed from OD_Preload_Link_Collection.
+ * @since 1.0.0 Added support for dns-prefetch.
  */
 final class OD_Link_Collection implements Countable {
 
@@ -53,6 +54,7 @@
 	 * Adds link.
 	 *
 	 * @since 0.3.0
+	 * @since 1.0.0 Added support for dns-prefetch.
 	 *
 	 * @phpstan-param LinkAttributes $attributes
 	 *
@@ -82,6 +84,11 @@
 				/* translators: 1: link, 2: rel=preconnect, 3: 'href' attribute name */
 				sprintf( __( 'A %1$s with %2$s must include an "%3$s" attribute.', 'optimization-detective' ), 'link', 'rel=preconnect', 'href' )
 			);
+		} elseif ( 'dns-prefetch' === $attributes['rel'] && ! array_key_exists( 'href', $attributes ) ) {
+			$throw_invalid_argument_exception(
+				/* translators: 1: link, 2: rel=dns-prefetch, 3: 'href' attribute name */
+				sprintf( __( 'A %1$s with %2$s must include an "%3$s" attribute.', 'optimization-detective' ), 'link', 'rel=dns-prefetch', 'href' )
+			);
 		}
 		if ( ! array_key_exists( 'href', $attributes ) && ! array_key_exists( 'imagesrcset', $attributes ) ) {
 			$throw_invalid_argument_exception(
Index: helper.php
===================================================================
--- helper.php	(revision 3470885)
+++ helper.php	(working copy)
@@ -293,7 +293,7 @@
 		),
 		'embed-optimizer'   => array(
 			'name'        => __( 'Embed Optimizer', 'optimization-detective' ),
-			'description' => __( 'Optimizes the performance of embeds through lazy-loading, preconnecting, and reserving space to reduce layout shifts.', 'optimization-detective' ),
+			'description' => __( 'Optimizes the performance of embeds through lazy-loading, adding dns-prefetch links, and reserving space to reduce layout shifts.', 'optimization-detective' ),
 			'url'         => admin_url( 'plugin-install.php?tab=plugin-information&plugin=embed-optimizer&TB_iframe=true&width=772' ),
 		),
 	);
Index: readme.txt
===================================================================
--- readme.txt	(revision 3470885)
+++ readme.txt	(working copy)
@@ -1,8 +1,8 @@
 === Optimization Detective ===
 
 Contributors: wordpressdotorg
-Tested up to: 6.9
-Stable tag:   1.0.0-beta4
+Tested up to: 7.0
+Stable tag:   1.0.0-beta5
 License:      GPLv2 or later
 License URI:  https://www.gnu.org/licenses/gpl-2.0.html
 Tags:         performance, optimization, rum
@@ -55,6 +55,16 @@
 
 == Changelog ==
 
+= 1.0.0-beta5 =
+
+**Bug Fixes**
+
+* Prevent fatal error in `od_get_current_url_metrics_etag()` when `$wp_query->posts` is `null`. ([2347](https://github.com/WordPress/performance/pull/2347))
+
+**Enhancements**
+
+* Add support for dns-prefetch links. ([2256](https://github.com/WordPress/performance/pull/2256))
+
 = 1.0.0-beta4 =
 
 **Enhancements**
Index: storage/data.php
===================================================================
--- storage/data.php	(revision 3470885)
+++ storage/data.php	(working copy)
@@ -212,7 +212,7 @@
 						'post_modified_gmt' => $post->post_modified_gmt,
 					);
 				},
-				( $wp_query instanceof WP_Query && $wp_query->post_count > 0 ) ? $wp_query->posts : array()
+				( $wp_query instanceof WP_Query && is_array( $wp_query->posts ) ) ? $wp_query->posts : array()
 			)
 		),
 		'active_theme'     => array(

performance-lab

Important

Stable tag change: 4.0.1 → 4.1.0

svn status:

M       includes/server-timing/defaults.php
M       load.php
M       readme.txt
svn diff
Index: includes/server-timing/defaults.php
===================================================================
--- includes/server-timing/defaults.php	(revision 3470885)
+++ includes/server-timing/defaults.php	(working copy)
@@ -47,8 +47,11 @@
 				'before-template-db-queries',
 				array(
 					'measure_callback' => static function ( $metric ) use ( $current_function ): void {
+						// If no queries have been run yet, $wpdb->queries will be null, which is valid (0 queries).
+						$queries = $GLOBALS['wpdb']->queries ?? array();
+
 						// This should never happen, but some odd database implementations may be doing it wrong.
-						if ( ! isset( $GLOBALS['wpdb']->queries ) || ! is_array( $GLOBALS['wpdb']->queries ) ) {
+						if ( ! is_array( $queries ) ) {
 							wp_trigger_error(
 								$current_function,
 								esc_html(
@@ -69,7 +72,7 @@
 						 * @var float[] $query_times
 						 */
 						$query_times = array();
-						foreach ( $GLOBALS['wpdb']->queries as $query ) {
+						foreach ( $queries as $query ) {
 							if ( ! is_array( $query ) || ! isset( $query[1] ) || ! is_float( $query[1] ) ) {
 								wp_trigger_error(
 									$current_function,
@@ -196,8 +199,11 @@
 								return;
 							}
 
+							// If no queries have been run yet, $wpdb->queries will be null, which is valid (0 queries).
+							$queries = $GLOBALS['wpdb']->queries ?? array();
+
 							// This should never happen, but some odd database implementations may be doing it wrong.
-							if ( ! isset( $GLOBALS['wpdb']->queries ) || ! is_array( $GLOBALS['wpdb']->queries ) ) {
+							if ( ! is_array( $queries ) ) {
 								// A notice is already emitted above, but if $perflab_query_time_before_template was not
 								// set, then this condition wouldn't be checked in the first place.
 								return;
@@ -209,7 +215,7 @@
 							 * @var float[] $query_times
 							 */
 							$query_times = array();
-							foreach ( $GLOBALS['wpdb']->queries as $query ) {
+							foreach ( $queries as $query ) {
 								if ( ! is_array( $query ) || ! isset( $query[1] ) || ! is_float( $query[1] ) ) {
 									// A notice is already emitted above.
 									return;
Index: load.php
===================================================================
--- load.php	(revision 3470885)
+++ load.php	(working copy)
@@ -5,7 +5,7 @@
  * Description: Performance plugin from the WordPress Performance Team, which is a collection of standalone performance features.
  * Requires at least: 6.6
  * Requires PHP: 7.2
- * Version: 4.0.1
+ * Version: 4.1.0
  * Author: WordPress Performance Team
  * Author URI: https://make.wordpress.org/performance/
  * License: GPLv2 or later
@@ -21,7 +21,7 @@
 }
 // @codeCoverageIgnoreEnd
 
-define( 'PERFLAB_VERSION', '4.0.1' );
+define( 'PERFLAB_VERSION', '4.1.0' );
 define( 'PERFLAB_MAIN_FILE', __FILE__ );
 define( 'PERFLAB_PLUGIN_DIR_PATH', plugin_dir_path( PERFLAB_MAIN_FILE ) );
 define( 'PERFLAB_SCREEN', 'performance-lab' );
@@ -123,10 +123,6 @@
 			'constant'     => 'VIEW_TRANSITIONS_VERSION',
 			'experimental' => true,
 		),
-		'web-worker-offloading'   => array(
-			'constant'     => 'WEB_WORKER_OFFLOADING_VERSION',
-			'experimental' => true,
-		),
 		'webp-uploads'            => array(
 			'constant' => 'WEBP_UPLOADS_VERSION',
 		),
Index: readme.txt
===================================================================
--- readme.txt	(revision 3470885)
+++ readme.txt	(working copy)
@@ -1,8 +1,8 @@
 === Performance Lab ===
 
 Contributors: wordpressdotorg
-Tested up to: 6.9
-Stable tag:   4.0.1
+Tested up to: 7.0
+Stable tag:   4.1.0
 License:      GPLv2 or later
 License URI:  https://www.gnu.org/licenses/gpl-2.0.html
 Tags:         performance, site health, measurement, optimization, diagnostics
@@ -25,7 +25,6 @@
 * [Performant Translations](https://wordpress.org/plugins/performant-translations/)
 * [Speculative Loading](https://wordpress.org/plugins/speculation-rules/)
 * [View Transitions](https://wordpress.org/plugins/view-transitions/) _(experimental)_
-* [Web Worker Offloading](https://wordpress.org/plugins/web-worker-offloading/) _(experimental)_
 
 These plugins can also be installed separately from installing Performance Lab, but having the Performance Lab plugin also active will ensure you find out about new performance features as they are developed.
 
@@ -74,6 +73,16 @@
 
 == Changelog ==
 
+= 4.1.0 =
+
+**Bug Fixes**
+
+* Fix invalid Server-Timing logic for database query timing when `$wpdb->queries` is `null` due to no query having been done yet. ([2346](https://github.com/WordPress/performance/pull/2346))
+
+**Documentation**
+
+* Remove Web Worker Offloading from being featured by Performance Lab. ([2404](https://github.com/WordPress/performance/pull/2404))
+
 = 4.0.1 =
 
 **Bug Fixes**

speculation-rules

Warning

Stable tag is unchanged at 1.6.0, so no plugin release will occur.

svn status:

M       load.php
M       plugin-api.php
M       settings.php
M       uninstall.php
svn diff
Index: load.php
===================================================================
--- load.php	(revision 3470885)
+++ load.php	(working copy)
@@ -59,8 +59,8 @@
 			// Otherwise, register this copy if it is actually the one installed in the directory for plugins.
 			rtrim( WP_PLUGIN_DIR, '/' ) === dirname( __DIR__ )
 		) {
-			$GLOBALS[ $global_var_name ]['version'] = $version;
-			$GLOBALS[ $global_var_name ]['load']    = $load;
+			$GLOBALS[ $global_var_name ]['version'] = $version; // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound -- It is prefixed.
+			$GLOBALS[ $global_var_name ]['load']    = $load; // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound -- It is prefixed.
 		}
 	}
 )(
Index: plugin-api.php
===================================================================
--- plugin-api.php	(revision 3470885)
+++ plugin-api.php	(working copy)
@@ -135,7 +135,7 @@
 	}
 
 	wp_print_inline_script_tag(
-		(string) wp_json_encode( plsr_get_speculation_rules() ),
+		(string) wp_json_encode( plsr_get_speculation_rules(), JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ),
 		array( 'type' => 'speculationrules' )
 	);
 }
Index: settings.php
===================================================================
--- settings.php	(revision 3470885)
+++ settings.php	(working copy)
@@ -340,6 +340,7 @@
 				}
 JS;
 			// 👆 This 'JS;' line can only be indented two tabs when minimum PHP version is increased to 7.3+.
+			$js .= "\n//# sourceURL=speculation-rules-auth-admin-notice";
 			wp_print_inline_script_tag( $js, array( 'type' => 'module' ) );
 			?>
 		<?php endif; ?>
Index: uninstall.php
===================================================================
--- uninstall.php	(revision 3470885)
+++ uninstall.php	(working copy)
@@ -13,7 +13,7 @@
 
 // For a multisite, delete the option for all sites (however limited to 100 sites to avoid memory limit or timeout problems in large scale networks).
 if ( is_multisite() ) {
-	$site_ids = get_sites(
+	$plsr_site_ids = get_sites(
 		array(
 			'fields'                 => 'ids',
 			'number'                 => 100,
@@ -22,8 +22,8 @@
 		)
 	);
 
-	foreach ( $site_ids as $site_id ) {
-		switch_to_blog( $site_id );
+	foreach ( $plsr_site_ids as $plsr_site_id ) {
+		switch_to_blog( $plsr_site_id );
 		plsr_delete_plugin_option();
 		restore_current_blog();
 	}

view-transitions

Important

Stable tag change: 1.1.2 → 1.2.0

svn status:

M       css/view-transition-animation-wipe.min.css
M       includes/admin.php
M       includes/settings.php
M       readme.txt
svn diff
Index: css/view-transition-animation-wipe.min.css
===================================================================
--- css/view-transition-animation-wipe.min.css	(revision 3470885)
+++ css/view-transition-animation-wipe.min.css	(working copy)
@@ -1 +1 @@
-@property --plvt-view-transition-animation-wipe-angle{syntax:"<angle>";initial-value:270deg;inherits:false}@property --plvt-view-transition-animation-wipe-progress{syntax:"<number>";initial-value:0;inherits:false}@property --plvt-view-transition-animation-duration{syntax:"<time>";initial-value:1s;inherits:false}@keyframes plvt-view-transition-animation-wipe-new{0%{--plvt-view-transition-animation-wipe-progress:0}to{--plvt-view-transition-animation-wipe-progress:1}}::view-transition-new(*),::view-transition-old(*){backface-visibility:hidden;mix-blend-mode:normal}::view-transition-old(root){animation:none var(--plvt-view-transition-animation-duration) cubic-bezier(.45,0,.35,1);animation-delay:0s;animation-fill-mode:both;opacity:1;transform:none}::view-transition-new(root){animation:plvt-view-transition-animation-wipe-new var(--plvt-view-transition-animation-duration) cubic-bezier(.45,0,.35,1);animation-fill-mode:both;-webkit-mask-image:linear-gradient(var(--plvt-view-transition-animation-wipe-angle),#000 calc(-70% + 170%*var(--plvt-view-transition-animation-wipe-progress, 0)),transparent calc(170%*var(--plvt-view-transition-animation-wipe-progress, 0)));mask-image:linear-gradient(var(--plvt-view-transition-animation-wipe-angle),#000 calc(-70% + 170%*var(--plvt-view-transition-animation-wipe-progress, 0)),transparent calc(170%*var(--plvt-view-transition-animation-wipe-progress, 0)));opacity:1;transform:none}
\ No newline at end of file
+@property --plvt-view-transition-animation-wipe-angle{syntax:"<angle>";initial-value:270deg;inherits:false}@property --plvt-view-transition-animation-wipe-progress{syntax:"<number>";initial-value:0;inherits:false}@property --plvt-view-transition-animation-duration{syntax:"<time>";initial-value:1s;inherits:false}@keyframes plvt-view-transition-animation-wipe-new{0%{--plvt-view-transition-animation-wipe-progress:0}to{--plvt-view-transition-animation-wipe-progress:1}}::view-transition-new(*),::view-transition-old(*){backface-visibility:hidden;mix-blend-mode:normal}::view-transition-old(root){animation:none var(--plvt-view-transition-animation-duration) cubic-bezier(.45,0,.35,1);animation-delay:0s;animation-fill-mode:both;opacity:1;transform:none}::view-transition-new(root){animation:plvt-view-transition-animation-wipe-new var(--plvt-view-transition-animation-duration) cubic-bezier(.45,0,.35,1);animation-fill-mode:both;-webkit-mask-image:linear-gradient(var(--plvt-view-transition-animation-wipe-angle),#000 calc(-70% + 170%*var(--plvt-view-transition-animation-wipe-progress, 0)),#0000 calc(170%*var(--plvt-view-transition-animation-wipe-progress, 0)));mask-image:linear-gradient(var(--plvt-view-transition-animation-wipe-angle),#000 calc(-70% + 170%*var(--plvt-view-transition-animation-wipe-progress, 0)),#0000 calc(170%*var(--plvt-view-transition-animation-wipe-progress, 0)));opacity:1;transform:none}
\ No newline at end of file
Index: includes/admin.php
===================================================================
--- includes/admin.php	(revision 3470885)
+++ includes/admin.php	(working copy)
@@ -23,6 +23,11 @@
  * @since 1.1.0
  */
 function plvt_print_view_transitions_admin_style(): void {
+	// Short circuit if the feature is already present in core. See <https://core.trac.wordpress.org/ticket/64470>.
+	if ( function_exists( 'wp_enqueue_view_transitions_admin_css' ) ) {
+		return;
+	}
+
 	$options = plvt_get_stored_setting_value();
 	if ( ! isset( $options['enable_admin_transitions'] ) || true !== $options['enable_admin_transitions'] ) {
 		return;
Index: includes/settings.php
===================================================================
--- includes/settings.php	(revision 3470885)
+++ includes/settings.php	(working copy)
@@ -296,22 +296,25 @@
 		)
 	);
 
-	add_settings_section(
-		'plvt_admin_view_transitions',
-		_x( 'Admin View Transitions', 'Settings section', 'view-transitions' ),
-		static function (): void {
-			?>
-			<p class="description">
-				<?php esc_html_e( 'This section allows you to control view transitions usage in the WordPress admin area.', 'view-transitions' ); ?>
-			</p>
-			<?php
-		},
-		'reading',
-		array(
-			'before_section' => '<div id="admin-view-transitions">',
-			'after_section'  => '</div>',
-		)
-	);
+	// Only show the setting if the feature is not already present in core. See <https://core.trac.wordpress.org/ticket/64470>.
+	if ( ! function_exists( 'wp_enqueue_view_transitions_admin_css' ) ) {
+		add_settings_section(
+			'plvt_admin_view_transitions',
+			_x( 'Admin View Transitions', 'Settings section', 'view-transitions' ),
+			static function (): void {
+				?>
+				<p class="description">
+					<?php esc_html_e( 'This section allows you to control view transitions usage in the WordPress admin area.', 'view-transitions' ); ?>
+				</p>
+				<?php
+			},
+			'reading',
+			array(
+				'before_section' => '<div id="admin-view-transitions">',
+				'after_section'  => '</div>',
+			)
+		);
+	}
 
 	$fields = array(
 		'override_theme_config'                 => array(
Index: readme.txt
===================================================================
--- readme.txt	(revision 3470885)
+++ readme.txt	(working copy)
@@ -1,8 +1,8 @@
 === View Transitions ===
 
 Contributors: wordpressdotorg
-Tested up to: 6.9
-Stable tag:   1.1.2
+Tested up to: 7.0
+Stable tag:   1.2.0
 License:      GPLv2 or later
 License URI:  https://www.gnu.org/licenses/gpl-2.0.html
 Tags:         performance, view transitions, smooth transitions, animations
@@ -56,6 +56,12 @@
 
 == Changelog ==
 
+= 1.2.0 =
+
+**Enhancements**
+
+* Omit admin View Transitions functionality when present in core. ([2344](https://github.com/WordPress/performance/pull/2344))
+
 = 1.1.2 =
 
 **Bug Fixes**

web-worker-offloading

Important

Stable tag change: 0.2.0 → 0.2.1

svn status:

M       helper.php
M       hooks.php
M       load.php
M       readme.txt
M       third-party/google-site-kit.php
M       third-party/seo-by-rank-math.php
M       third-party/woocommerce.php
M       third-party.php
svn diff
Index: helper.php
===================================================================
--- helper.php	(revision 3470885)
+++ helper.php	(working copy)
@@ -6,9 +6,11 @@
  * @package web-worker-offloading
  */
 
+// @codeCoverageIgnoreStart
 if ( ! defined( 'ABSPATH' ) ) {
 	exit; // Exit if accessed directly.
 }
+// @codeCoverageIgnoreEnd
 
 /**
  * Gets configuration for Web Worker Offloading.
@@ -23,11 +25,11 @@
 	$config = array(
 		// The source code in the build directory is compiled from <https://github.com/BuilderIO/partytown/tree/main/src/lib>.
 		// See webpack config in the WordPress/performance repo: <https://github.com/WordPress/performance/blob/282a068f3eb2575d37aeb9034e894e7140fcddca/webpack.config.js#L84-L130>.
-		'lib' => wp_parse_url( plugin_dir_url( __FILE__ ), PHP_URL_PATH ) . 'build/',
+		'lib' => wp_parse_url( plugins_url( 'build/', __FILE__ ), PHP_URL_PATH ),
 	);
 
 	if ( WP_DEBUG && SCRIPT_DEBUG ) {
-		$config['debug'] = true;
+		$config['debug'] = true;// @codeCoverageIgnore
 	}
 
 	/**
@@ -70,3 +72,159 @@
 	 */
 	return (array) apply_filters( 'plwwo_configuration', $config );
 }
+
+/**
+ * Registers defaults scripts for Web Worker Offloading.
+ *
+ * @since 0.1.0
+ * @access private
+ *
+ * @param WP_Scripts $scripts WP_Scripts instance.
+ */
+function plwwo_register_default_scripts( WP_Scripts $scripts ): void {
+	// The source code for partytown.js is built from <https://github.com/BuilderIO/partytown/blob/b292a14047a0c12ca05ba97df1833935d42fdb66/src/lib/main/snippet.ts>.
+	// See webpack config in the WordPress/performance repo: <https://github.com/WordPress/performance/blob/282a068f3eb2575d37aeb9034e894e7140fcddca/webpack.config.js#L84-L130>.
+	if ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) {
+		$partytown_js_path = '/build/debug/partytown.js';// @codeCoverageIgnore
+	} else {
+		$partytown_js_path = '/build/partytown.js';
+	}
+
+	$partytown_js = file_get_contents( __DIR__ . $partytown_js_path ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- It's a local filesystem path not a remote request.
+	if ( false === $partytown_js ) {
+		return;// @codeCoverageIgnore
+	}
+
+	$scripts->add(
+		'web-worker-offloading',
+		'',
+		array(),
+		WEB_WORKER_OFFLOADING_VERSION,
+		array( 'in_footer' => false )
+	);
+
+	$scripts->add_inline_script(
+		'web-worker-offloading',
+		sprintf(
+			'window.partytown = {...(window.partytown || {}), ...%s};',
+			wp_json_encode( plwwo_get_configuration(), JSON_HEX_TAG | JSON_UNESCAPED_SLASHES )
+		),
+		'before'
+	);
+
+	$scripts->add_inline_script( 'web-worker-offloading', $partytown_js );
+}
+
+/**
+ * Prepends web-worker-offloading to the list of scripts to print if one of the queued scripts is offloaded to a worker.
+ *
+ * @since 0.1.0
+ * @access private
+ *
+ * @param string[]|mixed $script_handles An array of enqueued script dependency handles.
+ * @return string[] Script handles.
+ */
+function plwwo_filter_print_scripts_array( $script_handles ): array {
+	$scripts = wp_scripts();
+	foreach ( (array) $script_handles as $handle ) {
+		if ( true === (bool) $scripts->get_data( $handle, 'worker' ) ) {
+			$scripts->set_group( 'web-worker-offloading', false, 0 ); // Try to print in the head.
+			array_unshift( $script_handles, 'web-worker-offloading' );
+			break;
+		}
+	}
+	return $script_handles;
+}
+
+/**
+ * Updates script type for handles having `web-worker-offloading` as dependency.
+ *
+ * @since 0.1.0
+ * @access private
+ *
+ * @param string|mixed $tag    Script tag.
+ * @param string       $handle Script handle.
+ * @return string|mixed Script tag with type="text/partytown" for eligible scripts.
+ */
+function plwwo_update_script_type( $tag, string $handle ) {
+	if (
+		is_string( $tag )
+		&&
+		(bool) wp_scripts()->get_data( $handle, 'worker' )
+	) {
+		$html_processor = new WP_HTML_Tag_Processor( $tag );
+		while ( $html_processor->next_tag( array( 'tag_name' => 'SCRIPT' ) ) ) {
+			if ( $html_processor->get_attribute( 'id' ) === "{$handle}-js" ) {
+				$html_processor->set_attribute( 'type', 'text/partytown' );
+				$tag = $html_processor->get_updated_html();
+				break;
+			}
+		}
+	}
+	return $tag;
+}
+
+/**
+ * Filters inline script attributes to offload to a worker if the script has been opted-in.
+ *
+ * @since 0.1.0
+ * @access private
+ *
+ * @param array<string, mixed>|mixed $attributes Attributes.
+ * @return array<string, mixed> Attributes.
+ */
+function plwwo_filter_inline_script_attributes( $attributes ): array {
+	$attributes = (array) $attributes;
+	if (
+		isset( $attributes['id'] )
+		&&
+		1 === preg_match( '/^(?P<handle>.+)-js-(?:before|after)$/', $attributes['id'], $matches )
+		&&
+		(bool) wp_scripts()->get_data( $matches['handle'], 'worker' )
+	) {
+		$attributes['type'] = 'text/partytown';
+	}
+	return $attributes;
+}
+
+/**
+ * Displays the HTML generator meta tag for the Web Worker Offloading plugin.
+ *
+ * See {@see 'wp_head'}.
+ *
+ * @since 0.1.1
+ */
+function plwwo_render_generator_meta_tag(): void {
+	// Use the plugin slug as it is immutable.
+	echo '<meta name="generator" content="web-worker-offloading ' . esc_attr( WEB_WORKER_OFFLOADING_VERSION ) . '">' . "\n";
+}
+
+/**
+ * Displays a sunset warning notice for the plugin in the plugin row meta.
+ *
+ * @since 0.2.0
+ * @access private
+ *
+ * @param string $plugin_file Path to the plugin file relative to the plugins directory.
+ */
+function plwwo_render_sunset_notice( string $plugin_file ): void {
+	if ( 'web-worker-offloading/load.php' !== $plugin_file ) {
+		return;
+	}
+
+	$message = sprintf(
+		/* translators: 1: GitHub issue URL. 2: Support forum URL. */
+		__( 'The Web Worker Offloading plugin is proposed for being sunset. Please refer to the <a href="%1$s" target="_blank" rel="noopener">GitHub issue</a> for more information. If you have metrics showing how this plugin specifically improved your Interaction to Next Paint (INP), please share them in the <a href="%2$s" target="_blank" rel="noopener">support forum</a> as this could provide a reason to keep the plugin.', 'web-worker-offloading' ),
+		esc_url( 'https://github.com/WordPress/performance/issues/2284' ),
+		esc_url( 'https://wordpress.org/support/plugin/web-worker-offloading/' )
+	);
+	?>
+	<div class="notice inline notice-warning notice-alt">
+		<p>
+			<?php
+			echo wp_kses_post( $message );
+			?>
+		</p>
+	</div>
+	<?php
+}
Index: hooks.php
===================================================================
--- hooks.php	(revision 3470885)
+++ hooks.php	(working copy)
@@ -6,137 +6,14 @@
  * @package web-worker-offloading
  */
 
+// @codeCoverageIgnoreStart
 if ( ! defined( 'ABSPATH' ) ) {
 	exit; // Exit if accessed directly.
 }
-
-/**
- * Registers defaults scripts for Web Worker Offloading.
- *
- * @since 0.1.0
- * @access private
- *
- * @param WP_Scripts $scripts WP_Scripts instance.
- */
-function plwwo_register_default_scripts( WP_Scripts $scripts ): void {
-	// The source code for partytown.js is built from <https://github.com/BuilderIO/partytown/blob/b292a14047a0c12ca05ba97df1833935d42fdb66/src/lib/main/snippet.ts>.
-	// See webpack config in the WordPress/performance repo: <https://github.com/WordPress/performance/blob/282a068f3eb2575d37aeb9034e894e7140fcddca/webpack.config.js#L84-L130>.
-	if ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) {
-		$partytown_js_path = '/build/debug/partytown.js';
-	} else {
-		$partytown_js_path = '/build/partytown.js';
-	}
-
-	$partytown_js = file_get_contents( __DIR__ . $partytown_js_path ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- It's a local filesystem path not a remote request.
-	if ( false === $partytown_js ) {
-		return;
-	}
-
-	$scripts->add(
-		'web-worker-offloading',
-		'',
-		array(),
-		WEB_WORKER_OFFLOADING_VERSION,
-		array( 'in_footer' => false )
-	);
-
-	$scripts->add_inline_script(
-		'web-worker-offloading',
-		sprintf(
-			'window.partytown = {...(window.partytown || {}), ...%s};',
-			wp_json_encode( plwwo_get_configuration() )
-		),
-		'before'
-	);
-
-	$scripts->add_inline_script( 'web-worker-offloading', $partytown_js );
-}
 add_action( 'wp_default_scripts', 'plwwo_register_default_scripts' );
-
-/**
- * Prepends web-worker-offloading to the list of scripts to print if one of the queued scripts is offloaded to a worker.
- *
- * @since 0.1.0
- * @access private
- *
- * @param string[]|mixed $script_handles An array of enqueued script dependency handles.
- * @return string[] Script handles.
- */
-function plwwo_filter_print_scripts_array( $script_handles ): array {
-	$scripts = wp_scripts();
-	foreach ( (array) $script_handles as $handle ) {
-		if ( true === (bool) $scripts->get_data( $handle, 'worker' ) ) {
-			$scripts->set_group( 'web-worker-offloading', false, 0 ); // Try to print in the head.
-			array_unshift( $script_handles, 'web-worker-offloading' );
-			break;
-		}
-	}
-	return $script_handles;
-}
 add_filter( 'print_scripts_array', 'plwwo_filter_print_scripts_array', PHP_INT_MAX );
-
-/**
- * Updates script type for handles having `web-worker-offloading` as dependency.
- *
- * @since 0.1.0
- * @access private
- *
- * @param string|mixed $tag    Script tag.
- * @param string       $handle Script handle.
- * @return string|mixed Script tag with type="text/partytown" for eligible scripts.
- */
-function plwwo_update_script_type( $tag, string $handle ) {
-	if (
-		is_string( $tag )
-		&&
-		(bool) wp_scripts()->get_data( $handle, 'worker' )
-	) {
-		$html_processor = new WP_HTML_Tag_Processor( $tag );
-		while ( $html_processor->next_tag( array( 'tag_name' => 'SCRIPT' ) ) ) {
-			if ( $html_processor->get_attribute( 'id' ) === "{$handle}-js" ) {
-				$html_processor->set_attribute( 'type', 'text/partytown' );
-				$tag = $html_processor->get_updated_html();
-				break;
-			}
-		}
-	}
-	return $tag;
-}
 add_filter( 'script_loader_tag', 'plwwo_update_script_type', 10, 2 );
-
-/**
- * Filters inline script attributes to offload to a worker if the script has been opted-in.
- *
- * @since 0.1.0
- * @access private
- *
- * @param array<string, mixed>|mixed $attributes Attributes.
- * @return array<string, mixed> Attributes.
- */
-function plwwo_filter_inline_script_attributes( $attributes ): array {
-	$attributes = (array) $attributes;
-	if (
-		isset( $attributes['id'] )
-		&&
-		1 === preg_match( '/^(?P<handle>.+)-js-(?:before|after)$/', $attributes['id'], $matches )
-		&&
-		(bool) wp_scripts()->get_data( $matches['handle'], 'worker' )
-	) {
-		$attributes['type'] = 'text/partytown';
-	}
-	return $attributes;
-}
 add_filter( 'wp_inline_script_attributes', 'plwwo_filter_inline_script_attributes' );
-
-/**
- * Displays the HTML generator meta tag for the Web Worker Offloading plugin.
- *
- * See {@see 'wp_head'}.
- *
- * @since 0.1.1
- */
-function plwwo_render_generator_meta_tag(): void {
-	// Use the plugin slug as it is immutable.
-	echo '<meta name="generator" content="web-worker-offloading ' . esc_attr( WEB_WORKER_OFFLOADING_VERSION ) . '">' . "\n";
-}
 add_action( 'wp_head', 'plwwo_render_generator_meta_tag' );
+add_action( 'after_plugin_row_meta', 'plwwo_render_sunset_notice' );
+// @codeCoverageIgnoreEnd
Index: load.php
===================================================================
--- load.php	(revision 3470885)
+++ load.php	(working copy)
@@ -5,7 +5,7 @@
  * Description: Offloads select JavaScript execution to a Web Worker to reduce work on the main thread and improve the Interaction to Next Paint (INP) metric.
  * Requires at least: 6.6
  * Requires PHP: 7.2
- * Version: 0.2.0
+ * Version: 0.2.1
  * Author: WordPress Performance Team
  * Author URI: https://make.wordpress.org/performance/
  * License: GPLv2 or later
@@ -15,9 +15,9 @@
  * @package web-worker-offloading
  */
 
-// Exit if accessed directly.
+// @codeCoverageIgnoreStart
 if ( ! defined( 'ABSPATH' ) ) {
-	exit;
+	exit; // Exit if accessed directly.
 }
 
 // Define the constant.
@@ -43,8 +43,9 @@
 	);
 }
 
-define( 'WEB_WORKER_OFFLOADING_VERSION', '0.2.0' );
+define( 'WEB_WORKER_OFFLOADING_VERSION', '0.2.1' );
 
 require_once __DIR__ . '/helper.php';
 require_once __DIR__ . '/hooks.php';
 require_once __DIR__ . '/third-party.php';
+// @codeCoverageIgnoreEnd
Index: readme.txt
===================================================================
--- readme.txt	(revision 3470885)
+++ readme.txt	(working copy)
@@ -1,8 +1,8 @@
 === Web Worker Offloading ===
 
 Contributors: wordpressdotorg
-Tested up to: 6.9
-Stable tag:   0.2.0
+Tested up to: 7.0
+Stable tag:   0.2.1
 License:      GPLv2 or later
 License URI:  https://www.gnu.org/licenses/gpl-2.0.html
 Tags:         performance, JavaScript, web worker, partytown, analytics
@@ -13,7 +13,7 @@
 
 This plugin offloads JavaScript execution to a Web Worker, improving performance by freeing up the main thread. This should translate into improved [Interaction to Next Paint](https://web.dev/articles/inp) (INP) scores.
 
-⚠ _This functionality is experimental._ ⚠
+⚠ _This functionality is experimental, and **it is now [intended to be sunset](https://github.com/WordPress/performance/issues/2284)**._ ⚠
 
 In order to opt in a script to be loaded in a worker, simply add `worker` script data to a registered script. For example,
 if you have a script registered with the handle of `foo`, opt-in to offload it to a web worker by doing:
@@ -94,6 +94,10 @@
 
 == Changelog ==
 
+= 0.2.1 =
+
+* Intend to sunset. ([2404](https://github.com/WordPress/performance/pull/2404))
+
 = 0.2.0 =
 
 **Enhancements**
Index: third-party/google-site-kit.php
===================================================================
--- third-party/google-site-kit.php	(revision 3470885)
+++ third-party/google-site-kit.php	(working copy)
@@ -6,9 +6,11 @@
  * @package web-worker-offloading
  */
 
+// @codeCoverageIgnoreStart
 if ( ! defined( 'ABSPATH' ) ) {
 	exit; // Exit if accessed directly.
 }
+// @codeCoverageIgnoreEnd
 
 /**
  * Configures WWO for Site Kit and Google Analytics.
@@ -41,7 +43,7 @@
 
 	return $configuration;
 }
-add_filter( 'plwwo_configuration', 'plwwo_google_site_kit_configure' );
+add_filter( 'plwwo_configuration', 'plwwo_google_site_kit_configure' ); // @codeCoverageIgnore
 
 plwwo_mark_scripts_for_offloading(
 	array(
@@ -68,4 +70,4 @@
 	return $attributes;
 }
 
-add_filter( 'wp_inline_script_attributes', 'plwwo_google_site_kit_filter_inline_script_attributes' );
+add_filter( 'wp_inline_script_attributes', 'plwwo_google_site_kit_filter_inline_script_attributes' ); // @codeCoverageIgnore
Index: third-party/seo-by-rank-math.php
===================================================================
--- third-party/seo-by-rank-math.php	(revision 3470885)
+++ third-party/seo-by-rank-math.php	(working copy)
@@ -6,9 +6,11 @@
  * @package web-worker-offloading
  */
 
+// @codeCoverageIgnoreStart
 if ( ! defined( 'ABSPATH' ) ) {
 	exit; // Exit if accessed directly.
 }
+// @codeCoverageIgnoreEnd
 
 /**
  * Configures WWO for Rank Math SEO and Google Analytics.
@@ -30,7 +32,7 @@
 	$configuration['forward'][] = 'gtag';
 	return $configuration;
 }
-add_filter( 'plwwo_configuration', 'plwwo_rank_math_configure' );
+add_filter( 'plwwo_configuration', 'plwwo_rank_math_configure' ); // @codeCoverageIgnore
 
 /*
  * Note: The following integration is not targeting the \RankMath\Analytics\GTag::enqueue_gtag_js() code which is only
@@ -58,7 +60,7 @@
 	return $attributes;
 }
 
-add_filter( 'wp_script_attributes', 'plwwo_rank_math_filter_script_attributes' );
+add_filter( 'wp_script_attributes', 'plwwo_rank_math_filter_script_attributes' ); // @codeCoverageIgnore
 
 /**
  * Filters inline script attributes to offload Rank Math's GTag script tag to Partytown.
@@ -78,4 +80,4 @@
 	return $attributes;
 }
 
-add_filter( 'wp_inline_script_attributes', 'plwwo_rank_math_filter_inline_script_attributes' );
+add_filter( 'wp_inline_script_attributes', 'plwwo_rank_math_filter_inline_script_attributes' ); // @codeCoverageIgnore
Index: third-party/woocommerce.php
===================================================================
--- third-party/woocommerce.php	(revision 3470885)
+++ third-party/woocommerce.php	(working copy)
@@ -6,9 +6,11 @@
  * @package web-worker-offloading
  */
 
+// @codeCoverageIgnoreStart
 if ( ! defined( 'ABSPATH' ) ) {
 	exit; // Exit if accessed directly.
 }
+// @codeCoverageIgnoreEnd
 
 /**
  * Configures WWO for WooCommerce and Google Analytics.
@@ -31,7 +33,7 @@
 
 	return $configuration;
 }
-add_filter( 'plwwo_configuration', 'plwwo_woocommerce_configure' );
+add_filter( 'plwwo_configuration', 'plwwo_woocommerce_configure' ); // @codeCoverageIgnore
 
 plwwo_mark_scripts_for_offloading(
 	// Note: 'woocommerce-google-analytics-integration' is intentionally not included because for some reason events like add_to_cart don't get tracked.
Index: third-party.php
===================================================================
--- third-party.php	(revision 3470885)
+++ third-party.php	(working copy)
@@ -6,9 +6,11 @@
  * @package web-worker-offloading
  */
 
+// @codeCoverageIgnoreStart
 if ( ! defined( 'ABSPATH' ) ) {
 	exit; // Exit if accessed directly.
 }
+// @codeCoverageIgnoreEnd
 
 /**
  * Adds scripts to be offloaded to a worker.

webp-uploads

Warning

Stable tag is unchanged at 2.6.1, so no plugin release will occur.

svn status:

M       helper.php
svn diff
Index: helper.php
===================================================================
--- helper.php	(revision 3470885)
+++ helper.php	(working copy)
@@ -154,9 +154,9 @@
 		return $editor;
 	}
 
-	$height = isset( $size_data['height'] ) ? (int) $size_data['height'] : 0;
-	$width  = isset( $size_data['width'] ) ? (int) $size_data['width'] : 0;
-	$crop   = isset( $size_data['crop'] ) ? $size_data['crop'] : false;
+	$height = (int) ( $size_data['height'] ?? 0 );
+	$width  = (int) ( $size_data['width'] ?? 0 );
+	$crop   = $size_data['crop'] ?? false;
 	if ( $width <= 0 && $height <= 0 ) {
 		return new WP_Error( 'image_wrong_dimensions', __( 'At least one of the dimensions must be a positive number.', 'webp-uploads' ) );
 	}

@westonruter
Copy link
Copy Markdown
Member Author

westonruter commented Feb 27, 2026

@westonruter westonruter marked this pull request as ready for review February 27, 2026 07:25
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Feb 27, 2026

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: westonruter <westonruter@git.wordpress.org>
Co-authored-by: mukeshpanchal27 <mukesh27@git.wordpress.org>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

Comment thread plugins/web-worker-offloading/helper.php Outdated
Co-authored-by: Mukesh Panchal <mukeshpanchal27@users.noreply.github.com>
@codecov
Copy link
Copy Markdown

codecov Bot commented Feb 27, 2026

Codecov Report

❌ Patch coverage is 0% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 69.33%. Comparing base (ee918b1) to head (f015929).
⚠️ Report is 9 commits behind head on release/2026-02-27.

Files with missing lines Patch % Lines
plugins/embed-optimizer/load.php 0.00% 1 Missing ⚠️
plugins/optimization-detective/load.php 0.00% 1 Missing ⚠️
plugins/performance-lab/load.php 0.00% 1 Missing ⚠️
Additional details and impacted files
@@                 Coverage Diff                 @@
##           release/2026-02-27    #2405   +/-   ##
===================================================
  Coverage               69.33%   69.33%           
===================================================
  Files                      90       90           
  Lines                    7749     7749           
===================================================
  Hits                     5373     5373           
  Misses                   2376     2376           
Flag Coverage Δ
multisite 69.33% <0.00%> (ø)
single 35.73% <0.00%> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@westonruter westonruter merged commit 868417e into release/2026-02-27 Feb 27, 2026
30 checks passed
@westonruter westonruter deleted the publish/2026-02-27 branch February 27, 2026 19:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Infrastructure Issues for the overall performance plugin infrastructure no milestone PRs that do not have a defined milestone for release skip changelog PRs that should not be mentioned in changelogs [Type] Documentation Documentation to be added or enhanced

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants