Commit 1778ca309ab for woocommerce
commit 1778ca309ab960f7708cf8ad8fbeeae6fe3f7d43
Author: Vincent Borgers <88669109+VincentBorgers@users.noreply.github.com>
Date: Mon Oct 5 12:10:45 2026 +0200
Fix product search for users who can read but not edit private products (#69362)
* Fix product search for users who can read but not edit private products
* Add changelog entry for private product search fix
* Update docblock
* Make sure user in test has no edit_private_products capability
---------
Co-authored-by: Albert Juhé Lluveras <contact@albertjuhe.com>
diff --git a/plugins/woocommerce/changelog/31733-fix-private-product-search-capability b/plugins/woocommerce/changelog/31733-fix-private-product-search-capability
new file mode 100644
index 00000000000..f5c9db799c9
--- /dev/null
+++ b/plugins/woocommerce/changelog/31733-fix-private-product-search-capability
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Show private products in admin product searches to users who can read private products but not edit them.
diff --git a/plugins/woocommerce/includes/data-stores/class-wc-product-data-store-cpt.php b/plugins/woocommerce/includes/data-stores/class-wc-product-data-store-cpt.php
index a054a78e43c..3f58cf54324 100644
--- a/plugins/woocommerce/includes/data-stores/class-wc-product-data-store-cpt.php
+++ b/plugins/woocommerce/includes/data-stores/class-wc-product-data-store-cpt.php
@@ -2051,7 +2051,7 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
* @param string $term Search term.
* @param string $type Type of product.
* @param bool $include_variations Include variations in search or not.
- * @param bool $all_statuses Should we search all statuses or limit to published.
+ * @param bool $all_statuses True searches every status. False searches published products, plus private products when the current user can read them.
* @param null|int $limit Limit returned results. @since 3.5.0.
* @param null|array $include Keep specific results. @since 3.6.0.
* @param null|array $exclude Discard specific results. @since 3.6.0.
@@ -2086,7 +2086,7 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
*/
$post_statuses = apply_filters(
'woocommerce_search_products_post_statuses',
- current_user_can( 'edit_private_products' ) ? array( 'private', 'publish' ) : array( 'publish' )
+ current_user_can( 'read_private_products' ) ? array( 'private', 'publish' ) : array( 'publish' )
);
// See if search term contains OR keywords.
diff --git a/plugins/woocommerce/phpcs.xml b/plugins/woocommerce/phpcs.xml
index db630ac8883..4bddbc1c73c 100644
--- a/plugins/woocommerce/phpcs.xml
+++ b/plugins/woocommerce/phpcs.xml
@@ -133,6 +133,7 @@
<element key="15" value="manage_woocommerce"/>
<element key="16" value="manage_product_terms"/>
<element key="17" value="view_woocommerce_reports"/>
+ <element key="18" value="read_private_products"/>
</property>
</properties>
</rule>
diff --git a/plugins/woocommerce/tests/php/includes/data-stores/class-wc-product-data-store-cpt-test.php b/plugins/woocommerce/tests/php/includes/data-stores/class-wc-product-data-store-cpt-test.php
index 8a76b6b050d..62d239c6d61 100644
--- a/plugins/woocommerce/tests/php/includes/data-stores/class-wc-product-data-store-cpt-test.php
+++ b/plugins/woocommerce/tests/php/includes/data-stores/class-wc-product-data-store-cpt-test.php
@@ -326,6 +326,26 @@ class WC_Product_Data_Store_CPT_Test extends WC_Unit_Test_Case {
}
}
+ /**
+ * @testdox Search should include private products for users who can read them but not edit them.
+ */
+ public function test_search_products_includes_private_products_for_users_who_can_read_them(): void {
+ $product = $this->create_search_test_product( 'Searchable private product', 'private' );
+ $user_id = self::factory()->user->create( array( 'role' => 'customer' ) );
+ wp_set_current_user( $user_id );
+
+ $data_store = WC_Data_Store::load( 'product' );
+
+ $this->assertNotContains( $product->get_id(), $data_store->search_products( 'Searchable private product', '', false, false ), 'Private product should not be returned to users who cannot read private products' );
+
+ wp_get_current_user()->add_cap( 'read_private_products' );
+
+ $this->assertTrue( current_user_can( 'read_private_products' ), 'The user under test should be able to read private products' );
+ $this->assertFalse( current_user_can( 'edit_private_products' ), 'Granting read access should leave the user unable to edit private products' );
+
+ $this->assertContains( $product->get_id(), $data_store->search_products( 'Searchable private product', '', false, false ), 'Private product should be returned to users who can read private products but not edit them' );
+ }
+
/**
* Ensure product rating counts are calculated correctly.
*