Commit ebba561f1de for woocommerce

commit ebba561f1de36d4e4000236d010f0ce834535b13
Author: Vladimir Reznichenko <kalessil@gmail.com>
Date:   Mon Oct 26 10:14:48 2026 +0100

    [Performance] Micro-optimizations package to compress woo core execution time (final batch) (#70220)

diff --git a/plugins/woocommerce/changelog/performance-woo-startup-hotpath-micro-optimiations-p3 b/plugins/woocommerce/changelog/performance-woo-startup-hotpath-micro-optimiations-p3
new file mode 100644
index 00000000000..fc532606b13
--- /dev/null
+++ b/plugins/woocommerce/changelog/performance-woo-startup-hotpath-micro-optimiations-p3
@@ -0,0 +1,4 @@
+Significance: minor
+Type: performance
+
+Micro-optimizations package to compress Woo core initialization execution time (final batch).
diff --git a/plugins/woocommerce/includes/class-wc-cache-helper.php b/plugins/woocommerce/includes/class-wc-cache-helper.php
index 6e7b84c307b..20f481e34e7 100644
--- a/plugins/woocommerce/includes/class-wc-cache-helper.php
+++ b/plugins/woocommerce/includes/class-wc-cache-helper.php
@@ -53,11 +53,11 @@ class WC_Cache_Helper {

 		// Optimization note: this is the earliest stage at which we can bulk-prime pages data. As a result, we
 		// prime data for all pages used in is_page checks across the core, even if only a subset is required here.
-		$pages                    = array( 'cart', 'checkout', 'coming_soon', 'myaccount', 'shop', 'terms' );
+		$pages                    = array( 'cart', 'checkout', 'coming_soon', 'myaccount', 'refund_returns', 'shop', 'terms' );
 		$woocommerce_page_options = array_map( static fn ( string $page ) => sprintf( 'woocommerce_%s_page_id', $page ), $pages );
 		wp_prime_option_caches( $woocommerce_page_options );
 		$woocommerce_page_ids = array_combine( $pages, array_map( static fn ( string $page ) => wc_get_page_id( $page ), $pages ) );
-		_prime_post_caches( array_values( array_filter( $woocommerce_page_ids ) ), false, false );
+		_prime_post_caches( array_values( array_filter( $woocommerce_page_ids, static fn( $page_id ) => $page_id > 0 ) ), false, false );

 		$page_ids = array_filter( array( $woocommerce_page_ids['cart'], $woocommerce_page_ids['checkout'], $woocommerce_page_ids['myaccount'] ) );
 		if ( ! is_page( $page_ids ) ) {
diff --git a/plugins/woocommerce/includes/class-wc-query.php b/plugins/woocommerce/includes/class-wc-query.php
index acea738d142..262c680c3d4 100644
--- a/plugins/woocommerce/includes/class-wc-query.php
+++ b/plugins/woocommerce/includes/class-wc-query.php
@@ -608,6 +608,15 @@ class WC_Query {
 	 * @param WP_Query $q Query instance.
 	 */
 	public function product_query( $q ) {
+		// Prime caches to reduce future queries.
+		wp_prime_option_caches(
+			array(
+				'woocommerce_default_catalog_orderby',
+				'woocommerce_catalog_columns',
+				'woocommerce_catalog_rows',
+			)
+		);
+
 		if ( ! is_feed() ) {
 			$ordering = $this->get_catalog_ordering_args();
 			$q->set( 'orderby', $ordering['orderby'] );
diff --git a/plugins/woocommerce/includes/wc-product-functions.php b/plugins/woocommerce/includes/wc-product-functions.php
index 2a75cd65db9..a910f5f5b60 100644
--- a/plugins/woocommerce/includes/wc-product-functions.php
+++ b/plugins/woocommerce/includes/wc-product-functions.php
@@ -1473,7 +1473,6 @@ function wc_get_related_products( $product_id, $limit = 5, $exclude_ids = array(

 	// We want to query related posts if they are not cached, or we don't have enough.
 	if ( false === $related_posts || count( $related_posts ) < $limit ) {
-
 		$cats_array = apply_filters( 'woocommerce_product_related_posts_relate_by_category', true, $product_id ) ? apply_filters( 'woocommerce_get_related_product_cat_terms', wc_get_product_term_ids( $product_id, 'product_cat' ), $product_id ) : array();
 		$tags_array = apply_filters( 'woocommerce_product_related_posts_relate_by_tag', true, $product_id ) ? apply_filters( 'woocommerce_get_related_product_tag_terms', wc_get_product_term_ids( $product_id, 'product_tag' ), $product_id ) : array();

@@ -1485,13 +1484,16 @@ function wc_get_related_products( $product_id, $limit = 5, $exclude_ids = array(
 			$related_posts = $data_store->get_related_products( $cats_array, $tags_array, $exclude_ids, $limit + 10, $product_id );
 		}

+		$original_transient = $transient;
 		if ( $transient && is_array( $transient ) ) {
 			$transient[ $query_args ] = $related_posts;
 		} else {
 			$transient = array( $query_args => $related_posts );
 		}

-		set_transient( $transient_name, $transient, DAY_IN_SECONDS );
+		if ( $original_transient !== $transient ) {
+			set_transient( $transient_name, $transient, DAY_IN_SECONDS );
+		}
 	}

 	$related_posts = apply_filters(
diff --git a/plugins/woocommerce/phpstan-baseline.neon b/plugins/woocommerce/phpstan-baseline.neon
index 1a9f9d68b36..c224f21eb28 100644
--- a/plugins/woocommerce/phpstan-baseline.neon
+++ b/plugins/woocommerce/phpstan-baseline.neon
@@ -47001,12 +47001,6 @@ parameters:
 			count: 1
 			path: src/Blocks/Assets/Api.php

-		-
-			message: '#^Method Automattic\\WooCommerce\\Blocks\\Assets\\Api\:\:get_file_version\(\) should return string but returns int\<0, max\>\|false\.$#'
-			identifier: return.type
-			count: 1
-			path: src/Blocks/Assets/Api.php
-
 		-
 			message: '#^Method Automattic\\WooCommerce\\Blocks\\Assets\\Api\:\:register_script\(\) has no return type specified\.$#'
 			identifier: missingType.return
diff --git a/plugins/woocommerce/src/Blocks/Assets/Api.php b/plugins/woocommerce/src/Blocks/Assets/Api.php
index 435d5930e7b..2735221fc30 100644
--- a/plugins/woocommerce/src/Blocks/Assets/Api.php
+++ b/plugins/woocommerce/src/Blocks/Assets/Api.php
@@ -99,8 +99,9 @@ class Api {
 	 * @return string The cache buster value to use for the given file.
 	 */
 	protected function get_file_version( $file ) {
-		if ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG && file_exists( $this->package->get_path() . $file ) ) {
-			return filemtime( $this->package->get_path( trim( $file, '/' ) ) );
+		if ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) {
+			$mtime = @filemtime( $this->package->get_path( $file ) ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged -- performance optimization
+			return $mtime ? (string) $mtime : $this->wc_version;
 		}
 		return $this->wc_version;
 	}
diff --git a/plugins/woocommerce/src/Blocks/AssetsController.php b/plugins/woocommerce/src/Blocks/AssetsController.php
index f2c1e2bd811..1b8823b704d 100644
--- a/plugins/woocommerce/src/Blocks/AssetsController.php
+++ b/plugins/woocommerce/src/Blocks/AssetsController.php
@@ -550,7 +550,7 @@ final class AssetsController {

 		foreach ( $wp_scripts->registered as $handle => $script ) {
 			// scripts that are loaded in the footer has extra->group = 1.
-			if ( array_intersect( $known_packages, $script->deps ) && ! isset( $script->extra['group'] ) ) {
+			if ( ! isset( $script->extra['group'] ) && ! empty( $script->deps ) && array_intersect( $known_packages, $script->deps ) ) {
 				// Append the script to footer.
 				$wp_scripts->add_data( $handle, 'group', 1 );
 				// Show a warning.
@@ -564,7 +564,6 @@ final class AssetsController {
 					$error_handle,
 					sprintf( 'console.warn( "%s" );', $error_message )
 				);
-
 			}
 		}
 	}
diff --git a/plugins/woocommerce/src/Blocks/BlockTemplatesRegistry.php b/plugins/woocommerce/src/Blocks/BlockTemplatesRegistry.php
index 2a289e44aaf..9e218a9e20a 100644
--- a/plugins/woocommerce/src/Blocks/BlockTemplatesRegistry.php
+++ b/plugins/woocommerce/src/Blocks/BlockTemplatesRegistry.php
@@ -114,18 +114,18 @@ class BlockTemplatesRegistry {
 			);
 			if ( wp_is_block_theme() ) {
 				$product_types = wc_get_product_types();
-				if ( count( $product_types ) > 0 ) {
+				if ( ! empty( $product_types ) ) {
 					add_filter( 'default_wp_template_part_areas', array( $this, 'register_add_to_cart_with_options_template_part_area' ), 10, 1 );
-					if ( array_key_exists( ProductType::SIMPLE, $product_types ) ) {
+					if ( isset( $product_types[ ProductType::SIMPLE ] ) ) {
 						$template_parts[ SimpleProductAddToCartWithOptionsTemplate::SLUG ] = new SimpleProductAddToCartWithOptionsTemplate();
 					}
-					if ( array_key_exists( ProductType::EXTERNAL, $product_types ) ) {
+					if ( isset( $product_types[ ProductType::EXTERNAL ] ) ) {
 						$template_parts[ ExternalProductAddToCartWithOptionsTemplate::SLUG ] = new ExternalProductAddToCartWithOptionsTemplate();
 					}
-					if ( array_key_exists( ProductType::VARIABLE, $product_types ) ) {
+					if ( isset( $product_types[ ProductType::VARIABLE ] ) ) {
 						$template_parts[ VariableProductAddToCartWithOptionsTemplate::SLUG ] = new VariableProductAddToCartWithOptionsTemplate();
 					}
-					if ( array_key_exists( ProductType::GROUPED, $product_types ) ) {
+					if ( isset( $product_types[ ProductType::GROUPED ] ) ) {
 						$template_parts[ GroupedProductAddToCartWithOptionsTemplate::SLUG ] = new GroupedProductAddToCartWithOptionsTemplate();
 					}
 				}
diff --git a/plugins/woocommerce/src/Blocks/DependencyDetection.php b/plugins/woocommerce/src/Blocks/DependencyDetection.php
index 324731ace2c..ffbe7f6c8fa 100644
--- a/plugins/woocommerce/src/Blocks/DependencyDetection.php
+++ b/plugins/woocommerce/src/Blocks/DependencyDetection.php
@@ -232,18 +232,16 @@ final class DependencyDetection {
 	 */
 	private function is_woocommerce_script( string $url ): bool {
 		// Get the WooCommerce plugin URL (accounts for custom plugin directories).
-		$wc_plugin_url = \plugins_url( '/', WC_PLUGIN_FILE );
+		static $wc_plugin_url = null;
+		$wc_plugin_url        = $wc_plugin_url ?? \plugins_url( '/', WC_PLUGIN_FILE );

 		// Check if the URL starts with the WooCommerce plugin URL and is in a known subdirectory.
 		if ( strpos( $url, $wc_plugin_url ) !== 0 ) {
 			return false;
 		}

-		// Get the path after the WooCommerce plugin URL.
-		$relative_path = substr( $url, strlen( $wc_plugin_url ) );
-
-		// Check if it's in one of the known WooCommerce asset directories.
-		return (bool) preg_match( '#^(client|assets|build|vendor)/#', $relative_path );
+		// Check if it's in one of the known WooCommerce asset directories (requires normalization to relative path).
+		return (bool) preg_match( '#^(client|assets|build|vendor)/#', substr( $url, strlen( $wc_plugin_url ) ) );
 	}

 	/**
diff --git a/plugins/woocommerce/src/Blocks/Payments/Api.php b/plugins/woocommerce/src/Blocks/Payments/Api.php
index fa7da034bc4..478d5ff06e0 100644
--- a/plugins/woocommerce/src/Blocks/Payments/Api.php
+++ b/plugins/woocommerce/src/Blocks/Payments/Api.php
@@ -130,25 +130,19 @@ class Api {
 		// Preload option caches to minimize future queries for options that do not yet exist or are not set to autoload.
 		wp_prime_option_caches(
 			array(
-				'woocommerce_cheque_settings',
-				'woocommerce_paypal_settings',
+				'woocommerce_bacs_settings',
 				'woocommerce_bacs_accounts',
+				'woocommerce_cheque_settings',
 				'woocommerce_cod_settings',
+				'woocommerce_paypal_settings',
 			)
 		);

-		$payment_method_registry->register(
-			Package::container()->get( Cheque::class )
-		);
-		$payment_method_registry->register(
-			Package::container()->get( PayPal::class )
-		);
-		$payment_method_registry->register(
-			Package::container()->get( BankTransfer::class )
-		);
-		$payment_method_registry->register(
-			Package::container()->get( CashOnDelivery::class )
-		);
+		$container = Package::container();
+		$payment_method_registry->register( $container->get( Cheque::class ) );
+		$payment_method_registry->register( $container->get( PayPal::class ) );
+		$payment_method_registry->register( $container->get( BankTransfer::class ) );
+		$payment_method_registry->register( $container->get( CashOnDelivery::class ) );
 	}

 	/**
diff --git a/plugins/woocommerce/src/Blocks/Utils/BlockTemplateUtils.php b/plugins/woocommerce/src/Blocks/Utils/BlockTemplateUtils.php
index 8308faffda3..74e7eeed7e6 100644
--- a/plugins/woocommerce/src/Blocks/Utils/BlockTemplateUtils.php
+++ b/plugins/woocommerce/src/Blocks/Utils/BlockTemplateUtils.php
@@ -187,17 +187,12 @@ class BlockTemplateUtils {
 			$template->origin = 'plugin';
 		}

-		/*
-		* Run the block hooks algorithm introduced in WP 6.4 on the template content.
-		*/
-		if ( function_exists( 'inject_ignored_hooked_blocks_metadata_attributes' ) ) {
-			$hooked_blocks = get_hooked_blocks();
-			if ( ! empty( $hooked_blocks ) || has_filter( 'hooked_block_types' ) ) {
-				$before_block_visitor = make_before_block_visitor( $hooked_blocks, $template );
-				$after_block_visitor  = make_after_block_visitor( $hooked_blocks, $template );
-				$blocks               = parse_blocks( $template->content );
-				$template->content    = traverse_and_serialize_blocks( $blocks, $before_block_visitor, $after_block_visitor );
-			}
+		$hooked_blocks = get_hooked_blocks();
+		if ( ! empty( $hooked_blocks ) || has_filter( 'hooked_block_types' ) ) {
+			$before_block_visitor = make_before_block_visitor( $hooked_blocks, $template );
+			$after_block_visitor  = make_after_block_visitor( $hooked_blocks, $template );
+			$blocks               = parse_blocks( $template->content );
+			$template->content    = traverse_and_serialize_blocks( $blocks, $before_block_visitor, $after_block_visitor );
 		}

 		return $template;
@@ -752,11 +747,11 @@ class BlockTemplateUtils {
 		$saved_templates = $request_level_cache[ $template_type ][ $theme ];
 		if ( ! empty( $saved_templates ) && is_array( $slugs ) && array() !== $slugs ) {
 			$slugs           = array_map( 'sanitize_title', $slugs );
-			$saved_templates = array_filter( $saved_templates, fn( $template ) => in_array( $template->post_name, $slugs, true ) );
+			$saved_templates = array_filter( $saved_templates, static fn( $template ) => in_array( $template->post_name, $slugs, true ) );
 		}
 		if ( ! empty( $saved_templates ) ) {
-			$block_templates = array_map( fn( $template ) => self::build_template_result_from_post( $template ), $saved_templates );
-			$block_templates = array_values( array_filter( $block_templates, fn( $template ) => $template instanceof \WP_Block_Template ) );
+			$block_templates = array_map( static fn( $template ) => self::build_template_result_from_post( $template ), $saved_templates );
+			$block_templates = array_values( array_filter( $block_templates, static fn( $template ) => $template instanceof \WP_Block_Template ) );

 			return $block_templates;
 		}
diff --git a/plugins/woocommerce/src/Packages.php b/plugins/woocommerce/src/Packages.php
index 7f65303265d..51f0dce790e 100644
--- a/plugins/woocommerce/src/Packages.php
+++ b/plugins/woocommerce/src/Packages.php
@@ -125,6 +125,14 @@ class Packages {
 	protected static function get_enabled_packages() {
 		$enabled_packages = array();

+		// Preload option caches to minimize future queries for options that do not yet exist or are not set to autoload.
+		wp_prime_option_caches(
+			array_map(
+				static fn( $name ) => 'wc_feature_' . str_replace( '-', '_', $name ) . '_enabled',
+				array_keys( self::$merged_packages )
+			)
+		);
+
 		foreach ( self::$merged_packages as $merged_package_name => $package_class ) {

 			$option       = 'wc_feature_' . str_replace( '-', '_', $merged_package_name ) . '_enabled';
diff --git a/plugins/woocommerce/src/Utilities/FeaturesUtil.php b/plugins/woocommerce/src/Utilities/FeaturesUtil.php
index f8a10ccb3b5..6a8a11590b2 100644
--- a/plugins/woocommerce/src/Utilities/FeaturesUtil.php
+++ b/plugins/woocommerce/src/Utilities/FeaturesUtil.php
@@ -39,39 +39,21 @@ class FeaturesUtil {
 	 * @return bool True if the feature is enabled, false if not or if the feature doesn't exist.
 	 */
 	public static function feature_is_enabled( string $feature_id ): bool {
-		$features_controller = wc_get_container()->get( FeaturesController::class );
-		$feature             = $features_controller->get_feature_definition( $feature_id );
+		static $features_controller = null;
+		$features_controller        = $features_controller ?? wc_get_container()->get( FeaturesController::class );

-		// Log deprecation notice for deprecated features (only from the public API).
-		if ( ! empty( $feature['deprecated_since'] ) ) {
-			self::log_deprecated_feature_usage( $feature_id, $feature['deprecated_since'] );
+		static $checked_deprecations = array();
+		if ( ! isset( $checked_deprecations[ $feature_id ] ) ) {
+			$checked_deprecations[ $feature_id ] = true;
+			$definition                          = $features_controller->get_feature_definition( $feature_id );
+			if ( ! empty( $definition['deprecated_since'] ) ) {
+				wc_deprecated_function( "FeaturesUtil::feature_is_enabled('{$feature_id}')", $definition['deprecated_since'] );
+			}
 		}

 		return $features_controller->feature_is_enabled( $feature_id );
 	}

-	/**
-	 * Log usage of a deprecated feature.
-	 *
-	 * This method ensures logging only happens once per request to avoid spam.
-	 *
-	 * @param string $feature_id       The feature id being checked.
-	 * @param string $deprecated_since The version since which the feature is deprecated.
-	 */
-	private static function log_deprecated_feature_usage( string $feature_id, string $deprecated_since ): void {
-		static $logged = array();
-
-		if ( isset( $logged[ $feature_id ] ) ) {
-			return;
-		}
-		$logged[ $feature_id ] = true;
-
-		wc_deprecated_function(
-			"FeaturesUtil::feature_is_enabled('{$feature_id}')",
-			$deprecated_since
-		);
-	}
-
 	/**
 	 * Declare (in)compatibility with a given feature for a given plugin.
 	 *