Commit 4c88743167e for woocommerce
commit 4c88743167e40340cb19b76bb683f51f8f1850b3
Author: Albert Juhé Lluveras <contact@albertjuhe.com>
Date: Wed Jul 8 14:39:41 2026 +0200
Remove Sample badge from products generated during the CYS flow (#66322)
* Remove Sample badge on product update
* Add changelog
* Revert "Remove Sample badge on product update"
This reverts commit 00c2582767d27c6ad3b5f7649772fdc06954eda0.
* Remove the Sample badge completely
* Completely remove OnboardingProducts.php and UpdateProducts.php
* Enhancements
* Update PHPStan
* Use wc_deprecated_function() instead of _deprecated_function()
* Remove cleanup migration for _headstart_post meta
diff --git a/plugins/woocommerce/changelog/fix-51573-remove-sample-badge-on-product-update b/plugins/woocommerce/changelog/fix-51573-remove-sample-badge-on-product-update
new file mode 100644
index 00000000000..64110108bc3
--- /dev/null
+++ b/plugins/woocommerce/changelog/fix-51573-remove-sample-badge-on-product-update
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Remove Sample badge from sample products generated during the CYS flow
diff --git a/plugins/woocommerce/includes/admin/list-tables/class-wc-admin-list-table-products.php b/plugins/woocommerce/includes/admin/list-tables/class-wc-admin-list-table-products.php
index 6591e4c2463..fad7a879c64 100644
--- a/plugins/woocommerce/includes/admin/list-tables/class-wc-admin-list-table-products.php
+++ b/plugins/woocommerce/includes/admin/list-tables/class-wc-admin-list-table-products.php
@@ -58,7 +58,6 @@ class WC_Admin_List_Table_Products extends WC_Admin_List_Table {
add_filter( 'views_edit-product', array( $this, 'product_views' ) );
add_filter( 'get_search_query', array( $this, 'search_label' ) );
add_filter( 'posts_clauses', array( $this, 'posts_clauses' ), 10, 2 );
- add_action( 'manage_product_posts_custom_column', array( $this, 'add_sample_product_badge' ), 9, 2 );
// Use hooks to prime various caches and improve products page performance.
add_action( 'load-edit.php', array( $this, 'prime_status_counts_cache' ) );
@@ -841,13 +840,10 @@ class WC_Admin_List_Table_Products extends WC_Admin_List_Table {
* @param int $post_id Post ID.
*
* @since 8.8.0
+ * @deprecated 11.1.0
*/
public function add_sample_product_badge( $column_name, $post_id ) {
- $is_sample_product = 'product' === get_post_type( $post_id ) && get_post_meta( $post_id, '_headstart_post', true );
-
- if ( $is_sample_product && 'name' === $column_name ) {
- echo '<span class="sample-product-badge" style="margin-right: 6px;border-radius: 4px; background: #F6F7F7; padding: 4px; color: #3C434A;font-size: 12px;font-style: normal;font-weight: 400;line-height: 16px; height: 24px;">' . esc_html__( 'Sample', 'woocommerce' ) . '</span>';
- }
+ wc_deprecated_function( __METHOD__, '11.1.0' );
}
/**
diff --git a/plugins/woocommerce/phpstan-baseline.neon b/plugins/woocommerce/phpstan-baseline.neon
index 80278e498e7..e3eda14b1e6 100644
--- a/plugins/woocommerce/phpstan-baseline.neon
+++ b/plugins/woocommerce/phpstan-baseline.neon
@@ -38817,12 +38817,6 @@ parameters:
count: 1
path: src/Admin/API/OnboardingProductTypes.php
- -
- message: '#^Method Automattic\\WooCommerce\\Admin\\API\\OnboardingProducts\:\:create_products\(\) has invalid return type Automattic\\WooCommerce\\Admin\\API\\WP_Error\.$#'
- identifier: class.notFound
- count: 1
- path: src/Admin/API/OnboardingProducts.php
-
-
message: '#^Method Automattic\\WooCommerce\\Admin\\API\\OnboardingProducts\:\:create_products\(\) has invalid return type Automattic\\WooCommerce\\Admin\\API\\WP_REST_Response\.$#'
identifier: class.notFound
@@ -38830,9 +38824,9 @@ parameters:
path: src/Admin/API/OnboardingProducts.php
-
- message: '#^Method Automattic\\WooCommerce\\Admin\\API\\OnboardingProducts\:\:create_products\(\) should return Automattic\\WooCommerce\\Admin\\API\\WP_Error\|Automattic\\WooCommerce\\Admin\\API\\WP_REST_Response but returns WP_REST_Response\.$#'
+ message: '#^Method Automattic\\WooCommerce\\Admin\\API\\OnboardingProducts\:\:create_products\(\) should return Automattic\\WooCommerce\\Admin\\API\\WP_REST_Response but returns WP_REST_Response\.$#'
identifier: return.type
- count: 2
+ count: 1
path: src/Admin/API/OnboardingProducts.php
-
@@ -38854,7 +38848,7 @@ parameters:
path: src/Admin/API/OnboardingProducts.php
-
- message: '#^PHPDoc tag @extends has invalid value \(WC_REST_Data_Controller\)\: Unexpected token "\\n ", expected ''\<'' at offset 88 on line 5$#'
+ message: '#^PHPDoc tag @extends has invalid value \(WC_REST_Data_Controller\)\: Unexpected token "\\n \* ", expected ''\<'' at offset 90 on line 5$#'
identifier: phpDoc.parseError
count: 1
path: src/Admin/API/OnboardingProducts.php
@@ -46605,18 +46599,6 @@ parameters:
count: 2
path: src/Admin/Features/OnboardingTasks/Tasks/Payments.php
- -
- message: '#^Call to method get_id\(\) on an unknown class Automattic\\WooCommerce\\Admin\\Features\\OnboardingTasks\\Tasks\\WC_Product\.$#'
- identifier: class.notFound
- count: 1
- path: src/Admin/Features/OnboardingTasks/Tasks/Products.php
-
- -
- message: '#^Call to method get_meta\(\) on an unknown class Automattic\\WooCommerce\\Admin\\Features\\OnboardingTasks\\Tasks\\WC_Product\.$#'
- identifier: class.notFound
- count: 1
- path: src/Admin/Features/OnboardingTasks/Tasks/Products.php
-
-
message: '#^Call to method get_status\(\) on an unknown class Automattic\\WooCommerce\\Admin\\Features\\OnboardingTasks\\Tasks\\WC_Product\.$#'
identifier: class.notFound
@@ -46653,12 +46635,6 @@ parameters:
count: 1
path: src/Admin/Features/OnboardingTasks/Tasks/Products.php
- -
- message: '#^Parameter \$product of method Automattic\\WooCommerce\\Admin\\Features\\OnboardingTasks\\Tasks\\Products\:\:is_valid_product\(\) has invalid type Automattic\\WooCommerce\\Admin\\Features\\OnboardingTasks\\Tasks\\WC_Product\.$#'
- identifier: class.notFound
- count: 1
- path: src/Admin/Features/OnboardingTasks/Tasks/Products.php
-
-
message: '#^Parameter \$product of method Automattic\\WooCommerce\\Admin\\Features\\OnboardingTasks\\Tasks\\Products\:\:maybe_set_has_product_transient\(\) has invalid type Automattic\\WooCommerce\\Admin\\Features\\OnboardingTasks\\Tasks\\WC_Product\.$#'
identifier: class.notFound
@@ -49275,30 +49251,6 @@ parameters:
count: 1
path: src/Autoloader.php
- -
- message: '#^Cannot call method date\(\) on WC_DateTime\|null\.$#'
- identifier: method.nonObject
- count: 2
- path: src/Blocks/AIContent/UpdateProducts.php
-
- -
- message: '#^Parameter \#1 \$price of method WC_Product\:\:set_price\(\) expects string, int given\.$#'
- identifier: argument.type
- count: 1
- path: src/Blocks/AIContent/UpdateProducts.php
-
- -
- message: '#^Parameter \#1 \$price of method WC_Product\:\:set_regular_price\(\) expects string, int given\.$#'
- identifier: argument.type
- count: 1
- path: src/Blocks/AIContent/UpdateProducts.php
-
- -
- message: '#^Parameter \#1 \$var of function count expects array\|Countable, array\|null given\.$#'
- identifier: argument.type
- count: 2
- path: src/Blocks/AIContent/UpdateProducts.php
-
-
message: '#^Default value of the parameter \#1 \$classes \(string\) of method Automattic\\WooCommerce\\Blocks\\Assets\:\:add_theme_admin_body_class\(\) is incompatible with type array\.$#'
identifier: parameter.defaultValue
@@ -56931,7 +56883,6 @@ parameters:
count: 1
path: src/Internal/Admin/Logging/LogHandlerFileV2.php
-
-
message: '#^Call to protected method prepare_column_headers\(\) of class WC_Admin_Log_Table_List\.$#'
identifier: method.protected
diff --git a/plugins/woocommerce/src/Admin/API/OnboardingProducts.php b/plugins/woocommerce/src/Admin/API/OnboardingProducts.php
index b5639a1041e..0cf22fa8a06 100644
--- a/plugins/woocommerce/src/Admin/API/OnboardingProducts.php
+++ b/plugins/woocommerce/src/Admin/API/OnboardingProducts.php
@@ -1,21 +1,20 @@
<?php
/**
- * REST API Onboarding Themes Controller
+ * REST API Onboarding Products Controller
*
- * Handles requests to install and activate themes.
+ * Handles requests to create dummy products for the Customize Your Store flow.
*/
namespace Automattic\WooCommerce\Admin\API;
-use Automattic\WooCommerce\Blocks\AIContent\UpdateProducts;
-
defined( 'ABSPATH' ) || exit;
/**
- * Onboarding Themes Controller.
+ * Onboarding Products Controller.
*
* @internal
* @extends WC_REST_Data_Controller
+ * @deprecated 11.1.0
*/
class OnboardingProducts extends \WC_REST_Data_Controller {
/**
@@ -53,27 +52,22 @@ class OnboardingProducts extends \WC_REST_Data_Controller {
/**
* Create products.
*
+ * @deprecated 11.1.0 Sample product creation for the Customize Your Store flow has been removed.
+ *
* @param WP_REST_Request $request Full details about the request.
- * @return WP_Error|WP_REST_Response
+ * @return WP_REST_Response
*/
public function create_products( $request ) {
- $update_products = new UpdateProducts();
-
- $products = $update_products->fetch_dummy_products_to_update();
-
- if ( is_wp_error( $products ) ) {
- return rest_ensure_response( array( 'success' => false ) );
- }
-
- return rest_ensure_response( array( 'success' => true ) );
+ wc_deprecated_function( __METHOD__, '11.1.0' );
+ return rest_ensure_response( array( 'success' => false ) );
}
/**
- * Check if a given request has access to manage themes.
+ * Check if a given request has access to create dummy products.
*
* @param WP_REST_Request $request Full details about the request.
- * @return WP_Error|boolean
+ * @return WP_Error|bool
*/
public function update_item_permissions_check( $request ) {
if ( ! current_user_can( 'manage_options' ) ) {
@@ -81,5 +75,4 @@ class OnboardingProducts extends \WC_REST_Data_Controller {
}
return true;
}
-
}
diff --git a/plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/Products.php b/plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/Products.php
index 5075f4d9e8c..59ce45eb436 100644
--- a/plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/Products.php
+++ b/plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/Products.php
@@ -188,7 +188,7 @@ class Products extends Task {
* @param WC_Product $product Product object.
*/
public function maybe_set_has_product_transient( $product_id, $product ) {
- if ( ! $this->has_previously_completed() && $this->is_valid_product( $product ) ) {
+ if ( ! $this->has_previously_completed() && ProductStatus::PUBLISH === $product->get_status() ) {
set_transient( self::HAS_PRODUCT_TRANSIENT, 'yes' );
$this->possibly_track_completion();
}
@@ -259,18 +259,6 @@ class Products extends Task {
}
}
- /**
- * Check if the product qualifies as a user created product.
- *
- * @param WC_Product $product Product object.
- * @return bool
- */
- private function is_valid_product( $product ) {
- return ProductStatus::PUBLISH === $product->get_status() &&
- ( ! $product->get_meta( '_headstart_post' ) ||
- get_post_meta( $product->get_id(), '_edit_last', true ) );
- }
-
/**
* Check if the store has any user created published products.
*
@@ -282,56 +270,8 @@ class Products extends Task {
return 'yes' === $product_exists;
}
- global $wpdb;
-
- /*
- * Check if any valid products exist and return 'yes' or 'no'
- * A valid product must:
- * 1. Be a published product post type
- * 2. Meet one of these conditions:
- * - Have been edited by a user (_edit_last meta exists), OR
- * - Not have _headstart_post meta, OR
- * - Have _headstart_post meta but it's NULL
- */
- $value = $wpdb->get_var(
- $wpdb->prepare(
- "SELECT IF(
- EXISTS (
- SELECT 1 FROM {$wpdb->posts} p
- WHERE p.post_type = %s
- AND p.post_status = %s
- AND (
- EXISTS (
- SELECT 1 FROM {$wpdb->postmeta} pm
- WHERE pm.post_id = p.ID
- AND pm.meta_key = %s
- )
- OR
- NOT EXISTS (
- SELECT 1 FROM {$wpdb->postmeta} pm
- WHERE pm.post_id = p.ID
- AND pm.meta_key = %s
- )
- OR
- EXISTS (
- SELECT 1 FROM {$wpdb->postmeta} pm
- WHERE pm.post_id = p.ID
- AND pm.meta_key = %s
- AND pm.meta_value = ''
- )
- )
- LIMIT 1
- ),
- 'yes', 'no'
- )",
- 'product',
- ProductStatus::PUBLISH,
- '_edit_last',
- '_headstart_post',
- '_headstart_post'
- )
- );
-
+ $counts = wp_count_posts( 'product' );
+ $value = isset( $counts->publish ) && $counts->publish > 0 ? 'yes' : 'no';
set_transient( self::HAS_PRODUCT_TRANSIENT, $value );
return 'yes' === $value;
}
diff --git a/plugins/woocommerce/src/Blocks/AIContent/UpdateProducts.php b/plugins/woocommerce/src/Blocks/AIContent/UpdateProducts.php
index e4ceb8bf196..9678183d1ba 100644
--- a/plugins/woocommerce/src/Blocks/AIContent/UpdateProducts.php
+++ b/plugins/woocommerce/src/Blocks/AIContent/UpdateProducts.php
@@ -2,239 +2,11 @@
namespace Automattic\WooCommerce\Blocks\AIContent;
-use WP_Error;
-
/**
- * This class is used to create dummy products for the Customize Your Store flow.
- * Even if it is in the AI Content namespace, it is not used for AI content generation.
+ * This class was used to create dummy products for the Customize Your Store flow.
*
* @internal
+ * @deprecated This class can't be removed due https://github.com/woocommerce/woocommerce/issues/52311.
*/
class UpdateProducts {
-
- /**
- * The dummy products.
- */
- const DUMMY_PRODUCTS = [
- [
- 'title' => 'Vintage Typewriter',
- 'image' => 'assets/images/pattern-placeholders/writing-typing-keyboard-technology-white-vintage.jpg',
- 'description' => 'A hit spy novel or a love letter? Anything you type using this vintage typewriter from the 20s is bound to make a mark.',
- 'price' => 90,
- ],
- [
- 'title' => 'Leather-Clad Leisure Chair',
- 'image' => 'assets/images/pattern-placeholders/table-wood-house-chair-floor-window.jpg',
- 'description' => 'Sit back and relax in this comfy designer chair. High-grain leather and steel frame add luxury to your your leisure.',
- 'price' => 249,
- ],
- [
- 'title' => 'Black and White',
- 'image' => 'assets/images/pattern-placeholders/white-black-black-and-white-photograph-monochrome-photography.jpg',
- 'description' => 'This 24" x 30" high-quality print just exudes summer. Hang it on the wall and forget about the world outside.',
- 'price' => 115,
- ],
- [
- 'title' => '3-Speed Bike',
- 'image' => 'assets/images/pattern-placeholders/road-sport-vintage-wheel-retro-old.jpg',
- 'description' => 'Zoom through the streets on this premium 3-speed bike. Manufactured and assembled in Germany in the 80s.',
- 'price' => 115,
- ],
- [
- 'title' => 'Hi-Fi Headphones',
- 'image' => 'assets/images/pattern-placeholders/man-person-music-black-and-white-white-photography.jpg',
- 'description' => 'Experience your favorite songs in a new way with these premium hi-fi headphones.',
- 'price' => 125,
- ],
- [
- 'title' => 'Retro Glass Jug (330 ml)',
- 'image' => 'assets/images/pattern-placeholders/drinkware-liquid-tableware-dishware-bottle-fluid.jpg',
- 'description' => 'Thick glass and a classic silhouette make this jug a must-have for any retro-inspired kitchen.',
- 'price' => 115,
- ],
- ];
-
-
- /**
- * Return all dummy products that were not modified by the store owner.
- *
- * @return array|WP_Error An array with the dummy products that need to have their content updated by AI.
- */
- public function fetch_dummy_products_to_update() {
- $real_products = $this->fetch_product_ids();
- $real_products_count = count( $real_products );
-
- if ( is_array( $real_products ) && $real_products_count > 6 ) {
- return array(
- 'product_content' => array(),
- );
- }
-
- $dummy_products = $this->fetch_product_ids( 'dummy' );
- $dummy_products_count = count( $dummy_products );
- $products_to_create = max( 0, 6 - $real_products_count - $dummy_products_count );
- while ( $products_to_create > 0 ) {
- $this->create_new_product( self::DUMMY_PRODUCTS[ $products_to_create - 1 ] );
- --$products_to_create;
- }
-
- // Identify dummy products that need to have their content updated.
- $dummy_products_ids = $this->fetch_product_ids( 'dummy' );
- if ( ! is_array( $dummy_products_ids ) ) {
- return new \WP_Error( 'failed_to_fetch_dummy_products', __( 'Failed to fetch dummy products.', 'woocommerce' ) );
- }
-
- $dummy_products = array_map(
- function ( $product ) {
- return wc_get_product( $product->ID );
- },
- $dummy_products_ids
- );
-
- $dummy_products_to_update = [];
- foreach ( $dummy_products as $dummy_product ) {
- if ( ! $dummy_product instanceof \WC_Product ) {
- continue;
- }
-
- $should_update_dummy_product = $this->should_update_dummy_product( $dummy_product );
-
- if ( $should_update_dummy_product ) {
- $dummy_products_to_update[] = $dummy_product;
- }
- }
-
- return $dummy_products_to_update;
- }
-
- /**
- * Verify if the dummy product should have its content generated and managed by AI.
- *
- * @param \WC_Product $dummy_product The dummy product.
- *
- * @return bool
- */
- public function should_update_dummy_product( $dummy_product ): bool {
- $date_created = $dummy_product->get_date_created();
- $date_modified = $dummy_product->get_date_modified();
-
- if ( ! $date_created instanceof \WC_DateTime || ! $date_modified instanceof \WC_DateTime ) {
- return false;
- }
-
- $formatted_date_created = $dummy_product->get_date_created()->date( 'Y-m-d H:i:s' );
- $formatted_date_modified = $dummy_product->get_date_modified()->date( 'Y-m-d H:i:s' );
-
- $timestamp_created = strtotime( $formatted_date_created );
- $timestamp_modified = strtotime( $formatted_date_modified );
- $timestamp_current = time();
-
- $dummy_product_recently_modified = abs( $timestamp_current - $timestamp_modified ) < 10;
- $dummy_product_not_modified = abs( $timestamp_modified - $timestamp_created ) < 60;
-
- if ( $dummy_product_not_modified || $dummy_product_recently_modified ) {
- return true;
- }
-
- return false;
- }
-
- /**
- * Creates a new product and assigns the _headstart_post meta to it.
- *
- * @param array $product_data The product data.
- *
- * @return bool|int|\WP_Error
- */
- public function create_new_product( $product_data ) {
- $product = new \WC_Product();
- $image_src = plugins_url( $product_data['image'], dirname( __DIR__, 2 ) );
- $image_alt = $product_data['title'];
- $product_image_id = $this->product_image_upload( $product->get_id(), $image_src, $image_alt );
-
- $saved_product = $this->product_update( $product, $product_image_id, $product_data['title'], $product_data['description'], $product_data['price'] );
-
- if ( is_wp_error( $saved_product ) ) {
- return $saved_product;
- }
-
- return update_post_meta( $saved_product, '_headstart_post', true );
- }
-
- /**
- * Return all existing products that have the _headstart_post meta assigned to them.
- *
- * @param string $type The type of products to fetch.
- *
- * @return array|null
- */
- public function fetch_product_ids( string $type = 'user_created' ) {
- global $wpdb;
-
- if ( 'user_created' === $type ) {
- return $wpdb->get_results( $wpdb->prepare( "SELECT ID FROM {$wpdb->posts} WHERE ID NOT IN ( SELECT p.ID FROM {$wpdb->posts} p JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id WHERE pm.meta_key = %s AND p.post_type = 'product' AND p.post_status = 'publish' ) AND post_type = 'product' AND post_status = 'publish' LIMIT 6", '_headstart_post' ) );
- }
-
- return $wpdb->get_results( $wpdb->prepare( "SELECT p.ID FROM {$wpdb->posts} p JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id WHERE pm.meta_key = %s AND p.post_type = 'product' AND p.post_status = 'publish'", '_headstart_post' ) );
- }
-
- /**
- * Upload the image for the product.
- *
- * @param int $product_id The product ID.
- * @param string $image_src The image source.
- * @param string $image_alt The image alt.
- *
- * @return int|string|WP_Error
- */
- private function product_image_upload( $product_id, $image_src, $image_alt ) {
- require_once ABSPATH . 'wp-admin/includes/media.php';
- require_once ABSPATH . 'wp-admin/includes/file.php';
- require_once ABSPATH . 'wp-admin/includes/image.php';
-
- // Since the media_sideload_image function is expensive and can take longer to complete
- // the process of downloading the external image and uploading it to the media library,
- // here we are increasing the time limit to avoid any issues.
- set_time_limit( 150 );
- wp_raise_memory_limit( 'image' );
-
- return media_sideload_image( $image_src, $product_id, $image_alt, 'id' );
- }
-
- /**
- * Update the product with the new content.
- *
- * @param \WC_Product $product The product.
- * @param int|string|WP_Error $product_image_id The product image ID.
- * @param string $product_title The product title.
- * @param string $product_description The product description.
- * @param int $product_price The product price.
- *
- * @return int|\WP_Error
- */
- private function product_update( $product, $product_image_id, $product_title, $product_description, $product_price ) {
- if ( ! $product instanceof \WC_Product ) {
- return new WP_Error( 'invalid_product', __( 'Invalid product.', 'woocommerce' ) );
- }
-
- if ( ! is_wp_error( $product_image_id ) ) {
- $product->set_image_id( $product_image_id );
- } else {
- wc_get_logger()->warning(
- sprintf(
- // translators: %s is a generated error message.
- __( 'The image upload failed: "%s", creating the product without image', 'woocommerce' ),
- $product_image_id->get_error_message()
- ),
- );
- }
- $product->set_name( $product_title );
- $product->set_description( $product_description );
- $product->set_price( $product_price );
- $product->set_regular_price( $product_price );
- $product->set_slug( sanitize_title( $product_title ) );
- $product->save();
-
- return $product->get_id();
- }
}