Commit a3c89c6c403 for woocommerce

commit a3c89c6c4037718b297acd876d2d35513c1e3600
Author: Vladimir Reznichenko <kalessil@gmail.com>
Date:   Wed Oct 7 11:50:33 2026 +0200

    [Performance] Consolidate verified review meta population across core workflows (#68044)

    Populate verified-owner review meta consistently across all review submission workflows.

    ---------

    Co-authored-by: Marcin Dudek <marcin.dudek.dev@gmail.com>

diff --git a/plugins/woocommerce/changelog/review-verified-owner-meta-backfill b/plugins/woocommerce/changelog/review-verified-owner-meta-backfill
new file mode 100644
index 00000000000..8d5f1d1af8c
--- /dev/null
+++ b/plugins/woocommerce/changelog/review-verified-owner-meta-backfill
@@ -0,0 +1,4 @@
+Significance: minor
+Type: performance
+
+Populate verified-owner review meta consistently across all review submission workflows.
diff --git a/plugins/woocommerce/includes/rest-api/Controllers/Version1/class-wc-rest-product-reviews-v1-controller.php b/plugins/woocommerce/includes/rest-api/Controllers/Version1/class-wc-rest-product-reviews-v1-controller.php
index fda59f3e98e..9eaa821ac3b 100644
--- a/plugins/woocommerce/includes/rest-api/Controllers/Version1/class-wc-rest-product-reviews-v1-controller.php
+++ b/plugins/woocommerce/includes/rest-api/Controllers/Version1/class-wc-rest-product-reviews-v1-controller.php
@@ -319,7 +319,8 @@ class WC_REST_Product_Reviews_V1_Controller extends WC_REST_Controller {
 			return new WP_Error( 'rest_product_review_failed_create', __( 'Creating product review failed.', 'woocommerce' ), array( 'status' => 500 ) );
 		}

-		update_comment_meta( $product_review_id, 'rating', ( ! empty( $request['rating'] ) ? $request['rating'] : '0' ) );
+		update_comment_meta( $product_review_id, 'rating', ! empty( $request['rating'] ) ? $request['rating'] : '0' );
+		wc_review_is_from_verified_owner( $product_review_id );

 		$product_review = get_comment( $product_review_id );

diff --git a/plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-product-reviews-controller.php b/plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-product-reviews-controller.php
index f959dcc559e..168880ad192 100644
--- a/plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-product-reviews-controller.php
+++ b/plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-product-reviews-controller.php
@@ -471,9 +471,10 @@ class WC_REST_Product_Reviews_Controller extends WC_REST_Controller {
 		}

 		update_comment_meta( $review_id, 'rating', ! empty( $request['rating'] ) ? $request['rating'] : '0' );
-
 		if ( isset( $request['verified'] ) && ! empty( $request['verified'] ) ) {
 			update_comment_meta( $review_id, 'verified', $request['verified'] );
+		} else {
+			wc_review_is_from_verified_owner( $review_id );
 		}

 		$review = get_comment( $review_id );
diff --git a/plugins/woocommerce/templates/single-product/review-meta.php b/plugins/woocommerce/templates/single-product/review-meta.php
index 653e9d478f0..438b026e1a9 100644
--- a/plugins/woocommerce/templates/single-product/review-meta.php
+++ b/plugins/woocommerce/templates/single-product/review-meta.php
@@ -12,13 +12,12 @@
  *
  * @see     https://woocommerce.com/document/template-structure/
  * @package WooCommerce\Templates
- * @version 3.4.0
+ * @version 11.3.0
  */

 defined( 'ABSPATH' ) || exit;

 global $comment;
-$verified = wc_review_is_from_verified_owner( $comment->comment_ID );

 if ( '0' === $comment->comment_approved ) { ?>

@@ -33,7 +32,7 @@ if ( '0' === $comment->comment_approved ) { ?>
 	<p class="meta">
 		<strong class="woocommerce-review__author"><?php comment_author(); ?> </strong>
 		<?php
-		if ( 'yes' === get_option( 'woocommerce_review_rating_verification_label' ) && $verified ) {
+		if ( 'yes' === get_option( 'woocommerce_review_rating_verification_label' ) && wc_review_is_from_verified_owner( $comment->comment_ID ) ) {
 			echo '<em class="woocommerce-review__verified verified">(' . esc_attr__( 'verified owner', 'woocommerce' ) . ')</em> ';
 		}

diff --git a/plugins/woocommerce/tests/php/includes/rest-api/Controllers/Version1/class-wc-rest-product-reviews-v1-controller-tests.php b/plugins/woocommerce/tests/php/includes/rest-api/Controllers/Version1/class-wc-rest-product-reviews-v1-controller-tests.php
index 7ff1a113223..b8009dfd31c 100644
--- a/plugins/woocommerce/tests/php/includes/rest-api/Controllers/Version1/class-wc-rest-product-reviews-v1-controller-tests.php
+++ b/plugins/woocommerce/tests/php/includes/rest-api/Controllers/Version1/class-wc-rest-product-reviews-v1-controller-tests.php
@@ -674,6 +674,36 @@ class WC_REST_Product_Reviews_V1_Controller_Tests extends WC_Unit_Test_Case {
 		$this->assertSame( 0, (int) get_post( $source_id )->comment_count );
 	}

+	/**
+	 * @testdox Creating a review eagerly populates the verified-owner meta at creation time, not lazily during response preparation.
+	 */
+	public function test_create_item_populates_verified_meta(): void {
+		$product = ProductHelper::create_simple_product();
+		$order   = OrderHelper::create_order( 0, $product );
+		$order->set_billing_email( 'jane.smith@example.org' );
+		$order->set_status( 'completed' );
+		$order->save();
+
+		// Stub prepare_item_for_response so it cannot backfill the meta as a side effect.
+		$sut = new class() extends WC_REST_Product_Reviews_V1_Controller {
+			public function prepare_item_for_response( $review, $request ) { // phpcs:ignore Squiz.Commenting.FunctionComment.Missing
+				return rest_ensure_response( array( 'id' => (int) $review->comment_ID ) );
+			}
+		};
+
+		$request = new WP_REST_Request( 'POST', '/wc/v1/products/' . $product->get_id() . '/reviews' );
+		$request->set_param( 'product_id', $product->get_id() );
+		$request->set_param( 'review', 'Great product, would buy again.' );
+		$request->set_param( 'name', 'Jane Smith' );
+		$request->set_param( 'email', 'jane.smith@example.org' );
+		$request->set_param( 'rating', 5 );
+
+		$response = $sut->create_item( $request );
+
+		$this->assertSame( 201, $response->get_status() );
+		$this->assertSame( '1', get_comment_meta( $response->get_data()['id'], 'verified', true ), 'The verified meta must be populated eagerly at creation time.' );
+	}
+
 	/**
 	 * Creates a product review through the controller.
 	 *
diff --git a/plugins/woocommerce/tests/php/includes/rest-api/Controllers/Version2/class-wc-rest-product-reviews-v2-controller-tests.php b/plugins/woocommerce/tests/php/includes/rest-api/Controllers/Version2/class-wc-rest-product-reviews-v2-controller-tests.php
index 967732f2281..2000d4c7de7 100644
--- a/plugins/woocommerce/tests/php/includes/rest-api/Controllers/Version2/class-wc-rest-product-reviews-v2-controller-tests.php
+++ b/plugins/woocommerce/tests/php/includes/rest-api/Controllers/Version2/class-wc-rest-product-reviews-v2-controller-tests.php
@@ -1,5 +1,6 @@
 <?php

+use Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper;
 use Automattic\WooCommerce\RestApi\UnitTests\Helpers\ProductHelper;

 /**
@@ -86,6 +87,36 @@ class WC_REST_Product_Reviews_V2_Controller_Test extends WC_REST_Unit_Test_case
 		$this->assertSame( 3, (int) get_comment_meta( $review_id, 'rating', true ) );
 	}

+	/**
+	 * @testdox Creating a review eagerly populates the verified-owner meta at creation time, not lazily during response preparation.
+	 */
+	public function test_create_item_populates_verified_meta(): void {
+		$product = ProductHelper::create_simple_product();
+		$order   = OrderHelper::create_order( 0, $product );
+		$order->set_billing_email( 'jane.smith@example.org' );
+		$order->set_status( 'completed' );
+		$order->save();
+
+		// Stub prepare_item_for_response so it cannot backfill the meta as a side effect.
+		$sut = new class() extends WC_REST_Product_Reviews_V2_Controller {
+			public function prepare_item_for_response( $review, $request ) { // phpcs:ignore Squiz.Commenting.FunctionComment.Missing
+				return rest_ensure_response( array( 'id' => (int) $review->comment_ID ) );
+			}
+		};
+
+		$request = new WP_REST_Request( 'POST', '/wc/v2/products/' . $product->get_id() . '/reviews' );
+		$request->set_param( 'product_id', $product->get_id() );
+		$request->set_param( 'review', 'Great product, would buy again.' );
+		$request->set_param( 'name', 'Jane Smith' );
+		$request->set_param( 'email', 'jane.smith@example.org' );
+		$request->set_param( 'rating', 5 );
+
+		$response = $sut->create_item( $request );
+
+		$this->assertSame( 201, $response->get_status() );
+		$this->assertSame( '1', get_comment_meta( $response->get_data()['id'], 'verified', true ), 'The verified meta must be populated eagerly at creation time.' );
+	}
+
 	/**
 	 * @testdox Creating a review as a shop manager strips markup that user role cannot post.
 	 */
diff --git a/plugins/woocommerce/tests/php/includes/rest-api/Controllers/Version3/class-wc-rest-product-reviews-controller-tests.php b/plugins/woocommerce/tests/php/includes/rest-api/Controllers/Version3/class-wc-rest-product-reviews-controller-tests.php
index 90ea473cdd8..75f7762bfa7 100644
--- a/plugins/woocommerce/tests/php/includes/rest-api/Controllers/Version3/class-wc-rest-product-reviews-controller-tests.php
+++ b/plugins/woocommerce/tests/php/includes/rest-api/Controllers/Version3/class-wc-rest-product-reviews-controller-tests.php
@@ -593,6 +593,47 @@ class WC_REST_Product_Reviews_Controller_Tests extends WC_REST_Unit_Test_Case {
 		$this->assertEquals( 4, $destination->get_average_rating() );
 	}

+	/**
+	 * @testdox Creating a review eagerly populates the verified-owner meta at creation time, not lazily during response preparation.
+	 * @testWith [false]
+	 *           [true]
+	 *
+	 * @param bool $include_verified Whether to include the verified parameter in the request.
+	 */
+	public function test_create_item_populates_verified_meta( bool $include_verified ): void {
+		$product = ProductHelper::create_simple_product();
+		$order   = OrderHelper::create_order( 0, $product );
+		$order->set_billing_email( 'jane.smith@example.org' );
+		$order->set_status( 'completed' );
+		$order->save();
+
+		// Stub prepare_item_for_response so it cannot backfill the meta as a side effect.
+		$sut = new class() extends WC_REST_Product_Reviews_Controller {
+			public function prepare_item_for_response( $review, $request ) { // phpcs:ignore Squiz.Commenting.FunctionComment.Missing
+				return rest_ensure_response( array( 'id' => (int) $review->comment_ID ) );
+			}
+		};
+
+		$body = array(
+			'product_id'     => $product->get_id(),
+			'review'         => $include_verified ? 'Verified by the caller.' : 'Great product, would buy again.',
+			'reviewer'       => 'Jane Smith',
+			'reviewer_email' => 'jane.smith@example.org',
+			'rating'         => 5,
+		);
+		if ( $include_verified ) {
+			$body['verified'] = true;
+		}
+
+		$request = new WP_REST_Request( 'POST', '/wc/v3/products/reviews' );
+		$request->set_body_params( $body );
+
+		$response = $sut->create_item( $request );
+
+		$this->assertSame( 201, $response->get_status() );
+		$this->assertSame( '1', get_comment_meta( $response->get_data()['id'], 'verified', true ), 'The verified meta must be populated eagerly at creation time.' );
+	}
+
 	/**
 	 * Creates two products and a review that can be moved between them.
 	 *