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

Prepare 3.0.0 release #1125

Merged
merged 10 commits into from
Apr 15, 2024
Merged

Prepare 3.0.0 release #1125

merged 10 commits into from
Apr 15, 2024

Conversation

westonruter
Copy link
Member

@westonruter westonruter commented Apr 11, 2024

Previously: #992

  • Bump stable tag in readme.txt
  • Bump versions in load.php
  • Run npm run since -- -r 3.0.0
  • Update changelog

@westonruter westonruter added [Type] Documentation Documentation to be added or enhanced Infrastructure Issues for the overall performance plugin infrastructure skip changelog PRs that should not be mentioned in changelogs labels Apr 11, 2024
@westonruter westonruter added this to the performance-lab 3.0.0 milestone Apr 11, 2024
@westonruter westonruter marked this pull request as ready for review April 12, 2024 04:33
Copy link

github-actions bot commented Apr 12, 2024

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 <[email protected]>
Co-authored-by: swissspidy <[email protected]>
Co-authored-by: mukeshpanchal27 <[email protected]>
Co-authored-by: felixarntz <[email protected]>

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

readme.txt Outdated Show resolved Hide resolved
readme.txt Outdated Show resolved Hide resolved
@westonruter
Copy link
Member Author

Here's a diff of the standalone plugins comparing what is previously released on WordPress.org with what is pending as of this branch:

Diff old new
diff -ur diff-builds/old/auto-sizes/auto-sizes.php diff-builds/new/auto-sizes/auto-sizes.php
--- diff-builds/old/auto-sizes/auto-sizes.php	2024-04-12 11:57:58.201899301 -0700
+++ diff-builds/new/auto-sizes/auto-sizes.php	2024-04-12 11:57:58.204899301 -0700
@@ -1,11 +1,11 @@
 <?php
 /**
  * Plugin Name: Auto-sizes for Lazy-loaded Images
- * Plugin URI: https://github.com/WordPress/performance/tree/trunk/modules/images/auto-sizes
- * Description: This plugin implements the HTML spec for adding `sizes="auto"` to lazy-loaded images.
- * Requires at least: 6.3
+ * Plugin URI: https://github.com/WordPress/performance/tree/trunk/plugins/auto-sizes
+ * Description: Instructs browsers to automatically choose the right image size for lazy-loaded images.
+ * Requires at least: 6.4
  * Requires PHP: 7.0
- * Version: 1.0.0
+ * Version: 1.0.1
  * Author: WordPress Performance Team
  * Author URI: https://make.wordpress.org/performance/
  * License: GPLv2 or later
@@ -15,8 +15,9 @@
  * @package auto-sizes
  */
 
+// Exit if accessed directly.
 if ( ! defined( 'ABSPATH' ) ) {
-	exit; // Exit if accessed directly.
+	exit;
 }
 
 // Define the constant.
@@ -24,6 +25,6 @@
 	return;
 }
 
-define( 'IMAGE_AUTO_SIZES_VERSION', '1.0.0' );
+define( 'IMAGE_AUTO_SIZES_VERSION', '1.0.1' );
 
 require_once __DIR__ . '/hooks.php';
diff -ur diff-builds/old/auto-sizes/hooks.php diff-builds/new/auto-sizes/hooks.php
--- diff-builds/old/auto-sizes/hooks.php	2024-04-12 11:57:58.201899301 -0700
+++ diff-builds/new/auto-sizes/hooks.php	2024-04-12 11:57:58.204899301 -0700
@@ -3,7 +3,7 @@
  * Hook callbacks used for Auto-sizes for Lazy-loaded Images.
  *
  * @package auto-sizes
