Commit c6dd7b44a6 for woocommerce

commit c6dd7b44a6f0d8476a543a88b5de449c11aebb95
Author: Taha Paksu <3295+tpaksu@users.noreply.github.com>
Date:   Tue Feb 24 19:32:49 2026 +0300

    Update store task list shipping plugin recommendations per country (#63379)

diff --git a/plugins/woocommerce/src/Admin/API/ShippingPartnerSuggestions.php b/plugins/woocommerce/src/Admin/API/ShippingPartnerSuggestions.php
index 0c5c8c2a95..ec56e77bcd 100644
--- a/plugins/woocommerce/src/Admin/API/ShippingPartnerSuggestions.php
+++ b/plugins/woocommerce/src/Admin/API/ShippingPartnerSuggestions.php
@@ -54,7 +54,6 @@ class ShippingPartnerSuggestions extends \WC_REST_Data_Controller {
 				'schema' => array( $this, 'get_suggestions_schema' ),
 			)
 		);
-
 	}

 	/**
@@ -154,40 +153,40 @@ class ShippingPartnerSuggestions extends \WC_REST_Data_Controller {
 				),
 			),
 			'properties' => array(
-				'name'              => array(
+				'name'                    => array(
 					'description' => __( 'Plugin name.', 'woocommerce' ),
 					'type'        => 'string',
 					'required'    => true,
 					'context'     => array( 'view', 'edit' ),
 					'readonly'    => true,
 				),
-				'slug'              => array(
+				'slug'                    => array(
 					'description' => __( 'Plugin slug used in https://wordpress.org/plugins/{slug}.', 'woocommerce' ),
 					'type'        => 'string',
 					'context'     => array( 'view', 'edit' ),
 					'readonly'    => true,
 				),
-				'layout_row'        => $layout_def,
-				'layout_column'     => $layout_def,
-				'description'       => array(
+				'layout_row'              => $layout_def,
+				'layout_column'           => $layout_def,
+				'description'             => array(
 					'description' => __( 'Description', 'woocommerce' ),
 					'type'        => 'string',
 					'context'     => array( 'view', 'edit' ),
 					'readonly'    => true,
 				),
-				'learn_more_link'   => array(
+				'learn_more_link'         => array(
 					'description' => __( 'Learn more link .', 'woocommerce' ),
 					'type'        => 'string',
 					'context'     => array( 'view', 'edit' ),
 					'readonly'    => true,
 				),
-				'is_visible'        => array(
+				'is_visible'              => array(
 					'description' => __( 'Suggestion visibility.', 'woocommerce' ),
 					'type'        => 'boolean',
 					'context'     => array( 'view', 'edit' ),
 					'readonly'    => true,
 				),
-				'available_layouts' => array(
+				'available_layouts'       => array(
 					'description' => __( 'Available layouts -- single, dual, or both', 'woocommerce' ),
 					'type'        => 'array',
 					'items'       => array(
@@ -197,6 +196,15 @@ class ShippingPartnerSuggestions extends \WC_REST_Data_Controller {
 					'context'     => array( 'view', 'edit' ),
 					'readonly'    => true,
 				),
+				'countries_where_primary' => array(
+					'description' => __( 'Countries where this partner should appear first.', 'woocommerce' ),
+					'type'        => 'array',
+					'items'       => array(
+						'type' => 'string',
+					),
+					'context'     => array( 'view', 'edit' ),
+					'readonly'    => true,
+				),
 			),
 		);

diff --git a/plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/Shipping.php b/plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/Shipping.php
index f06534b87c..6b2a501118 100644
--- a/plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/Shipping.php
+++ b/plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/Shipping.php
@@ -116,7 +116,7 @@ class Shipping extends Task {
 				return true;
 			}

-			return in_array( $store_country, array( 'CA', 'AU', 'NZ', 'SG', 'HK', 'GB', 'ES', 'IT', 'DE', 'FR', 'CL', 'AR', 'PE', 'BR', 'UY', 'GT', 'NL', 'AT', 'BE' ), true );
+			return in_array( $store_country, array( 'US', 'CA', 'AU', 'NZ', 'SG', 'HK', 'GB', 'ES', 'IT', 'DE', 'FR', 'MX', 'CO', 'CL', 'AR', 'PE', 'BR', 'UY', 'GT', 'NL', 'AT', 'BE' ), true );
 		}

 		return self::has_physical_products();
diff --git a/plugins/woocommerce/src/Admin/Features/ShippingPartnerSuggestions/DefaultShippingPartners.php b/plugins/woocommerce/src/Admin/Features/ShippingPartnerSuggestions/DefaultShippingPartners.php
index 39ddc01abd..ec803289ca 100644
--- a/plugins/woocommerce/src/Admin/Features/ShippingPartnerSuggestions/DefaultShippingPartners.php
+++ b/plugins/woocommerce/src/Admin/Features/ShippingPartnerSuggestions/DefaultShippingPartners.php
@@ -45,15 +45,15 @@ class DefaultShippingPartners {

 		return array(
 			array(
-				'id'                => 'woocommerce-shipstation-integration',
-				'name'              => 'ShipStation',
-				'slug'              => 'woocommerce-shipstation-integration',
-				'description'       => __( 'Powerful yet easy-to-use solution:', 'woocommerce' ),
-				'layout_column'     => array(
+				'id'                      => 'woocommerce-shipstation-integration',
+				'name'                    => 'ShipStation',
+				'slug'                    => 'woocommerce-shipstation-integration',
+				'description'             => __( 'Powerful yet easy-to-use solution:', 'woocommerce' ),
+				'layout_column'           => array(
 					'image'    => $asset_base_url . 'shipstation-column.svg',
 					'features' => $column_layout_features,
 				),
-				'layout_row'        => array(
+				'layout_row'              => array(
 					'image'    => $asset_base_url . 'shipstation-row.svg',
 					'features' => array(
 						array(
@@ -84,52 +84,55 @@ class DefaultShippingPartners {
 						),
 					),
 				),
-				'learn_more_link'   => 'https://wordpress.org/plugins/woocommerce-shipstation-integration/',
-				'is_visible'        => array(
-					self::get_rules_for_countries( array( 'AU', 'CA', 'GB' ) ),
+				'learn_more_link'         => 'https://wordpress.org/plugins/woocommerce-shipstation-integration/',
+				'is_visible'              => array(
+					self::get_rules_for_countries( array( 'US', 'AU', 'NZ', 'CA', 'GB' ) ),
 				),
-				'available_layouts' => array( 'row', 'column' ),
+				'available_layouts'       => array( 'row', 'column' ),
+				'countries_where_primary' => array( 'NZ', 'CA', 'GB' ),
 			),
 			array(
-				'id'                => 'skydropx-cotizador-y-envios',
-				'name'              => 'Skydropx',
-				'slug'              => 'skydropx-cotizador-y-envios',
-				'layout_column'     => array(
+				'id'                      => 'skydropx-cotizador-y-envios',
+				'name'                    => 'Skydropx',
+				'slug'                    => 'skydropx-cotizador-y-envios',
+				'layout_column'           => array(
 					'image'    => $asset_base_url . 'skydropx-column.svg',
 					'features' => $column_layout_features,
 				),
-				'description'       => '',
-				'learn_more_link'   => 'https://wordpress.org/plugins/skydropx-cotizador-y-envios/',
-				'is_visible'        => array(
+				'description'             => '',
+				'learn_more_link'         => 'https://wordpress.org/plugins/skydropx-cotizador-y-envios/',
+				'is_visible'              => array(
 					self::get_rules_for_countries( array() ), // No countries eligible for SkydropX promotion at this time.
 				),
-				'available_layouts' => array( 'column' ),
+				'available_layouts'       => array( 'column' ),
+				'countries_where_primary' => array(),
 			),
 			array(
-				'id'                => 'envia',
-				'name'              => 'Envia',
-				'slug'              => '',
-				'description'       => '',
-				'layout_column'     => array(
+				'id'                      => 'envia',
+				'name'                    => 'Envia',
+				'slug'                    => '',
+				'description'             => '',
+				'layout_column'           => array(
 					'image'    => $asset_base_url . 'envia-column.svg',
 					'features' => $column_layout_features,
 				),
-				'learn_more_link'   => 'https://woocommerce.com/products/envia-shipping-and-fulfillment/',
-				'is_visible'        => array(
-					self::get_rules_for_countries( array( 'CL', 'AR', 'PE', 'BR', 'UY', 'GT' ) ),
+				'learn_more_link'         => 'https://woocommerce.com/products/envia-shipping-and-fulfillment/',
+				'is_visible'              => array(
+					self::get_rules_for_countries( array( 'MX', 'CO', 'CL', 'AR', 'PE', 'BR', 'UY', 'GT' ) ),
 				),
-				'available_layouts' => array( 'column' ),
+				'available_layouts'       => array( 'column' ),
+				'countries_where_primary' => array( 'MX', 'CO', 'CL', 'AR', 'PE', 'BR', 'UY', 'GT' ),
 			),
 			array(
-				'id'                => 'easyship-woocommerce-shipping-rates',
-				'name'              => 'Easyship',
-				'slug'              => 'easyship-woocommerce-shipping-rates',
-				'description'       => __( 'Simplified shipping with: ', 'woocommerce' ),
-				'layout_column'     => array(
+				'id'                      => 'easyship-woocommerce-shipping-rates',
+				'name'                    => 'Easyship',
+				'slug'                    => 'easyship-woocommerce-shipping-rates',
+				'description'             => __( 'Simplified shipping with: ', 'woocommerce' ),
+				'layout_column'           => array(
 					'image'    => $asset_base_url . 'easyship-column.svg',
 					'features' => $column_layout_features,
 				),
-				'layout_row'        => array(
+				'layout_row'              => array(
 					'image'    => $asset_base_url . 'easyship-row.svg',
 					'features' => array(
 						array(
@@ -157,22 +160,23 @@ class DefaultShippingPartners {
 						),
 					),
 				),
-				'learn_more_link'   => 'https://woocommerce.com/products/easyship-shipping-rates/',
-				'is_visible'        => array(
+				'learn_more_link'         => 'https://woocommerce.com/products/easyship-shipping-rates/',
+				'is_visible'              => array(
 					self::get_rules_for_countries( array( 'SG', 'HK', 'AU', 'NZ' ) ),
 				),
-				'available_layouts' => array( 'row', 'column' ),
+				'available_layouts'       => array( 'row', 'column' ),
+				'countries_where_primary' => array( 'SG', 'HK', 'AU' ),
 			),
 			array(
-				'id'                => 'packlink-pro-shipping',
-				'name'              => 'Packlink',
-				'slug'              => 'packlink-pro-shipping',
-				'description'       => __( 'Optimize your full shipping process:', 'woocommerce' ),
-				'layout_column'     => array(
+				'id'                      => 'packlink-pro-shipping',
+				'name'                    => 'Packlink',
+				'slug'                    => 'packlink-pro-shipping',
+				'description'             => __( 'Optimize your full shipping process:', 'woocommerce' ),
+				'layout_column'           => array(
 					'image'    => $asset_base_url . 'packlink-column.svg',
 					'features' => $column_layout_features,
 				),
-				'layout_row'        => array(
+				'layout_row'              => array(
 					'image'    => $asset_base_url . 'packlink-row.svg',
 					'features' => array(
 						array(
@@ -206,18 +210,19 @@ class DefaultShippingPartners {
 						),
 					),
 				),
-				'learn_more_link'   => 'https://wordpress.org/plugins/packlink-pro-shipping/',
-				'is_visible'        => array(
-					self::get_rules_for_countries( array( 'FR', 'DE', 'ES', 'IT' ) ),
+				'learn_more_link'         => 'https://wordpress.org/plugins/packlink-pro-shipping/',
+				'is_visible'              => array(
+					self::get_rules_for_countries( array( 'FR', 'DE', 'ES', 'IT', 'NL', 'AT', 'BE' ) ),
 				),
-				'available_layouts' => array( 'row', 'column' ),
+				'available_layouts'       => array( 'row', 'column' ),
+				'countries_where_primary' => array( 'FR', 'DE', 'ES', 'IT', 'NL', 'AT', 'BE' ),
 			),
 			array(
-				'id'                => 'woocommerce-shipping',
-				'name'              => 'WooCommerce Shipping',
-				'slug'              => 'woocommerce-shipping',
-				'description'       => __( 'Save time and money by printing your shipping labels right from your computer with WooCommerce Shipping. Try WooCommerce Shipping for free.', 'woocommerce' ),
-				'layout_column'     => array(
+				'id'                      => 'woocommerce-shipping',
+				'name'                    => 'WooCommerce Shipping',
+				'slug'                    => 'woocommerce-shipping',
+				'description'             => __( 'Save time and money by printing your shipping labels right from your computer with WooCommerce Shipping. Try WooCommerce Shipping for free.', 'woocommerce' ),
+				'layout_column'           => array(
 					'image'    => $asset_base_url . 'wcs-column.svg',
 					'features' => array(
 						array(
@@ -237,8 +242,8 @@ class DefaultShippingPartners {
 						),
 					),
 				),
-				'learn_more_link'   => 'https://woocommerce.com/products/shipping/',
-				'is_visible'        => array(
+				'learn_more_link'         => 'https://woocommerce.com/products/shipping/',
+				'is_visible'              => array(
 					self::get_rules_for_countries( array( 'US' ) ),
 					(object) array(
 						'type'    => 'not',
@@ -250,7 +255,8 @@ class DefaultShippingPartners {
 						),
 					),
 				),
-				'available_layouts' => array( 'column' ),
+				'available_layouts'       => array( 'column' ),
+				'countries_where_primary' => array( 'US' ),
 			),
 		);
 	}
diff --git a/plugins/woocommerce/src/Admin/Features/ShippingPartnerSuggestions/ShippingPartnerSuggestions.php b/plugins/woocommerce/src/Admin/Features/ShippingPartnerSuggestions/ShippingPartnerSuggestions.php
index d681d0fb36..faa32cecd7 100644
--- a/plugins/woocommerce/src/Admin/Features/ShippingPartnerSuggestions/ShippingPartnerSuggestions.php
+++ b/plugins/woocommerce/src/Admin/Features/ShippingPartnerSuggestions/ShippingPartnerSuggestions.php
@@ -37,7 +37,44 @@ class ShippingPartnerSuggestions extends RemoteSpecsEngine {
 			ShippingPartnerSuggestionsDataSourcePoller::get_instance()->set_specs_transient( array( $locale => $specs_to_save ), 3 * HOUR_IN_SECONDS );
 		}

-		return $specs_to_return;
+		return self::sort_by_primary( $specs_to_return );
+	}
+
+	/**
+	 * Sort suggestions so that partners whose countries_where_primary list contains the
+	 * current store country appear first.
+	 *
+	 * @param array $suggestions Suggestions to sort.
+	 * @return array Sorted suggestions.
+	 */
+	private static function sort_by_primary( array $suggestions ) {
+		$country = wc_get_base_location()['country'] ?? '';
+
+		// Attach original indices to preserve input order for equal-priority items
+		// (usort is not stable on PHP < 8.0).
+		$indexed = array_map(
+			function ( $item, $idx ) {
+				return array( $item, $idx );
+			},
+			$suggestions,
+			array_keys( $suggestions )
+		);
+
+		usort(
+			$indexed,
+			function ( $a, $b ) use ( $country ) {
+				$a_primary = isset( $a[0]->countries_where_primary ) && is_array( $a[0]->countries_where_primary ) && in_array( $country, $a[0]->countries_where_primary, true );
+				$b_primary = isset( $b[0]->countries_where_primary ) && is_array( $b[0]->countries_where_primary ) && in_array( $country, $b[0]->countries_where_primary, true );
+
+				if ( $a_primary === $b_primary ) {
+					return $a[1] - $b[1];
+				}
+
+				return $a_primary ? -1 : 1;
+			}
+		);
+
+		return array_column( $indexed, 0 );
 	}

 	/**
diff --git a/plugins/woocommerce/tests/php/src/Admin/Features/ShippingPartnerSuggestions/DefaultShippingPartnersTest.php b/plugins/woocommerce/tests/php/src/Admin/Features/ShippingPartnerSuggestions/DefaultShippingPartnersTest.php
index ceae6b0d21..ffb9aa8b93 100644
--- a/plugins/woocommerce/tests/php/src/Admin/Features/ShippingPartnerSuggestions/DefaultShippingPartnersTest.php
+++ b/plugins/woocommerce/tests/php/src/Admin/Features/ShippingPartnerSuggestions/DefaultShippingPartnersTest.php
@@ -57,8 +57,14 @@ class DefaultShippingPartnersTest extends WC_Unit_Test_Case {
 		$results = EvaluateSuggestion::evaluate_specs( $specs );

 		$this->assertCount( 0, $results['errors'] );
-		$this->assertCount( 1, $results['suggestions'] );
-		$this->assertEquals( 'woocommerce-shipping', $results['suggestions'][0]->id );
+
+		$ids = array_map(
+			function ( $s ) {
+				return $s->id;
+			},
+			$results['suggestions']
+		);
+		$this->assertContains( 'woocommerce-shipping', $ids );
 	}

 	/**
@@ -96,7 +102,14 @@ class DefaultShippingPartnersTest extends WC_Unit_Test_Case {

 		// Assert.
 		$this->assertCount( 0, $results['errors'] );
-		$this->assertCount( 0, $results['suggestions'] );
+
+		$ids = array_map(
+			function ( $s ) {
+				return $s->id;
+			},
+			$results['suggestions']
+		);
+		$this->assertNotContains( 'woocommerce-shipping', $ids );

 		// Clean up.
 		self::rmdir( dirname( $shipping_plugin_file_path ) );
diff --git a/plugins/woocommerce/tests/php/src/Internal/Admin/ShippingPartnerSuggestions/ShippingPartnerSuggestionsTest.php b/plugins/woocommerce/tests/php/src/Internal/Admin/ShippingPartnerSuggestions/ShippingPartnerSuggestionsTest.php
index c9a3e01cab..f8e06793ee 100644
--- a/plugins/woocommerce/tests/php/src/Internal/Admin/ShippingPartnerSuggestions/ShippingPartnerSuggestionsTest.php
+++ b/plugins/woocommerce/tests/php/src/Internal/Admin/ShippingPartnerSuggestions/ShippingPartnerSuggestionsTest.php
@@ -175,6 +175,80 @@ class ShippingPartnerSuggestionsTest extends WC_Unit_Test_Case {
 		remove_filter( 'woocommerce_admin_remote_specs_evaluator_should_log', '__return_true' );
 	}

+	/**
+	 * Test that primary suggestions are sorted before non-primary ones.
+	 */
+	public function test_sort_primary_suggestions_first() {
+		update_option( 'woocommerce_default_country', 'US' );
+
+		$specs = array(
+			(object) array(
+				'id'         => 'non-primary',
+				'is_visible' => true,
+			),
+			(object) array(
+				'id'                      => 'primary-partner',
+				'is_visible'              => true,
+				'countries_where_primary' => array( 'US' ),
+			),
+			(object) array(
+				'id'         => 'another-non-primary',
+				'is_visible' => true,
+			),
+		);
+
+		$suggestions = ShippingPartnerSuggestions::get_suggestions( $specs );
+		$ids         = array_map(
+			function ( $s ) {
+				return $s->id;
+			},
+			$suggestions
+		);
+
+		$this->assertSame( 'primary-partner', $ids[0] );
+	}
+
+	/**
+	 * Test that suggestions with equal primary status preserve their original order (stable sort).
+	 */
+	public function test_sort_preserves_order_for_equal_priority() {
+		update_option( 'woocommerce_default_country', 'US' );
+
+		$specs = array(
+			(object) array(
+				'id'                      => 'primary-a',
+				'is_visible'              => true,
+				'countries_where_primary' => array( 'US' ),
+			),
+			(object) array(
+				'id'                      => 'primary-b',
+				'is_visible'              => true,
+				'countries_where_primary' => array( 'US' ),
+			),
+			(object) array(
+				'id'         => 'non-primary-a',
+				'is_visible' => true,
+			),
+			(object) array(
+				'id'         => 'non-primary-b',
+				'is_visible' => true,
+			),
+		);
+
+		$suggestions = ShippingPartnerSuggestions::get_suggestions( $specs );
+		$ids         = array_map(
+			function ( $s ) {
+				return $s->id;
+			},
+			$suggestions
+		);
+
+		$this->assertSame(
+			array( 'primary-a', 'primary-b', 'non-primary-a', 'non-primary-b' ),
+			$ids
+		);
+	}
+
 	/**
 	 * Overrides the WC logger.
 	 *