- * @since n.e.x.t
+ * @since 1.0.0
  */
 
 if ( ! defined( 'ABSPATH' ) ) {
@@ -13,7 +13,7 @@
 /**
  * Adds auto to the sizes attribute to the image, if applicable.
  *
- * @since n.e.x.t
+ * @since 1.0.0
  *
  * @param array $attr Attributes for the image markup.
  * @return array The filtered attributes for the image markup.
@@ -43,7 +43,7 @@
 /**
  * Adds auto to the sizes attribute to the image, if applicable.
  *
- * @since n.e.x.t
+ * @since 1.0.0
  *
  * @param string $html The HTML image tag markup being filtered.
  * @return string The filtered HTML image tag markup.
@@ -69,3 +69,16 @@
 	return $html;
 }
 add_filter( 'wp_content_img_tag', 'auto_sizes_update_content_img_tag' );
+
+/**
+ * Displays the HTML generator tag for the plugin.
+ *
+ * See {@see 'wp_head'}.
+ *
+ * @since 1.0.1
+ */
+function auto_sizes_render_generator() {
+	// Use the plugin slug as it is immutable.
+	echo '<meta name="generator" content="auto-sizes ' . esc_attr( IMAGE_AUTO_SIZES_VERSION ) . '">' . "\n";
+}
+add_action( 'wp_head', 'auto_sizes_render_generator' );
diff -ur diff-builds/old/auto-sizes/readme.txt diff-builds/new/auto-sizes/readme.txt
--- diff-builds/old/auto-sizes/readme.txt	2024-04-12 11:57:58.201899301 -0700
+++ diff-builds/new/auto-sizes/readme.txt	2024-04-12 11:57:58.204899301 -0700
@@ -2,14 +2,14 @@
 
 Contributors:      wordpressdotorg
 Requires at least: 6.4
-Tested up to:      6.4
+Tested up to:      6.5
 Requires PHP:      7.0
-Stable tag:        1.0.0
+Stable tag:        1.0.1
 License:           GPLv2 or later
 License URI:       https://www.gnu.org/licenses/gpl-2.0.html
 Tags:              performance, images, auto-sizes
 
-Adds support for automatically calculating the sizes attribute for lazy-loaded images.
+Instructs browsers to automatically choose the right image size for lazy-loaded images.
 
 == Description ==
 
@@ -48,6 +48,12 @@
 
 == Changelog ==
 
+= 1.0.1 =
+
+* Add auto-sizes generator tag. ([1105](https://github.com/WordPress/performance/pull/1105))
+* Bump minimum required WP version to 6.4. ([1062](https://github.com/WordPress/performance/pull/1062))
+* Update tested WordPress version to 6.5. ([1027](https://github.com/WordPress/performance/pull/1027))
+
 = 1.0.0 =
 
 * Initial release of the Auto-sizes for Lazy-loaded Images plugin as a standalone plugin. ([904](https://github.com/WordPress/performance/pull/904))
diff -ur diff-builds/old/dominant-color-images/class-dominant-color-image-editor-gd.php diff-builds/new/dominant-color-images/class-dominant-color-image-editor-gd.php
--- diff-builds/old/dominant-color-images/class-dominant-color-image-editor-gd.php	2024-04-12 11:57:58.201899301 -0700
+++ diff-builds/new/dominant-color-images/class-dominant-color-image-editor-gd.php	2024-04-12 11:57:58.204899301 -0700
@@ -4,16 +4,15 @@
  * with dominant color detection
  *
  * @package dominant-color-images
- * @group dominant-color-images
  *
- * @since 1.2.0
+ * @since 1.0.0
  */
 
 /**
  * WordPress Image Editor Class for Image Manipulation through GD
  * with dominant color detection.
  *
- * @since 1.2.0
+ * @since 1.0.0
  *
  * @see WP_Image_Editor
  */
@@ -22,7 +21,7 @@
 	/**
 	 * Get dominant color from a file.
 	 *
-	 * @since 1.2.0
+	 * @since 1.0.0
 	 *
 	 * @return string|WP_Error Dominant hex color string, or an error on failure.
 	 */
@@ -52,7 +51,7 @@
 	 * Looks for transparent pixels in the image.
 	 * If there are none, it returns false.
 	 *
-	 * @since 1.2.0
+	 * @since 1.0.0
 	 *
 	 * @return bool|WP_Error True or false based on whether there are transparent pixels, or an error on failure.
 	 */
diff -ur diff-builds/old/dominant-color-images/class-dominant-color-image-editor-imagick.php diff-builds/new/dominant-color-images/class-dominant-color-image-editor-imagick.php
--- diff-builds/old/dominant-color-images/class-dominant-color-image-editor-imagick.php	2024-04-12 11:57:58.201899301 -0700
+++ diff-builds/new/dominant-color-images/class-dominant-color-image-editor-imagick.php	2024-04-12 11:57:58.204899301 -0700
@@ -4,16 +4,15 @@
  * with dominant color detection
  *
  * @package dominant-color-images
- * @group dominant-color-images
  *
- * @since 1.2.0
+ * @since 1.0.0
  */
 
 /**
  * WordPress Image Editor Class for Image Manipulation through Imagick
  * with dominant color detection.
  *
- * @since 1.2.0
+ * @since 1.0.0
  *
  * @see WP_Image_Editor
  */
@@ -22,7 +21,7 @@
 	/**
 	 * Get dominant color from a file.
 	 *
-	 * @since 1.2.0
+	 * @since 1.0.0
 	 *
 	 * @return string|WP_Error Dominant hex color string, or an error on failure.
 	 */
@@ -54,7 +53,7 @@
 	 * Looks for transparent pixels in the image.
 	 * If there are none, it returns false.
 	 *
-	 * @since 1.2.0
+	 * @since 1.0.0
 	 *
 	 * @return bool|WP_Error True or false based on whether there are transparent pixels, or an error on failure.
 	 */
Only in diff-builds/old/dominant-color-images: .gitattributes
diff -ur diff-builds/old/dominant-color-images/helper.php diff-builds/new/dominant-color-images/helper.php
--- diff-builds/old/dominant-color-images/helper.php	2024-04-12 11:57:58.201899301 -0700
+++ diff-builds/new/dominant-color-images/helper.php	2024-04-12 11:57:58.204899301 -0700
@@ -1,19 +1,16 @@
 <?php
 /**
- * Helper functions used for Dominant Color Images.
+ * Helper functions used for Image Placeholders.
  *
  * @package dominant-color-images
- * @since 2.1.0
+ *
+ * @since 1.0.0
  */
 
-if ( ! defined( 'ABSPATH' ) ) {
-	exit; // Exit if accessed directly.
-}
-
 /**
  * Overloads wp_image_editors() to load the extended classes.
  *
- * @since 1.2.0
+ * @since 1.0.0
  *
  * @param string[] $editors Array of available image editor class names. Defaults are 'WP_Image_Editor_Imagick', 'WP_Image_Editor_GD'.
  * @return string[] Registered image editors class names.
@@ -44,8 +41,8 @@
 /**
  * Computes the dominant color of the given attachment image and whether it has transparency.
  *
- * @since 1.2.0
- * @since 2.6.0 Function renamed to remove the `_` prefix.
+ * @since 1.0.0
+ *
  * @access private
  *
  * @param int $attachment_id The attachment ID.
@@ -94,8 +91,7 @@
 /**
  * Gets file path of image based on size.
  *
- * @since 1.2.0
- * @since 2.6.0 Function renamed to change `wp_` prefix to `dominant_color_`.
+ * @since 1.0.0
  *
  * @param int    $attachment_id Attachment ID for image.
  * @param string $size          Optional. Image size. Default 'medium'.
@@ -121,7 +117,7 @@
 /**
  * Gets the dominant color for an image attachment.
  *
- * @since 1.3.0
+ * @since 1.0.0
  *
  * @param int $attachment_id Attachment ID for image.
  * @return string|null Hex value of dominant color or null if not set.
@@ -145,7 +141,7 @@
 /**
  * Returns whether an image attachment has transparency.
  *
- * @since 1.3.0
+ * @since 1.0.0
  *
  * @param int $attachment_id Attachment ID for image.
  * @return bool|null Whether the image has transparency, or null if not set.
@@ -167,7 +163,7 @@
 /**
  * Gets hex color from RGB.
  *
- * @since 1.3.0
+ * @since 1.0.0
  *
  * @param int $red Red 0-255.
  * @param int $green Green 0-255.
diff -ur diff-builds/old/dominant-color-images/hooks.php diff-builds/new/dominant-color-images/hooks.php
--- diff-builds/old/dominant-color-images/hooks.php	2024-04-12 11:57:58.201899301 -0700
+++ diff-builds/new/dominant-color-images/hooks.php	2024-04-12 11:57:58.204899301 -0700
@@ -1,9 +1,10 @@
 <?php
 /**
- * Hook callbacks used for Dominant Color Images.
+ * Hook callbacks used for Image Placeholders.
  *
  * @package dominant-color-images
- * @since 2.1.0
+ *
+ * @since 1.0.0
  */
 
 if ( ! defined( 'ABSPATH' ) ) {
@@ -13,7 +14,7 @@
 /**
  * Add the dominant color metadata to the attachment.
  *
- * @since 1.2.0
+ * @since 1.0.0
  *
  * @param array $metadata      The attachment metadata.
  * @param int   $attachment_id The attachment ID.
@@ -38,7 +39,7 @@
 /**
  * Filters various image attributes to add the dominant color to the image.
  *
- * @since 1.2.0
+ * @since 1.0.0
  *
  * @param array  $attr       Attributes for the image markup.
  * @param object $attachment Image attachment post.
@@ -74,7 +75,7 @@
 /**
  * Filter image tags in content to add the dominant color to the image.
  *
- * @since 1.2.0
+ * @since 1.0.0
  *
  * @param string $filtered_image The filtered image.
  * @param string $context        The context of the image.
@@ -109,7 +110,7 @@
 	 *
 	 * You can set this to false in order disable adding the dominant color to the image.
 	 *
-	 * @since 1.2.0
+	 * @since 1.0.0
 	 *
 	 * @param bool   $add_dominant_color Whether to add the dominant color to the image. default true.
 	 * @param int    $attachment_id      The image attachment ID.
@@ -156,7 +157,7 @@
 /**
  * Add CSS needed for to show the dominant color as an image background.
  *
- * @since 1.2.0
+ * @since 1.0.0
  */
 function dominant_color_add_inline_style() {
 	$handle = 'dominant-color-styles';
@@ -170,18 +171,14 @@
 add_filter( 'wp_enqueue_scripts', 'dominant_color_add_inline_style' );
 
 /**
- * Displays the HTML generator tag for the Dominant Color Images plugin.
+ * Displays the HTML generator tag for the Image Placeholders plugin.
  *
  * See {@see 'wp_head'}.
  *
- * @since 2.3.0
+ * @since 1.0.0
  */
 function dominant_color_render_generator() {
-	if (
-		defined( 'DOMINANT_COLOR_IMAGES_VERSION' ) &&
-		! str_starts_with( DOMINANT_COLOR_IMAGES_VERSION, 'Performance Lab ' )
-	) {
-		echo '<meta name="generator" content="Dominant Color Images ' . esc_attr( DOMINANT_COLOR_IMAGES_VERSION ) . '">' . "\n";
-	}
+	// Use the plugin slug as it is immutable.
+	echo '<meta name="generator" content="dominant-color-images ' . esc_attr( DOMINANT_COLOR_IMAGES_VERSION ) . '">' . "\n";
 }
 add_action( 'wp_head', 'dominant_color_render_generator' );
diff -ur diff-builds/old/dominant-color-images/load.php diff-builds/new/dominant-color-images/load.php
--- diff-builds/old/dominant-color-images/load.php	2024-04-12 11:57:58.201899301 -0700
+++ diff-builds/new/dominant-color-images/load.php	2024-04-12 11:57:58.204899301 -0700
@@ -1,11 +1,11 @@
 <?php
 /**
- * Plugin Name: Dominant Color Images
- * Plugin URI: https://github.com/WordPress/performance/tree/trunk/modules/images/dominant-color-images
- * Description: Adds support to store the dominant color of newly uploaded images and create a placeholder background of that color.
- * Requires at least: 6.3
+ * Plugin Name: Image Placeholders
+ * Plugin URI: https://github.com/WordPress/performance/tree/trunk/plugins/dominant-color-images
+ * Description: Displays placeholders based on an image's dominant color while the image is loading.
+ * Requires at least: 6.4
  * Requires PHP: 7.0
- * Version: 1.0.1
+ * Version: 1.1.0
  * Author: WordPress Performance Team
  * Author URI: https://make.wordpress.org/performance/
  * License: GPLv2 or later
@@ -15,17 +15,17 @@
  * @package dominant-color-images
  */
 
-// Define the constant.
-if ( defined( 'DOMINANT_COLOR_IMAGES_VERSION' ) ) {
-	return;
+// Exit if accessed directly.
+if ( ! defined( 'ABSPATH' ) ) {
+	exit;
 }
 
-define( 'DOMINANT_COLOR_IMAGES_VERSION', '1.0.1' );
-
-// Do not load the code if it is already loaded through another means.
-if ( function_exists( 'dominant_color_metadata' ) ) {
+// Define required constants.
+if ( defined( 'DOMINANT_COLOR_IMAGES_VERSION' ) ) {
 	return;
 }
 
+define( 'DOMINANT_COLOR_IMAGES_VERSION', '1.1.0' );
+
 require_once __DIR__ . '/helper.php';
 require_once __DIR__ . '/hooks.php';
diff -ur diff-builds/old/dominant-color-images/readme.txt diff-builds/new/dominant-color-images/readme.txt
--- diff-builds/old/dominant-color-images/readme.txt	2024-04-12 11:57:58.201899301 -0700
+++ diff-builds/new/dominant-color-images/readme.txt	2024-04-12 11:57:58.204899301 -0700
@@ -1,33 +1,35 @@
-=== Dominant Color Images ===
+=== Image Placeholders ===
 
 Contributors:      wordpressdotorg
-Requires at least: 6.3
-Tested up to:      6.3
+Requires at least: 6.4
+Tested up to:      6.5
 Requires PHP:      7.0
-Stable tag:        1.0.1
+Stable tag:        1.1.0
 License:           GPLv2 or later
 License URI:       https://www.gnu.org/licenses/gpl-2.0.html
 Tags:              performance, images, dominant color
 
-Adds support to store the dominant color of newly uploaded images and create a placeholder background of that color.
+Displays placeholders based on an image's dominant color while the image is loading.
 
 == Description ==
 
 This plugin determines and stores the dominant color for newly uploaded images in the media library within WordPress and then uses it to create a placeholder background of that color in the frontend, visible until the image is loaded.
 
+_This plugin was formerly known as Dominant Color Images._
+
 == Installation ==
 
 = Installation from within WordPress =
 
 1. Visit **Plugins > Add New**.
-2. Search for **Dominant Color Images**.
-3. Install and activate the **Dominant Color Images** plugin.
+2. Search for **Image Placeholders**.
+3. Install and activate the **Image Placeholders** plugin.
 
 = Manual installation =
 
 1. Upload the entire `dominant-color-images` folder to the `/wp-content/plugins/` directory.
 2. Visit **Plugins**.
-3. Activate the **Dominant Color Images** plugin.
+3. Activate the **Image Placeholders** plugin.
 
 == Frequently Asked Questions ==
 
@@ -47,10 +49,17 @@
 
 == Changelog ==
 
+= 1.1.0 =
+
+* Rename plugin to "Image Placeholders". ([1101](https://github.com/WordPress/performance/pull/1101))
+* Use plugin slug for generator tag. ([1103](https://github.com/WordPress/performance/pull/1103))
+* Bump minimum required WP version to 6.4. ([1062](https://github.com/WordPress/performance/pull/1062))
+* Update tested WordPress version to 6.5. ([1027](https://github.com/WordPress/performance/pull/1027))
+
 = 1.0.1 =
 
 * Exclude ".wordpress-org" directory when deploying standalone plugins. ([866](https://github.com/WordPress/performance/pull/866))
 
 = 1.0.0 =
 
-* Initial release of the Dominant Color Images plugin as a standalone plugin. ([704](https://github.com/WordPress/performance/pull/704))
+* Initial release of the Image Placeholders plugin as a standalone plugin. ([704](https://github.com/WordPress/performance/pull/704))
Only in diff-builds/old/dominant-color-images: .wordpress-org
diff -ur diff-builds/old/embed-optimizer/hooks.php diff-builds/new/embed-optimizer/hooks.php
--- diff-builds/old/embed-optimizer/hooks.php	2024-04-12 11:57:58.201899301 -0700
+++ diff-builds/new/embed-optimizer/hooks.php	2024-04-12 11:57:58.204899301 -0700
@@ -22,7 +22,7 @@
  * @return string
  */
 function embed_optimizer_filter_oembed_html( string $html ): string {
-	$p = new WP_HTML_Tag_Processor( $html );
+	$html_processor = new WP_HTML_Tag_Processor( $html );
 
 	/**
 	 * Determine how to lazy load the embed.
@@ -37,22 +37,22 @@
 	$script_count      = 0;
 	$has_inline_script = false;
 	// Locate the iframes and scripts.
-	while ( $p->next_tag() ) {
-		if ( 'IFRAME' === $p->get_tag() ) {
-			$loading_value = $p->get_attribute( 'loading' );
+	while ( $html_processor->next_tag() ) {
+		if ( 'IFRAME' === $html_processor->get_tag() ) {
+			$loading_value = $html_processor->get_attribute( 'loading' );
 			if ( empty( $loading_value ) ) {
 				++$iframe_count;
-				if ( ! $p->set_bookmark( 'iframe' ) ) {
+				if ( ! $html_processor->set_bookmark( 'iframe' ) ) {
 					embed_optimizer_trigger_error( __FUNCTION__, esc_html__( 'Embed Optimizer unable to set iframe bookmark.', 'embed-optimizer' ) );
 					return $html;
 				}
 			}
-		} elseif ( 'SCRIPT' === $p->get_tag() ) {
-			if ( ! $p->get_attribute( 'src' ) ) {
+		} elseif ( 'SCRIPT' === $html_processor->get_tag() ) {
+			if ( ! $html_processor->get_attribute( 'src' ) ) {
 				$has_inline_script = true;
 			} else {
 				++$script_count;
-				if ( ! $p->set_bookmark( 'script' ) ) {
+				if ( ! $html_processor->set_bookmark( 'script' ) ) {
 					embed_optimizer_trigger_error( __FUNCTION__, esc_html__( 'Embed Optimizer unable to set script bookmark.', 'embed-optimizer' ) );
 					return $html;
 				}
@@ -60,26 +60,26 @@
 		}
 	}
 	// If there was only one non-inline script, make it lazy.
-	if ( 1 === $script_count && ! $has_inline_script && $p->has_bookmark( 'script' ) ) {
+	if ( 1 === $script_count && ! $has_inline_script && $html_processor->has_bookmark( 'script' ) ) {
 		add_action( 'wp_footer', 'embed_optimizer_lazy_load_scripts' );
-		if ( $p->seek( 'script' ) ) {
-			if ( $p->get_attribute( 'type' ) ) {
-				$p->set_attribute( 'data-original-type', $p->get_attribute( 'type' ) );
+		if ( $html_processor->seek( 'script' ) ) {
+			if ( $html_processor->get_attribute( 'type' ) ) {
+				$html_processor->set_attribute( 'data-original-type', $html_processor->get_attribute( 'type' ) );
 			}
-			$p->set_attribute( 'type', 'application/vnd.embed-optimizer.javascript' );
+			$html_processor->set_attribute( 'type', 'application/vnd.embed-optimizer.javascript' );
 		} else {
 			embed_optimizer_trigger_error( __FUNCTION__, esc_html__( 'Embed Optimizer unable to seek to script bookmark.', 'embed-optimizer' ) );
 		}
 	}
 	// If there was only one iframe, make it lazy.
-	if ( 1 === $iframe_count && $p->has_bookmark( 'iframe' ) ) {
-		if ( $p->seek( 'iframe' ) ) {
-			$p->set_attribute( 'loading', 'lazy' );
+	if ( 1 === $iframe_count && $html_processor->has_bookmark( 'iframe' ) ) {
+		if ( $html_processor->seek( 'iframe' ) ) {
+			$html_processor->set_attribute( 'loading', 'lazy' );
 		} else {
 			embed_optimizer_trigger_error( __FUNCTION__, esc_html__( 'Embed Optimizer unable to seek to iframe bookmark.', 'embed-optimizer' ) );
 		}
 	}
-	return $p->get_updated_html();
+	return $html_processor->get_updated_html();
 }
 add_filter( 'embed_oembed_html', 'embed_optimizer_filter_oembed_html' );
 
@@ -162,10 +162,7 @@
  * @since 0.1.0
  */
 function embed_optimizer_render_generator() {
-	if (
-		defined( 'EMBED_OPTIMIZER_VERSION' )
-	) {
-		echo '<meta name="generator" content="Embed Optimizer ' . esc_attr( EMBED_OPTIMIZER_VERSION ) . '">' . "\n";
-	}
+	// Use the plugin slug as it is immutable.
+	echo '<meta name="generator" content="embed-optimizer ' . esc_attr( EMBED_OPTIMIZER_VERSION ) . '">' . "\n";
 }
 add_action( 'wp_head', 'embed_optimizer_render_generator' );
diff -ur diff-builds/old/embed-optimizer/load.php diff-builds/new/embed-optimizer/load.php
--- diff-builds/old/embed-optimizer/load.php	2024-04-12 11:57:58.201899301 -0700
+++ diff-builds/new/embed-optimizer/load.php	2024-04-12 11:57:58.204899301 -0700
@@ -3,9 +3,9 @@
  * Plugin Name: Embed Optimizer
  * Plugin URI: https://github.com/WordPress/performance/tree/trunk/plugins/embed-optimizer
  * Description: Optimizes the performance of embeds by lazy-loading iframes and scripts.
- * Requires at least: 6.3
+ * Requires at least: 6.4
  * Requires PHP: 7.0
- * Version: 0.1.0
+ * Version: 0.1.1
  * Author: WordPress Performance Team
  * Author URI: https://make.wordpress.org/performance/
  * License: GPLv2 or later
@@ -20,7 +20,7 @@
 	exit;
 }
 
-define( 'EMBED_OPTIMIZER_VERSION', '0.1.0' );
+define( 'EMBED_OPTIMIZER_VERSION', '0.1.1' );
 
-// Load in the Embed Optimizer module hooks.
+// Load in the Embed Optimizer plugin hooks.
 require_once __DIR__ . '/hooks.php';
diff -ur diff-builds/old/embed-optimizer/readme.txt diff-builds/new/embed-optimizer/readme.txt
--- diff-builds/old/embed-optimizer/readme.txt	2024-04-12 11:57:58.201899301 -0700
+++ diff-builds/new/embed-optimizer/readme.txt	2024-04-12 11:57:58.204899301 -0700
@@ -1,10 +1,10 @@
 === Embed Optimizer ===
 
 Contributors:      wordpressdotorg
-Requires at least: 6.3
+Requires at least: 6.4
 Tested up to:      6.5
 Requires PHP:      7.0
-Stable tag:        0.1.0
+Stable tag:        0.1.1
 License:           GPLv2 or later
 License URI:       https://www.gnu.org/licenses/gpl-2.0.html
 Tags:              performance, embeds
@@ -49,6 +49,11 @@
 
 == Changelog ==
 
+= 0.1.1 =
+
+* Use plugin slug for generator tag. ([1103](https://github.com/WordPress/performance/pull/1103))
+* Bump minimum required WP version to 6.4. ([1076](https://github.com/WordPress/performance/pull/1076))
+
 = 0.1.0 =
 
 * Initial release.
Only in diff-builds/new/optimization-detective: build
diff -ur diff-builds/old/optimization-detective/class-od-html-tag-processor.php diff-builds/new/optimization-detective/class-od-html-tag-processor.php
--- diff-builds/old/optimization-detective/class-od-html-tag-processor.php	2024-04-12 11:57:58.201899301 -0700
+++ diff-builds/new/optimization-detective/class-od-html-tag-processor.php	2024-04-12 11:57:58.204899301 -0700
@@ -3,7 +3,7 @@
  * Optimization Detective: OD_HTML_Tag_Processor class
  *
  * @package optimization-detective
- * @since 0.1.0
+ * @since 0.1.1
  */
 
 // Exit if accessed directly.
@@ -12,376 +12,51 @@
 }
 
 /**
- * Processor leveraging WP_HTML_Tag_Processor which gathers breadcrumbs for computing XPaths while iterating the open_tags() generator.
+ * Extension to WP_HTML_Tag_Processor that supports injecting HTML.
  *
- * Eventually this class should be made largely obsolete once `WP_HTML_Processor` is fully implemented to support all HTML tags.
- *
- * @since 0.1.0
+ * @since 0.1.1
  * @access private
  */
-final class OD_HTML_Tag_Processor {
-
-	/**
-	 * HTML void tags (i.e. those which are self-closing).
-	 *
-	 * @link https://html.spec.whatwg.org/multipage/syntax.html#void-elements
-	 * @see WP_HTML_Processor::is_void()
-	 * @todo Reuse `WP_HTML_Processor::is_void()` once WordPress 6.4 is the minimum-supported version.
-	 *
-	 * @var string[]
-	 */
-	const VOID_TAGS = array(
-		'AREA',
-		'BASE',
-		'BASEFONT', // Obsolete.
-		'BGSOUND', // Obsolete.
-		'BR',
-		'COL',
-		'EMBED',
-		'FRAME', // Deprecated.
-		'HR',
-		'IMG',
-		'INPUT',
-		'KEYGEN', // Obsolete.
-		'LINK',
-		'META',
-		'PARAM', // Deprecated.
-		'SOURCE',
-		'TRACK',
-		'WBR',
-	);
-
-	/**
-	 * Raw text tags.
-	 *
-	 * These are treated like void tags for the purposes of walking over the document since we do not process any text
-	 * nodes. To cite the docblock for WP_HTML_Tag_Processor:
-	 *
-	 * > Some HTML elements are handled in a special way; their start and end tags
-	 * > act like a void tag. These are special because their contents can't contain
-	 * > HTML markup. Everything inside these elements is handled in a special way
-	 * > and content that _appears_ like HTML tags inside of them isn't. There can
-	 * > be no nesting in these elements.
-	 * >
-	 * > In the following list, "raw text" means that all of the content in the HTML
-	 * > until the matching closing tag is treated verbatim without any replacements
-	 * > and without any parsing.
-	 *
-	 * @link https://github.com/WordPress/wordpress-develop/blob/6dd00b1ffac54c20c1c1c7721aeebbcd82d0e378/src/wp-includes/html-api/class-wp-html-tag-processor.php#L136-L155
-	 * @link https://core.trac.wordpress.org/ticket/60392#comment:2
-	 *
-	 * @var string[]
-	 */
-	const RAW_TEXT_TAGS = array(
-		'SCRIPT',
-		'IFRAME',
-		'NOEMBED', // Deprecated.
-		'NOFRAMES', // Deprecated.
-		'STYLE',
-		'TEXTAREA',
-		'TITLE',
-		'XMP', // Deprecated.
-	);
-
-	/**
-	 * The set of HTML tags whose presence will implicitly close a <p> element.
-	 * For example '<p>foo<h1>bar</h1>' should parse the same as '<p>foo</p><h1>bar</h1>'.
-	 *
-	 * @link https://html.spec.whatwg.org/multipage/grouping-content.html#the-p-element
-	 *
-	 * @var string[]
-	 */
-	const P_CLOSING_TAGS = array(
-		'ADDRESS',
-		'ARTICLE',
-		'ASIDE',
-		'BLOCKQUOTE',
-		'DETAILS',
-		'DIV',
-		'DL',
-		'FIELDSET',
-		'FIGCAPTION',
-		'FIGURE',
-		'FOOTER',
-		'FORM',
-		'H1',
-		'H2',
-		'H3',
-		'H4',
-		'H5',
-		'H6',
-		'HEADER',
-		'HGROUP',
-		'HR',
-		'MAIN',
-		'MENU',
-		'NAV',
-		'OL',
-		'P',
-		'PRE',
-		'SEARCH',
-		'SECTION',
-		'TABLE',
-		'UL',
-	);
-
-	/**
-	 * Pattern for valid XPath subset for breadcrumb.
-	 *
-	 * @see self::get_xpath()
-	 * @var string
-	 */
-	const XPATH_PATTERN = '^(/\*\[\d+\]\[self::.+?\])+$';
-
-	/**
-	 * Open stack tags.
-	 *
-	 * @var string[]
-	 */
-	private $open_stack_tags = array();
+final class OD_HTML_Tag_Processor extends WP_HTML_Tag_Processor {
 
 	/**
-	 * Open stag indices.
+	 * Whether the old (pre-WP 6.5) signature for WP_HTML_Text_Replacement is needed.
 	 *
-	 * @var int[]
-	 */
-	private $open_stack_indices = array();
-
-	/**
-	 * Processor.
+	 * WordPress 6.5 changed the $end arg in the WP_HTML_Text_Replacement constructor to $length.
 	 *
-	 * @var WP_HTML_Tag_Processor
+	 * @var bool
 	 */
-	private $processor;
+	private $old_text_replacement_signature_needed;
 
 	/**
 	 * Constructor.
 	 *
 	 * @param string $html HTML to process.
 	 */
-	public function __construct( string $html ) {
-		$this->processor = new WP_HTML_Tag_Processor( $html );
+	public function __construct( $html ) {
+		$this->old_text_replacement_signature_needed = version_compare( get_bloginfo( 'version' ), '6.5', '<' );
+		parent::__construct( $html );
 	}
 
 	/**
-	 * Gets all open tags in the document.
-	 *
-	 * A generator is used so that when iterating at a specific tag, additional information about the tag at that point
-	 * can be queried from the class. Similarly, mutations may be performed when iterating at an open tag.
+	 * Appends HTML to the provided bookmark.
 	 *
-	 * @since 0.1.0
-	 *
-	 * @return Generator<string> Tag name of current open tag.
+	 * @param string $bookmark Bookmark.
+	 * @param string $html     HTML to inject.
+	 * @return bool Whether the HTML was appended.
 	 */
-	public function open_tags(): Generator {
-		$p = $this->processor;
-
-		/*
-		 * The keys for the following two arrays correspond to each other. Given the following document:
-		 *
-		 * <html>
-		 *   <head>
-		 *   </head>
-		 *   <body>
-		 *     <p>Hello!</p>
-		 *     <img src="lcp.png">
-		 *   </body>
-		 * </html>
-		 *
-		 * Upon processing the IMG element, the two arrays should be equal to the following:
-		 *
-		 * $open_stack_tags    = array( 'HTML', 'BODY', 'IMG' );
-		 * $open_stack_indices = array( 0, 1, 1 );
-		 */
-		$this->open_stack_tags    = array();
-		$this->open_stack_indices = array();
-		while ( $p->next_tag( array( 'tag_closers' => 'visit' ) ) ) {
-			$tag_name = $p->get_tag();
-			if ( ! $p->is_tag_closer() ) {
-
-				// Close an open P tag when a P-closing tag is encountered.
-				// TODO: There are quite a few more cases of optional closing tags: https://html.spec.whatwg.org/multipage/syntax.html#optional-tags
-				// Nevertheless, given WordPress's legacy of XHTML compatibility, the lack of closing tags may not be common enough to warrant worrying about any of them.
-				if ( in_array( $tag_name, self::P_CLOSING_TAGS, true ) ) {
-					$i = array_search( 'P', $this->open_stack_tags, true );
-					if ( false !== $i ) {
-						array_splice( $this->open_stack_tags, $i );
-						array_splice( $this->open_stack_indices, count( $this->open_stack_tags ) );
-					}
-				}
-
-				$level                   = count( $this->open_stack_tags );
-				$this->open_stack_tags[] = $tag_name;
-
-				if ( ! isset( $this->open_stack_indices[ $level ] ) ) {
-					$this->open_stack_indices[ $level ] = 0;
-				} else {
-					++$this->open_stack_indices[ $level ];
-				}
-
-				// Now that the breadcrumbs are constructed, yield the tag name so that they can be queried if desired.
-				// Other mutations may be performed to the open tag's attributes by the callee at this point as well.
-				yield $tag_name;
-
-				// Immediately pop off self-closing and raw text tags.
-				if (
-					in_array( $tag_name, self::VOID_TAGS, true )
-					||
-					in_array( $tag_name, self::RAW_TEXT_TAGS, true )
-					||
-					( $p->has_self_closing_flag() && $this->is_foreign_element() )
-				) {
-					array_pop( $this->open_stack_tags );
-				}
-			} else {
-				// If the closing tag is for self-closing or raw text tag, we ignore it since it was already handled above.
-				if (
-					in_array( $tag_name, self::VOID_TAGS, true )
-					||
-					in_array( $tag_name, self::RAW_TEXT_TAGS, true )
-				) {
-					continue;
-				}
-
-				$popped_tag_name = array_pop( $this->open_stack_tags );
-				if ( $popped_tag_name !== $tag_name ) {
-					$this->warn(
-						sprintf(
-							/* translators: 1: Popped tag name, 2: Closing tag name */
-							__( 'Expected popped tag stack element %1$s to match the currently visited closing tag %2$s.', 'optimization-detective' ),
-							$popped_tag_name,
-							$tag_name
-						)
-					);
-				}
-
-				array_splice( $this->open_stack_indices, count( $this->open_stack_tags ) + 1 );
-			}
+	public function append_html( string $bookmark, string $html ): bool {
+		if ( ! $this->has_bookmark( $bookmark ) ) {
+			return false;
 		}
-	}
 
-	/**
-	 * Warns of bad markup.
-	 *
-	 * @param string $message Warning message.
-	 */
-	private function warn( string $message ) {
-		wp_trigger_error(
-			__CLASS__ . '::open_tags',
-			esc_html( $message )
-		);
-	}
+		$start = $this->bookmarks[ $bookmark ]->start;
 
-	/**
-	 * Gets breadcrumbs for the current open tag.
-	 *
-	 * A breadcrumb consists of a tag name and its sibling index.
-	 *
-	 * @since 0.1.0
-	 *
-	 * @return Generator<array{string, int}> Breadcrumb.
-	 */
-	private function get_breadcrumbs(): Generator {
-		foreach ( $this->open_stack_tags as $i => $breadcrumb_tag_name ) {
-			yield array( $breadcrumb_tag_name, $this->open_stack_indices[ $i ] );
-		}
-	}
-
-	/**
-	 * Determines whether currently inside a foreign element (MATH or SVG).
-	 *
-	 * @since 0.1.0
-	 *
-	 * @return bool In foreign element.
-	 */
-	private function is_foreign_element(): bool {
-		foreach ( $this->open_stack_tags as $open_stack_tag ) {
-			if ( 'MATH' === $open_stack_tag || 'SVG' === $open_stack_tag ) {
-				return true;
-			}
-		}
-		return false;
-	}
-
-	/**
-	 * Gets XPath for the current open tag.
-	 *
-	 * It would be nicer if this were like `/html[1]/body[2]` but in XPath the position() here refers to the
-	 * index of the preceding node set. So it has to rather be written `/*[1][self::html]/*[2][self::body]`.
-	 *
-	 * @since 0.1.0
-	 *
-	 * @return string XPath.
-	 */
-	public function get_xpath(): string {
-		$xpath = '';
-		foreach ( $this->get_breadcrumbs() as list( $tag_name, $index ) ) {
-			$xpath .= sprintf( '/*[%d][self::%s]', $index, $tag_name );
-		}
-		return $xpath;
-	}
-
-	/**
-	 * Returns the value of a requested attribute from a matched tag opener if that attribute exists.
-	 *
-	 * This is a wrapper around the underlying HTML_Tag_Processor method of the same name since only a limited number of
-	 * methods can be exposed to prevent moving the pointer in such a way as the breadcrumb calculation is invalidated.
-	 *
-	 * @since 0.1.0
-	 * @see WP_HTML_Tag_Processor::get_attribute()
-	 *
-	 * @param string $name Name of attribute whose value is requested.
-	 * @return string|true|null Value of attribute or `null` if not available. Boolean attributes return `true`.
-	 */
-	public function get_attribute( string $name ) {
-		return $this->processor->get_attribute( $name );
-	}
-
-	/**
-	 * Updates or creates a new attribute on the currently matched tag with the passed value.
-	 *
-	 * This is a wrapper around the underlying HTML_Tag_Processor method of the same name since only a limited number of
-	 * methods can be exposed to prevent moving the pointer in such a way as the breadcrumb calculation is invalidated.
-	 *
-	 * @since 0.1.0
-	 * @see WP_HTML_Tag_Processor::set_attribute()
-	 *
-	 * @param string      $name  The attribute name to target.
-	 * @param string|bool $value The new attribute value.
-	 * @return bool Whether an attribute value was set.
-	 */
-	public function set_attribute( string $name, $value ): bool {
-		return $this->processor->set_attribute( $name, $value );
-	}
-
-	/**
-	 * Removes an attribute from the currently-matched tag.
-	 *
-	 * This is a wrapper around the underlying HTML_Tag_Processor method of the same name since only a limited number of
-	 * methods can be exposed to prevent moving the pointer in such a way as the breadcrumb calculation is invalidated.
-	 *
-	 * @since 0.1.0
-	 * @see WP_HTML_Tag_Processor::remove_attribute()
-	 *
-	 * @param string $name The attribute name to remove.
-	 * @return bool Whether an attribute was removed.
-	 */
-	public function remove_attribute( string $name ): bool {
-		return $this->processor->remove_attribute( $name );
-	}
-
-	/**
-	 * Returns the string representation of the HTML Tag Processor.
-	 *
-	 * This is a wrapper around the underlying HTML_Tag_Processor method of the same name since only a limited number of
-	 * methods can be exposed to prevent moving the pointer in such a way as the breadcrumb calculation is invalidated.
-	 *
-	 * @since 0.1.0
-	 * @see WP_HTML_Tag_Processor::get_updated_html()
-	 *
-	 * @return string The processed HTML.
-	 */
-	public function get_updated_html(): string {
-		return $this->processor->get_updated_html();
+		$this->lexical_updates[] = new WP_HTML_Text_Replacement(
+			$start,
+			$this->old_text_replacement_signature_needed ? $start : 0,
+			$html
+		);
+		return true;
 	}
 }
Only in diff-builds/new/optimization-detective: class-od-html-tag-walker.php
diff -ur diff-builds/old/optimization-detective/class-od-url-metric.php diff-builds/new/optimization-detective/class-od-url-metric.php
--- diff-builds/old/optimization-detective/class-od-url-metric.php	2024-04-12 11:57:58.201899301 -0700
+++ diff-builds/new/optimization-detective/class-od-url-metric.php	2024-04-12 11:57:58.204899301 -0700
@@ -134,7 +134,7 @@
 							'xpath'              => array(
 								'type'     => 'string',
 								'required' => true,
-								'pattern'  => OD_HTML_Tag_Processor::XPATH_PATTERN,
+								'pattern'  => OD_HTML_Tag_Walker::XPATH_PATTERN,
 							),
 							'intersectionRatio'  => array(
 								'type'     => 'number',
Only in diff-builds/old/optimization-detective: detection
diff -ur diff-builds/old/optimization-detective/detection.php diff-builds/new/optimization-detective/detection.php
--- diff-builds/old/optimization-detective/detection.php	2024-04-12 11:57:58.201899301 -0700
+++ diff-builds/new/optimization-detective/detection.php	2024-04-12 11:57:58.204899301 -0700
@@ -35,8 +35,8 @@
 	 */
 	$detection_time_window = apply_filters( 'od_detection_time_window', 5000 );
 
-	$web_vitals_lib_data = require __DIR__ . '/detection/web-vitals.asset.php';
-	$web_vitals_lib_src  = add_query_arg( 'ver', $web_vitals_lib_data['version'], plugin_dir_url( __FILE__ ) . '/detection/web-vitals.js' );
+	$web_vitals_lib_data = require __DIR__ . '/build/web-vitals.asset.php';
+	$web_vitals_lib_src  = add_query_arg( 'ver', $web_vitals_lib_data['version'], plugin_dir_url( __FILE__ ) . 'build/web-vitals.js' );
 
 	$current_url = od_get_current_url();
 	$detect_args = array(
@@ -64,7 +64,7 @@
 	return wp_get_inline_script_tag(
 		sprintf(
 			'import detect from %s; detect( %s );',
-			wp_json_encode( add_query_arg( 'ver', OPTIMIZATION_DETECTIVE_VERSION, plugin_dir_url( __FILE__ ) . 'detection/detect.js' ) ),
+			wp_json_encode( add_query_arg( 'ver', OPTIMIZATION_DETECTIVE_VERSION, plugin_dir_url( __FILE__ ) . 'detect.js' ) ),
 			wp_json_encode( $detect_args )
 		),
 		array( 'type' => 'module' )
Only in diff-builds/new/optimization-detective: detect.js
diff -ur diff-builds/old/optimization-detective/helper.php diff-builds/new/optimization-detective/helper.php
--- diff-builds/old/optimization-detective/helper.php	2024-04-12 11:57:58.201899301 -0700
+++ diff-builds/new/optimization-detective/helper.php	2024-04-12 11:57:58.204899301 -0700
@@ -18,5 +18,6 @@
  * @since 0.1.0
  */
 function od_render_generator_meta_tag() {
-	echo '<meta name="generator" content="Optimization Detective ' . esc_attr( OPTIMIZATION_DETECTIVE_VERSION ) . '">' . "\n";
+	// Use the plugin slug as it is immutable.
+	echo '<meta name="generator" content="optimization-detective ' . esc_attr( OPTIMIZATION_DETECTIVE_VERSION ) . '">' . "\n";
 }
diff -ur diff-builds/old/optimization-detective/load.php diff-builds/new/optimization-detective/load.php
--- diff-builds/old/optimization-detective/load.php	2024-04-12 11:57:58.201899301 -0700
+++ diff-builds/new/optimization-detective/load.php	2024-04-12 11:57:58.204899301 -0700
@@ -5,7 +5,7 @@
  * Description: Uses real user metrics to improve heuristics WordPress applies on the frontend to improve image loading priority.
  * Requires at least: 6.4
  * Requires PHP: 7.0
- * Version: 0.1.0
+ * Version: 0.1.1
  * Author: WordPress Performance Team
  * Author URI: https://make.wordpress.org/performance/
  * License: GPLv2 or later
@@ -27,7 +27,7 @@
 
 if (
 	( is_admin() || ( defined( 'WP_CLI' ) && WP_CLI ) ) &&
-	! file_exists( __DIR__ . '/detection/web-vitals.asset.php' )
+	! file_exists( __DIR__ . '/build/web-vitals.asset.php' )
 ) {
 	// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error
 	trigger_error(
@@ -35,7 +35,7 @@
 			sprintf(
 				/* translators: 1: File path. 2: CLI command. */
 				'[Optimization Detective] ' . __( 'Unable to load %1$s. Please make sure you have run %2$s.', 'optimization-detective' ),
-				'detection/web-vitals.asset.php',
+				'build/web-vitals.asset.php',
 				'`npm install && npm run build:optimization-detective`'
 			)
 		),
@@ -43,12 +43,13 @@
 	);
 }
 
-define( 'OPTIMIZATION_DETECTIVE_VERSION', '0.1.0' );
+define( 'OPTIMIZATION_DETECTIVE_VERSION', '0.1.1' );
 
 require_once __DIR__ . '/helper.php';
 
 // Core infrastructure classes.
 require_once __DIR__ . '/class-od-data-validation-exception.php';
+require_once __DIR__ . '/class-od-html-tag-processor.php';
 require_once __DIR__ . '/class-od-url-metric.php';
 require_once __DIR__ . '/class-od-url-metrics-group.php';
 require_once __DIR__ . '/class-od-url-metrics-group-collection.php';
@@ -63,7 +64,7 @@
 require_once __DIR__ . '/detection.php';
 
 // Optimization logic.
-require_once __DIR__ . '/class-od-html-tag-processor.php';
+require_once __DIR__ . '/class-od-html-tag-walker.php';
 require_once __DIR__ . '/optimization.php';
 
 // Add hooks for the above requires.
diff -ur diff-builds/old/optimization-detective/optimization.php diff-builds/new/optimization-detective/optimization.php
--- diff-builds/old/optimization-detective/optimization.php	2024-04-12 11:57:58.201899301 -0700
+++ diff-builds/new/optimization-detective/optimization.php	2024-04-12 11:57:58.204899301 -0700
@@ -237,14 +237,14 @@
 	$detected_lcp_element_xpaths = array();
 
 	// Walk over all tags in the document and ensure fetchpriority is set/removed, and gather IMG attributes or background-image for preloading.
-	$processor = new OD_HTML_Tag_Processor( $buffer );
-	foreach ( $processor->open_tags() as $tag_name ) {
+	$walker = new OD_HTML_Tag_Walker( $buffer );
+	foreach ( $walker->open_tags() as $tag_name ) {
 		$is_img_tag = (
 			'IMG' === $tag_name
 			&&
-			$processor->get_attribute( 'src' )
+			$walker->get_attribute( 'src' )
 			&&
-			! str_starts_with( $processor->get_attribute( 'src' ), 'data:' )
+			! str_starts_with( $walker->get_attribute( 'src' ), 'data:' )
 		);
 
 		/*
@@ -256,7 +256,7 @@
 		 * parser of the `url()` functions from the property value.
 		 */
 		$background_image_url = null;
-		$style                = $processor->get_attribute( 'style' );
+		$style                = $walker->get_attribute( 'style' );
 		if (
 			$style
 			&&
@@ -271,28 +271,28 @@
 			continue;
 		}
 
-		$xpath = $processor->get_xpath();
+		$xpath = $walker->get_xpath();
 
 		// Ensure the fetchpriority attribute is set on the element properly.
 		if ( $is_img_tag ) {
 			if ( $common_lcp_element && $xpath === $common_lcp_element['xpath'] ) {
-				if ( 'high' === $processor->get_attribute( 'fetchpriority' ) ) {
-					$processor->set_attribute( 'data-od-fetchpriority-already-added', true );
+				if ( 'high' === $walker->get_attribute( 'fetchpriority' ) ) {
+					$walker->set_attribute( 'data-od-fetchpriority-already-added', true );
 				} else {
-					$processor->set_attribute( 'fetchpriority', 'high' );
-					$processor->set_attribute( 'data-od-added-fetchpriority', true );
+					$walker->set_attribute( 'fetchpriority', 'high' );
+					$walker->set_attribute( 'data-od-added-fetchpriority', true );
 				}
 
 				// Never include loading=lazy on the LCP image common across all breakpoints.
-				if ( 'lazy' === $processor->get_attribute( 'loading' ) ) {
-					$processor->set_attribute( 'data-od-removed-loading', $processor->get_attribute( 'loading' ) );
-					$processor->remove_attribute( 'loading' );
+				if ( 'lazy' === $walker->get_attribute( 'loading' ) ) {
+					$walker->set_attribute( 'data-od-removed-loading', $walker->get_attribute( 'loading' ) );
+					$walker->remove_attribute( 'loading' );
 				}
-			} elseif ( $all_breakpoints_have_url_metrics && $processor->get_attribute( 'fetchpriority' ) ) {
+			} elseif ( $all_breakpoints_have_url_metrics && $walker->get_attribute( 'fetchpriority' ) ) {
 				// Note: The $all_breakpoints_have_url_metrics condition here allows for server-side heuristics to
 				// continue to apply while waiting for all breakpoints to have metrics collected for them.
-				$processor->set_attribute( 'data-od-removed-fetchpriority', $processor->get_attribute( 'fetchpriority' ) );
-				$processor->remove_attribute( 'fetchpriority' );
+				$walker->set_attribute( 'data-od-removed-fetchpriority', $walker->get_attribute( 'fetchpriority' ) );
+				$walker->remove_attribute( 'fetchpriority' );
 			}
 		}
 
@@ -306,7 +306,7 @@
 			if ( $is_img_tag ) {
 				$img_attributes = array();
 				foreach ( array( 'src', 'srcset', 'sizes', 'crossorigin' ) as $attr_name ) {
-					$value = $processor->get_attribute( $attr_name );
+					$value = $walker->get_attribute( $attr_name );
 					if ( null !== $value ) {
 						$img_attributes[ $attr_name ] = $value;
 					}
@@ -322,10 +322,9 @@
 		}
 
 		if ( $needs_detection ) {
-			$processor->set_attribute( 'data-od-xpath', $xpath );
+			$walker->set_attribute( 'data-od-xpath', $xpath );
 		}
 	}
-	$buffer = $processor->get_updated_html();
 
 	// If there were any LCP elements captured in URL Metrics that no longer exist in the document, we need to behave as
 	// if they didn't exist in the first place as there is nothing that can be preloaded.
@@ -337,24 +336,17 @@
 		}
 	}
 
-	// Inject any preload links at the end of the HEAD. In the future, WP_HTML_Processor could be used to do this injection.
-	// However, given the simple replacement here this is not essential.
+	// Inject any preload links at the end of the HEAD.
 	$head_injection = od_construct_preload_links( $lcp_elements_by_minimum_viewport_widths );
+	if ( $head_injection ) {
+		$walker->append_head_html( $head_injection );
+	}
 
 	// Inject detection script.
 	// TODO: When optimizing above, if we find that there is a stored LCP element but it fails to match, it should perhaps set $needs_detection to true and send the request with an override nonce. However, this would require backtracking and adding the data-od-xpath attributes.
 	if ( $needs_detection ) {
-		$head_injection .= od_get_detection_script( $slug, $group_collection );
-	}
-
-	if ( $head_injection ) {
-		$buffer = preg_replace(
-			'#(?=</HEAD>)#i',
-			$head_injection,
-			$buffer,
-			1
-		);
+		$walker->append_body_html( od_get_detection_script( $slug, $group_collection ) );
 	}
 
-	return $buffer;
+	return $walker->get_updated_html();
 }
diff -ur diff-builds/old/optimization-detective/readme.txt diff-builds/new/optimization-detective/readme.txt
--- diff-builds/old/optimization-detective/readme.txt	2024-04-12 11:57:58.201899301 -0700
+++ diff-builds/new/optimization-detective/readme.txt	2024-04-12 11:57:58.204899301 -0700
@@ -4,7 +4,7 @@
 Requires at least: 6.4
 Tested up to:      6.5
 Requires PHP:      7.0
-Stable tag:        0.1.0
+Stable tag:        0.1.1
 License:           GPLv2 or later
 License URI:       https://www.gnu.org/licenses/gpl-2.0.html
 Tags:              performance, images
@@ -137,6 +137,11 @@
 
 == Changelog ==
 
+= 0.1.1 =
+
+* Use plugin slug for generator tag. ([1103](https://github.com/WordPress/performance/pull/1103))
+* Prevent detection script injection from breaking import maps in classic themes. ([1084](https://github.com/WordPress/performance/pull/1084))
+
 = 0.1.0 =
 
 * Initial release.
diff -ur diff-builds/old/optimization-detective/storage/data.php diff-builds/new/optimization-detective/storage/data.php
--- diff-builds/old/optimization-detective/storage/data.php	2024-04-12 11:57:58.202899301 -0700
+++ diff-builds/new/optimization-detective/storage/data.php	2024-04-12 11:57:58.205899301 -0700
@@ -91,7 +91,7 @@
  * This is essentially the REQUEST_URI prefixed by the scheme and host for the home URL.
  * This is needed in particular due to subdirectory installs.
  *
- * @since n.e.x.t
+ * @since 0.1.1
  * @access private
  *
  * @return string Current URL.
diff -ur diff-builds/old/optimization-detective/storage/rest-api.php diff-builds/new/optimization-detective/storage/rest-api.php
--- diff-builds/old/optimization-detective/storage/rest-api.php	2024-04-12 11:57:58.202899301 -0700
+++ diff-builds/new/optimization-detective/storage/rest-api.php	2024-04-12 11:57:58.205899301 -0700
@@ -1,6 +1,6 @@
 <?php
 /**
- * REST API integration for the module.
+ * REST API integration for the plugin.
  *
  * @package optimization-detective
  * @since 0.1.0
diff -ur diff-builds/old/speculation-rules/load.php diff-builds/new/speculation-rules/load.php
--- diff-builds/old/speculation-rules/load.php	2024-04-12 11:57:58.203899301 -0700
+++ diff-builds/new/speculation-rules/load.php	2024-04-12 11:57:58.206899301 -0700
@@ -5,7 +5,7 @@
  * Description: Enables browsers to speculatively prerender or prefetch pages when hovering over links.
  * Requires at least: 6.4
  * Requires PHP: 7.0
- * Version: 1.1.0
+ * Version: 1.2.0
  * Author: WordPress Performance Team
  * Author URI: https://make.wordpress.org/performance/
  * License: GPLv2 or later
@@ -25,7 +25,7 @@
 	return;
 }
 
-define( 'SPECULATION_RULES_VERSION', '1.1.0' );
+define( 'SPECULATION_RULES_VERSION', '1.2.0' );
 
 require_once __DIR__ . '/class-plsr-url-pattern-prefixer.php';
 require_once __DIR__ . '/helper.php';
diff -ur diff-builds/old/speculation-rules/readme.txt diff-builds/new/speculation-rules/readme.txt
--- diff-builds/old/speculation-rules/readme.txt	2024-04-12 11:57:58.203899301 -0700
+++ diff-builds/new/speculation-rules/readme.txt	2024-04-12 11:57:58.206899301 -0700
@@ -4,7 +4,7 @@
 Requires at least: 6.4
 Tested up to:      6.5
 Requires PHP:      7.0
-Stable tag:        1.1.0
+Stable tag:        1.2.0
 License:           GPLv2 or later
 License URI:       https://www.gnu.org/licenses/gpl-2.0.html
 Tags:              performance, javascript, speculation rules, prerender, prefetch
@@ -102,6 +102,10 @@
 
 == Changelog ==
 
+= 1.2.0 =
+
+* Add missing uninstall.php to remove plugin's database option. ([1128](https://github.com/WordPress/performance/pull/1128))
+
 = 1.1.0 =
 
 * Allow excluding URL patterns from prerendering or prefetching specifically. ([1025](https://github.com/WordPress/performance/pull/1025))
Only in diff-builds/new/speculation-rules: uninstall.php
Only in diff-builds/old/webp-uploads: can-load.php
diff -ur diff-builds/old/webp-uploads/fallback.js diff-builds/new/webp-uploads/fallback.js
--- diff-builds/old/webp-uploads/fallback.js	2024-04-12 11:57:58.203899301 -0700
+++ diff-builds/new/webp-uploads/fallback.js	2024-04-12 11:57:58.206899301 -0700
@@ -1,124 +1 @@
-window.wpPerfLab = window.wpPerfLab || {};
-
-( function( document ) {
-	window.wpPerfLab.webpUploadsFallbackWebpImages = function( media ) {
-		for ( var i = 0; i < media.length; i++ ) {
-			try {
-				var image         = media[ i ],
-					media_details = image.media_details,
-					media_sources = media_details.sources,
-					sizes         = media_details.sizes,
-					sizes_keys    = Object.keys( sizes );
-
-				// If the full image has no JPEG version available, no sub-size will have JPEG available either.
-				if ( sizes.full && ! sizes.full.sources['image/jpeg'] ) {
-					continue;
-				}
-
-				var images = document.querySelectorAll( 'img.wp-image-' + image.id );
-
-				for ( var j = 0; j < images.length; j++ ) {
-
-					var src = images[ j ].src;
-
-					// If there are sources but no sizes, then attempt to replace src through sources. In that case, there is nothing more to replace.
-					if ( media_sources && ! sizes_keys.length ) {
-						// Only modify src if available and the relevant sources are set.
-						if ( src && media_sources['image/webp'] && media_sources['image/jpeg'] ) {
-							src = src.replace( media_sources['image/webp'].file, media_sources['image/jpeg'].file );
-							images[ j ].setAttribute( 'src', src );
-						}
-						continue;
-					}
-
-					var srcset = images[ j ].getAttribute( 'srcset' );
-
-					for ( var k = 0; k < sizes_keys.length; k++ ) {
-						var media_sizes_sources = sizes[ sizes_keys[ k ] ].sources;
-						if ( ! media_sizes_sources || ! media_sizes_sources['image/webp'] || ! media_sizes_sources['image/jpeg'] ) {
-							continue;
-						}
-
-						// Check to see if the image src has any size set, then update it.
-						if ( media_sizes_sources['image/webp'].source_url === src ) {
-							src = media_sizes_sources['image/jpeg'].source_url;
-
-							// If there is no srcset and the src has been replaced, there is nothing more to replace.
-							if ( ! srcset ) {
-								break;
-							}
-						}
-
-						if ( srcset ) {
-							srcset = srcset.replace( media_sizes_sources['image/webp'].source_url, media_sizes_sources['image/jpeg'].source_url );
-						}
-					}
-
-					if ( srcset ) {
-						images[ j ].setAttribute( 'srcset', srcset );
-					}
-
-					if ( src ) {
-						images[ j ].setAttribute( 'src', src );
-					}
-				}
-			} catch ( e ) {
-			}
-		}
-	};
-
-	var restApi = document.getElementById( 'webpUploadsFallbackWebpImages' ).getAttribute( 'data-rest-api' );
-
-	var loadMediaDetails = function( nodes ) {
-		var ids = [];
-		for ( var i = 0; i < nodes.length; i++ ) {
-			var node = nodes[ i ];
-			var srcset = node.getAttribute( 'srcset' ) || '';
-
-			if (
-				node.nodeName !== "IMG" ||
-				( ! node.src.match( /\.webp$/i ) && ! srcset.match( /\.webp\s+/ ) )
-			) {
-				continue;
-			}
-
-			var attachment = node.className.match( /wp-image-(\d+)/i );
-			if ( attachment && attachment[1] && ids.indexOf( attachment[1] ) === -1 ) {
-				ids.push( attachment[1] );
-			}
-		}
-
-		for ( var page = 0, pages = Math.ceil( ids.length / 100 ); page < pages; page++ ) {
-			var pageIds = [];
-			for ( var i = 0; i < 100 && i + page * 100 < ids.length; i++ ) {
-				pageIds.push( ids[ i + page * 100 ] );
-			}
-
-			var jsonp = document.createElement( 'script' );
-			var restPath = 'wp/v2/media/?_fields=id,media_details&_jsonp=wpPerfLab.webpUploadsFallbackWebpImages&per_page=100&include=' + pageIds.join( ',' );
-			if ( -1 !== restApi.indexOf( '?' ) ) {
-				restPath = restPath.replace( '?', '&' );
-			}
-			jsonp.src = restApi + restPath;
-			document.body.appendChild( jsonp );
-		}
-	};
-
-	try {
-		// Loop through already available images.
-		loadMediaDetails( document.querySelectorAll( 'img' ) );
-
-		// Start the mutation observer to update images added dynamically.
-		var observer = new MutationObserver( function( mutationList ) {
-			for ( var i = 0; i < mutationList.length; i++ ) {
-				loadMediaDetails( mutationList[ i ].addedNodes );
-			}
-		} );
-
-		observer.observe( document.body, {
-			subtree: true,
-			childList: true,
-		} );
-	} catch ( e ) {
-	}
-} )( document );
+window.wpPerfLab=window.wpPerfLab||{},function(e){window.wpPerfLab.webpUploadsFallbackWebpImages=function(t){for(let b=0;b<t.length;b++)try{var a=t[b],r=a.media_details,i=r.sources,l=r.sizes,s=Object.keys(l);if(l.full&&!l.full.sources["image/jpeg"])continue;var c=e.querySelectorAll("img.wp-image-"+a.id);for(let e=0;e<c.length;e++){var p=c[e].src;if(!i||s.length){var g=c[e].getAttribute("srcset");for(let e=0;e<s.length;e++){var o=l[s[e]].sources;if(o&&o["image/webp"]&&o["image/jpeg"]){if(o["image/webp"].source_url===p&&(p=o["image/jpeg"].source_url,!g))break;g&&(g=g.replace(o["image/webp"].source_url,o["image/jpeg"].source_url))}}g&&c[e].setAttribute("srcset",g),p&&c[e].setAttribute("src",p)}else p&&i["image/webp"]&&i["image/jpeg"]&&(p=p.replace(i["image/webp"].file,i["image/jpeg"].file),c[e].setAttribute("src",p))}}catch(e){}};var t=e.getElementById("webpUploadsFallbackWebpImages").getAttribute("data-rest-api"),a=function(a){var r=[];for(let e=0;e<a.length;e++){var i=a[e],l=i.getAttribute("srcset")||"";if("IMG"===i.nodeName&&(i.src.match(/\.webp$/i)||l.match(/\.webp\s+/))){var s=i.className.match(/wp-image-(\d+)/i);s&&s[1]&&-1===r.indexOf(s[1])&&r.push(s[1])}}for(let a=0,i=Math.ceil(r.length/100);a<i;a++){var c=[];for(let e=0;e<100&&e+100*a<r.length;e++)c.push(r[e+100*a]);var p=e.createElement("script"),g="wp/v2/media/?_fields=id,media_details&_jsonp=wpPerfLab.webpUploadsFallbackWebpImages&per_page=100&include="+c.join(",");-1!==t.indexOf("?")&&(g=g.replace("?","&")),p.src=t+g,e.body.appendChild(p)}};try{a(e.querySelectorAll("img")),new MutationObserver((function(e){for(let t=0;t<e.length;t++)a(e[t].addedNodes)})).observe(e.body,{subtree:!0,childList:!0})}catch(e){}}(document);
\ No newline at end of file
Only in diff-builds/old/webp-uploads: .gitattributes
diff -ur diff-builds/old/webp-uploads/helper.php diff-builds/new/webp-uploads/helper.php
--- diff-builds/old/webp-uploads/helper.php	2024-04-12 11:57:58.203899301 -0700
+++ diff-builds/new/webp-uploads/helper.php	2024-04-12 11:57:58.206899301 -0700
@@ -1,8 +1,9 @@
 <?php
 /**
- * Helper functions used for WebP Uploads.
+ * Helper functions used for Modern Image Formats.
  *
  * @package webp-uploads
+ *
  * @since 1.0.0
  */
 
@@ -256,7 +257,7 @@
 /**
  * Returns mime types that should be used for an image in the specific context.
  *
- * @since 1.4.0
+ * @since 1.0.0
  *
  * @param int    $attachment_id The attachment ID.
  * @param string $context       The current context.
@@ -286,7 +287,7 @@
 /**
  * Verifies if the request is for a frontend context within the <body> tag.
  *
- * @since 1.3.0
+ * @since 1.0.0
  *
  * @global WP_Query $wp_query WordPress Query object.
  *
@@ -311,7 +312,7 @@
 /**
  * Check whether the additional image is larger than the original image.
  *
- * @since 1.3.0
+ * @since 1.0.0
  *
  * @param array $original   An array with the metadata of the attachment.
  * @param array $additional An array containing the filename and file size for additional mime.
@@ -327,7 +328,7 @@
 		 * By default the performance lab plugin will use the mime type with the smaller filesize
 		 * rather than defaulting to `webp`.
 		 *
-		 * @since 1.3.0
+		 * @since 1.0.0
 		 *
 		 * @param bool $preferred_filesize Prioritize file size over mime type. Default true.
 		 */
diff -ur diff-builds/old/webp-uploads/hooks.php diff-builds/new/webp-uploads/hooks.php
--- diff-builds/old/webp-uploads/hooks.php	2024-04-12 11:57:58.203899301 -0700
+++ diff-builds/new/webp-uploads/hooks.php	2024-04-12 11:57:58.206899301 -0700
@@ -1,9 +1,10 @@
 <?php
 /**
- * Hook callbacks used for WebP Uploads.
+ * Hook callbacks used for Modern Image Formats.
  *
  * @package webp-uploads
- * @since 2.1.0
+ *
+ * @since 1.0.0
  */
 
 if ( ! defined( 'ABSPATH' ) ) {
@@ -530,7 +531,6 @@
  * for the specified image sizes, the *.webp references are stored inside of each size.
  *
  * @since 1.0.0
- * @since 1.3.0 Remove `webp_uploads_prefer_smaller_image_file` filter.
  *
  * @param string $original_image An <img> tag where the urls would be updated.
  * @param string $context        The context where this is function is being used.
@@ -607,7 +607,7 @@
 					continue;
 				}
 
-				/** This filter is documented in modules/images/webp-uploads/load.php */
+				/** This filter is documented in plugins/webp-uploads/load.php */
 				$filtered_image = (string) apply_filters( 'webp_uploads_pre_replace_additional_image_source', $image, $attachment_id, $size, $target_mime, $context );
 
 				// If filtered image is same as the image, run our own replacement logic, otherwise rely on the filtered image.
@@ -647,7 +647,7 @@
  * Updates the references of the featured image to the a new image format if available, in the same way it
  * occurs in the_content of a post.
  *
- * @since 1.1.0
+ * @since 1.0.0
  *
  * @param string $html          The current HTML markup of the featured image.
  * @param int    $post_id       The current post ID where the featured image is requested.
@@ -662,7 +662,7 @@
 /**
  * Adds a fallback mechanism to replace webp images with jpeg alternatives on older browsers.
  *
- * @since 1.3.0
+ * @since 1.0.0
  */
 function webp_uploads_wepb_fallback() {
 	// Get mime type transforms for the site.
@@ -712,7 +712,7 @@
  * Developers can control the generation of additional mime images for all sizes using the
  * webp_uploads_image_sizes_with_additional_mime_type_support filter.
  *
- * @since 1.3.0
+ * @since 1.0.0
  *
  * @return array An array of image sizes that can have additional mime types.
  */
@@ -733,7 +733,7 @@
 	/**
 	 * Filters whether additional mime types are allowed for image sizes.
 	 *
-	 * @since 1.3.0
+	 * @since 1.0.0
 	 *
 	 * @param array $allowed_sizes A map of image size names and whether they are allowed to have additional mime types.
 	 */
@@ -745,8 +745,7 @@
 /**
  * Updates the quality of WebP image sizes generated by WordPress to 82.
  *
- * @since 1.7.0
- * @since 2.7.0 Bump minimum WP to 6.3 so remove WP 6.1 related checks.
+ * @since 1.0.0
  *
  * @param int    $quality   Quality level between 1 (low) and 100 (high).
  * @param string $mime_type Image mime type.
@@ -764,18 +763,35 @@
 add_filter( 'wp_editor_set_quality', 'webp_uploads_modify_webp_quality', 10, 2 );
 
 /**
- * Displays the HTML generator tag for the WebP Uploads plugin.
+ * Displays the HTML generator tag for the Modern Image Formats plugin.
  *
  * See {@see 'wp_head'}.
  *
- * @since 2.2.0
+ * @since 1.0.0
  */
 function webp_uploads_render_generator() {
-	if (
-		defined( 'WEBP_UPLOADS_VERSION' ) &&
-		! str_starts_with( WEBP_UPLOADS_VERSION, 'Performance Lab ' )
-	) {
-		echo '<meta name="generator" content="WebP Uploads ' . esc_attr( WEBP_UPLOADS_VERSION ) . '">' . "\n";
-	}
+	// Use the plugin slug as it is immutable.
+	echo '<meta name="generator" content="webp-uploads ' . esc_attr( WEBP_UPLOADS_VERSION ) . '">' . "\n";
 }
 add_action( 'wp_head', 'webp_uploads_render_generator' );
+
+/**
+ * Adds a settings link to the plugin's action links.
+ *
+ * @since 1.1.0
+ *
+ * @param array $links An array of plugin action links.
+ * @return array The modified list of actions.
+ */
+function webp_uploads_settings_link( $links ) {
+	if ( ! is_array( $links ) ) {
+		return $links;
+	}
+	$links[] = sprintf(
+		'<a href="%1$s">%2$s</a>',
+		esc_url( admin_url( 'options-media.php#perflab_generate_webp_and_jpeg' ) ),
+		esc_html__( 'Settings', 'webp-uploads' )
+	);
+	return $links;
+}
+add_filter( 'plugin_action_links_' . WEBP_UPLOADS_MAIN_FILE, 'webp_uploads_settings_link' );
diff -ur diff-builds/old/webp-uploads/image-edit.php diff-builds/new/webp-uploads/image-edit.php
--- diff-builds/old/webp-uploads/image-edit.php	2024-04-12 11:57:58.203899301 -0700
+++ diff-builds/new/webp-uploads/image-edit.php	2024-04-12 11:57:58.206899301 -0700
@@ -1,8 +1,9 @@
 <?php
 /**
- * Edit images integration for the module, including backup and restore support.
+ * Edit images integration for the plugin, including backup and restore support.
  *
  * @package webp-uploads
+ *
  * @since 1.0.0
  */
 
@@ -427,7 +428,8 @@
  * The filter {@see 'image_edit_thumbnails_separately'} was introduced in WordPress 6.3 with default value of `false`,
  * for a behavior that previously was always enabled.
  *
- * @since 2.6.0
+ * @since 1.0.2
+ *
  * @see https://core.trac.wordpress.org/ticket/57685
  *
  * @return bool True if editing image thumbnails is enabled, false otherwise.
diff -ur diff-builds/old/webp-uploads/load.php diff-builds/new/webp-uploads/load.php
--- diff-builds/old/webp-uploads/load.php	2024-04-12 11:57:58.203899301 -0700
+++ diff-builds/new/webp-uploads/load.php	2024-04-12 11:57:58.206899301 -0700
@@ -1,11 +1,11 @@
 <?php
 /**
- * Plugin Name: WebP Uploads
- * Plugin URI: https://github.com/WordPress/performance/tree/trunk/modules/images/webp-uploads
- * Description: Creates WebP versions for new JPEG image uploads if supported by the server.
- * Requires at least: 6.3
+ * Plugin Name: Modern Image Formats
+ * Plugin URI: https://github.com/WordPress/performance/tree/trunk/plugins/webp-uploads
+ * Description: Converts images to more modern formats such as WebP or AVIF during upload.
+ * Requires at least: 6.4
  * Requires PHP: 7.0
- * Version: 1.0.5
+ * Version: 1.1.0
  * Author: WordPress Performance Team
  * Author URI: https://make.wordpress.org/performance/
  * License: GPLv2 or later
@@ -15,31 +15,18 @@
  * @package webp-uploads
  */
 
-// Define the constant.
-if ( defined( 'WEBP_UPLOADS_VERSION' ) ) {
-	return;
+// Exit if accessed directly.
+if ( ! defined( 'ABSPATH' ) ) {
+	exit;
 }
 
-define( 'WEBP_UPLOADS_VERSION', '1.0.5' );
-
-// Do not load the code if it is already loaded through another means.
-if ( function_exists( 'webp_uploads_create_sources_property' ) ) {
+// Define required constants.
+if ( defined( 'WEBP_UPLOADS_VERSION' ) ) {
 	return;
 }
 
-// Do not load the code and show an admin notice instead if conditions are not met.
-if ( ! require __DIR__ . '/can-load.php' ) {
-	add_action(
-		'admin_notices',
-		static function () {
-			printf(
-				'<div class="notice notice-error"><p>%s</p></div>',
-				esc_html__( 'The WebP Uploads feature cannot be loaded from within the plugin since it is already merged into WordPress core.', 'webp-uploads' )
-			);
-		}
-	);
-	return;
-}
+define( 'WEBP_UPLOADS_VERSION', '1.1.0' );
+define( 'WEBP_UPLOADS_MAIN_FILE', plugin_basename( __FILE__ ) );
 
 require_once __DIR__ . '/helper.php';
 require_once __DIR__ . '/rest-api.php';
diff -ur diff-builds/old/webp-uploads/readme.txt diff-builds/new/webp-uploads/readme.txt
--- diff-builds/old/webp-uploads/readme.txt	2024-04-12 11:57:58.203899301 -0700
+++ diff-builds/new/webp-uploads/readme.txt	2024-04-12 11:57:58.206899301 -0700
@@ -1,33 +1,35 @@
-=== WebP Uploads ===
+=== Modern Image Formats ===
 
 Contributors:      wordpressdotorg
-Requires at least: 6.3
-Tested up to:      6.3
+Requires at least: 6.4
+Tested up to:      6.5
 Requires PHP:      7.0
-Stable tag:        1.0.5
+Stable tag:        1.1.0
 License:           GPLv2 or later
 License URI:       https://www.gnu.org/licenses/gpl-2.0.html
 Tags:              performance, images, webp
 
-Creates WebP versions for new JPEG image uploads if supported by the server.
+Converts images to more modern formats such as WebP or AVIF during upload.
 
 == Description ==
 
 This plugin adds WebP support for media uploads within the WordPress application. WebP images will be generated only for new uploads, pre-existing imagery will not be converted to WebP format. By default, WebP images will only be generated for JPEG uploads, only the original uploaded file will still exist as a JPEG image. All generated image sizes will exist as WebP only. If you wish to change this behaviour, there is a checkbox in `Settings > Media` that - when checked - will alter the behaviour of this plugin to generate both JPEG and WebP images for every sub-size (noting again that this will only affect newly uploaded images, i.e. after making said change).
 
+_This plugin was formerly known as WebP Uploads._
+
 == Installation ==
 
 = Installation from within WordPress =
 
 1. Visit **Plugins > Add New**.
-2. Search for **WebP Uploads**.
-3. Install and activate the **WebP Uploads** plugin.
+2. Search for **Modern Image Formats**.
+3. Install and activate the **Modern Image Formats** plugin.
 
 = Manual installation =
 
 1. Upload the entire `webp-uploads` folder to the `/wp-content/plugins/` directory.
 2. Visit **Plugins**.
-3. Activate the **WebP Uploads** plugin.
+3. Activate the **Modern Image Formats** plugin.
 
 == Frequently Asked Questions ==
 
@@ -45,19 +47,28 @@
 
 Contributions are always welcome! Learn more about how to get involved in the [Core Performance Team Handbook](https://make.wordpress.org/performance/handbook/get-involved/).
 
-= I've activated the WebP Uploads module, but WebP images are not always generated when I upload a JPEG image. Why? =
+= I've activated the Modern Image Formats plugin, but WebP images are not always generated when I upload a JPEG image. Why? =
 
 There are two primary reasons that a WebP image may not be generated:
 
-1. The WebP Uploads plugin has identified that the WebP version of the uploaded JPEG image would have a larger file size than the original JPEG image, so it does not generate the WebP version.
+1. The Modern Image Formats plugin has identified that the WebP version of the uploaded JPEG image would have a larger file size than the original JPEG image, so it does not generate the WebP version.
 2. The JPEG image was not uploaded to the [Media Library](https://wordpress.com/support/media/). At this time, WebP versions are only generated for images to the Media Library. WebP versions are not generated for JPEG images that are added to your site in other ways, such as in a template file or the [Customizer](https://wordpress.com/support/customizer/).
 
-= With the WebP Uploads plugin activated, will the plugin generate JPEG and WebP versions of every image that I upload? =
+= With the Modern Image Formats plugin activated, will the plugin generate JPEG and WebP versions of every image that I upload? =
 
-By default, the WebP Uploads plugin will only generate WebP versions of the images that you upload. If you wish to have both WebP **and** JPEG versions generated, you can navigate to **Settings > Media** and enable the **Generate JPEG files in addition to WebP** option.
+By default, the Modern Image Formats plugin will only generate WebP versions of the images that you upload. If you wish to have both WebP **and** JPEG versions generated, you can navigate to **Settings > Media** and enable the **Generate JPEG files in addition to WebP** option.
 
 == Changelog ==
 
+= 1.1.0 =
+
+* Add link to WebP settings to plugins table. ([1036](https://github.com/WordPress/performance/pull/1036))
+* Rename plugin to "Modern Image Formats". ([1101](https://github.com/WordPress/performance/pull/1101))
+* Use plugin slug for generator tag. ([1103](https://github.com/WordPress/performance/pull/1103))
+* Delete option when uninstalling the Modern Image Formats plugin. ([1116](https://github.com/WordPress/performance/pull/1116))
+* Bump minimum required WP version to 6.4. ([1062](https://github.com/WordPress/performance/pull/1062))
+* Update tested WordPress version to 6.5. ([1027](https://github.com/WordPress/performance/pull/1027))
+
 = 1.0.5 =
 
 * Exclude ".wordpress-org" directory when deploying standalone plugins. ([866](https://github.com/WordPress/performance/pull/866))
@@ -80,4 +91,4 @@
 
 = 1.0.0 =
 
-* Initial release of the WebP Uploads plugin as a standalone plugin. ([664](https://github.com/WordPress/performance/pull/664))
+* Initial release of the Modern Image Formats plugin as a standalone plugin. ([664](https://github.com/WordPress/performance/pull/664))
diff -ur diff-builds/old/webp-uploads/rest-api.php diff-builds/new/webp-uploads/rest-api.php
--- diff-builds/old/webp-uploads/rest-api.php	2024-04-12 11:57:58.203899301 -0700
+++ diff-builds/new/webp-uploads/rest-api.php	2024-04-12 11:57:58.206899301 -0700
@@ -1,8 +1,9 @@
 <?php
 /**
- * REST API integration for the module.
+ * REST API integration for the plugin.
  *
  * @package webp-uploads
+ *
  * @since 1.0.0
  */
 
diff -ur diff-builds/old/webp-uploads/settings.php diff-builds/new/webp-uploads/settings.php
--- diff-builds/old/webp-uploads/settings.php	2024-04-12 11:57:58.203899301 -0700
+++ diff-builds/new/webp-uploads/settings.php	2024-04-12 11:57:58.206899301 -0700
@@ -1,9 +1,10 @@
 <?php
 /**
- * Settings for the WebP Uploads module.
+ * Settings for the Modern Image Formats plugin.
  *
  * @package webp-uploads
- * @since 1.6.0
+ *
+ * @since 1.0.0
  */
 
 if ( ! defined( 'ABSPATH' ) ) {
@@ -13,7 +14,7 @@
 /**
  * Registers setting for generating both JPEG and WebP versions for image uploads.
  *
- * @since 1.6.0
+ * @since 1.0.0
  */
 function webp_uploads_register_media_settings_field() {
 	register_setting(
@@ -31,7 +32,7 @@
 /**
  * Adds media settings field for the 'perflab_generate_webp_and_jpeg' setting.
  *
- * @since 1.6.0
+ * @since 1.0.0
  */
 function webp_uploads_add_media_settings_field() {
 	// Add settings field.
@@ -49,7 +50,7 @@
 /**
  * Renders the settings field for the 'perflab_generate_webp_and_jpeg' setting.
  *
- * @since 1.6.0
+ * @since 1.0.0
  */
 function webp_uploads_generate_webp_jpeg_setting_callback() {
 	if ( ! is_multisite() ) {
@@ -70,7 +71,7 @@
 /**
  * Adds custom style for media settings.
  *
- * @since 1.6.0
+ * @since 1.0.0
  */
 function webp_uploads_media_setting_style() {
 	if ( is_multisite() ) {
Only in diff-builds/new/webp-uploads: uninstall.php
Only in diff-builds/old/webp-uploads: .wordpress-org

Files being deleted:

  1. dominant-color-images/.gitattributes
  2. dominant-color-images/.wordpress-org
  3. optimization-detective/detection
  4. webp-uploads/can-load.php
  5. webp-uploads/.gitattributes
  6. webp-uploads/.wordpress-org

Files being added:

  1. optimization-detective/build
  2. optimization-detective/class-od-html-tag-walker.php
  3. optimization-detective/detect.js
  4. speculation-rules/uninstall.php
  5. webp-uploads/uninstall.php

@westonruter
Copy link
Member Author

✅ Testing passed

Upon upgrading, the modules are removed from the settings page. Instead, the standalone plugins are shown:

Before After
Screenshot 2024-04-12 13 35 12 Screenshot 2024-04-12 13 35 50

For the Site Health modules, I can confirm they show up as expected:

image

image

I also tried adding a large autoloaded option: cat wp-includes/*.php | wp option add all-wp-includes --autoload=yes and saw:

image

Clicking Disable Autoload successfully cleared the critical issue:

image

After deleting all transients and activating Twenty Twenty and visiting the homepage, I saw the Audit Enqueued Assets test:

image

When a standalone plugin is not installed, I see an "Active" button as expected:

image

Clicking it results in the plugin being installed and activated:

image

Similarly, if the plugin was already installed but just not activated, clicking Activate will activate the plugin already installed:

image

After installing and activating all of the ZIP builds of all pending plugins, the Performance screen shows:

image

The old names are there as expected since the plugins haven't been pushed to the directory:

image

When file mods are disabled and a feature plugin is not installed, a warning is shown and the activate button us properly disabled:

image

With all standalone plugins active, the generator meta tags are all present:

<meta name="generator" content="WordPress 6.5.2" />
<meta name="generator" content="auto-sizes 1.0.1">
<meta name="generator" content="dominant-color-images 1.1.0">
<meta name="generator" content="embed-optimizer 0.1.1">
<meta name="generator" content="optimization-detective 0.1.1">
<meta name="generator" content="performance-lab 3.0.0; plugins: auto-sizes, dominant-color-images, embed-optimizer, performant-translations, speculation-rules, webp-uploads">
<meta name="generator" content="Performant Translations 1.1.2">
<meta name="generator" content="speculation-rules 1.2.0">
<meta name="generator" content="webp-uploads 1.1.0">

Note that the generator meta tag hasn't yet been updated to use a slug, since it is not in the monorepo. I've proposed this in swissspidy/performant-translations#174.

For Server Timing, I've enabled output buffering and added the_content to the filters which are tracked. And it does show up in the Timing panel of the network panel in DevTools:

image

@westonruter
Copy link
Member Author

I also smoke tested changes in the standalone plugins' changelogs to ensure they worked (e.g. Speculative Loading's uninstall.php works and Optimization Detective's detection script is now added to the end of the body).

Co-authored-by: Mukesh Panchal <[email protected]>
@westonruter westonruter merged commit 490b3b5 into release/3.0.0 Apr 15, 2024
26 checks passed
@westonruter westonruter deleted the prepare/3.0.0-release branch April 15, 2024 16:44
@westonruter westonruter mentioned this pull request May 17, 2024
7 tasks
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 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.

4 participants