From 2c59a33a914db198b7784882ba9986b28e7c55f8 Mon Sep 17 00:00:00 2001 From: Fernando Espinosa Date: Fri, 9 May 2025 16:22:12 +0200 Subject: [PATCH 01/11] Add contextual banners for WooCommerce Shipping & Tax Enhance the NUX (New User Experience) system by adding contextual banners that show different content based on: - Store country (US vs non-US) - Whether the WooCommerce Shipping plugin is active This creates a more personalized onboarding flow by: 1. Adding a new option flag for tracking contextual banner state 2. Improving the banner display logic with prioritized checks 3. Creating three different contextual banner types 4. Ensuring proper transition between traditional and contextual banners The change maintains backward compatibility while providing more targeted guidance. --- classes/class-wc-connect-nux.php | 157 +++++++++++++++++++++++++++---- 1 file changed, 139 insertions(+), 18 deletions(-) diff --git a/classes/class-wc-connect-nux.php b/classes/class-wc-connect-nux.php index 908530907..b214f0195 100644 --- a/classes/class-wc-connect-nux.php +++ b/classes/class-wc-connect-nux.php @@ -16,7 +16,8 @@ class WC_Connect_Nux { * Option name for dismissing success banner * after the JP connection flow */ - const SHOULD_SHOW_AFTER_CXN_BANNER = 'should_display_nux_after_jp_cxn_banner'; + const SHOULD_SHOW_AFTER_CXN_BANNER = 'should_display_nux_after_jp_cxn_banner'; + const SHOULD_SHOW_CONTEXTUAL_BANNER = 'should_display_nux_contextual_banner'; /** * @var WC_Connect_Tracks @@ -241,23 +242,48 @@ public static function get_banner_type_to_display( $status = array() ) { return 'before_jetpack_connection'; case self::JETPACK_CONNECTED: case self::JETPACK_OFFLINE_MODE: - // Has the user just gone through our NUX connection flow? + // Priority 1: Standard "after connection" banner (if pending from NUX flow). + // This banner also handles initial TOS acceptance if coming from the NUX connection flow. if ( isset( $status['should_display_after_cxn_banner'] ) && $status['should_display_after_cxn_banner'] ) { return 'after_jetpack_connection'; } - // Has the user already accepted our TOS? Then do nothing. - // Note: TOS is accepted during the after_connection banner - if ( - isset( $status['tos_accepted'] ) - && ! $status['tos_accepted'] - && isset( $status['can_accept_tos'] ) - && $status['can_accept_tos'] - ) { + // Priority 2: TOS acceptance banner (if Jetpack connected, but TOS not yet accepted, + // and the standard "after connection" banner is not pending). + if ( isset( $status['tos_accepted'] ) && ! $status['tos_accepted'] && + isset( $status['can_accept_tos'] ) && $status['can_accept_tos'] ) { return 'tos_only_banner'; } - return false; + // For existing users: if TOS accepted, after_cxn_banner done, but contextual_banner flag not yet set, set it now. + if ( isset( $status['tos_accepted'] ) && $status['tos_accepted'] && + ( ! isset( $status['should_display_after_cxn_banner'] ) || ! $status['should_display_after_cxn_banner'] ) && + ( ! isset( $status['should_display_contextual_banner'] ) || ! $status['should_display_contextual_banner'] ) + ) { + // This user is eligible for contextual banners but the flag isn't set. Set it now. + WC_Connect_Options::update_option( self::SHOULD_SHOW_CONTEXTUAL_BANNER, true ); + // Update the status for the current execution path, so Priority 3 check below can pick it up. + $status['should_display_contextual_banner'] = true; + } + + // Priority 3: Contextual banners (if standard "after connection" is done or was not applicable, + // TOS is accepted, and the contextual flag is set - either previously or by the block above). + if ( isset( $status['should_display_contextual_banner'] ) && $status['should_display_contextual_banner'] ) { + // Determine which specific contextual banner to show. + $is_us_store = ( isset( $status['store_country'] ) && 'US' === $status['store_country'] ); + + if ( $is_us_store ) { + if ( isset( $status['is_wcs_shipping_plugin_active'] ) && ! $status['is_wcs_shipping_plugin_active'] ) { + return 'after_cxn_us_no_wcs_plugin'; + } else { + return 'after_cxn_us_with_wcs_plugin'; + } + } else { + return 'after_cxn_non_us'; + } + } + + return false; // All NUX banners handled or no NUX banner needed for this state. default: return false; } @@ -372,12 +398,22 @@ public function set_up_nux_notices() { // If this is the case, the admin can connect the site on their own, and should be able to use WCS as ususal $jetpack_install_status = $this->get_jetpack_install_status(); + // Ensure is_plugin_active() is available for WCS check + if ( ! function_exists( 'is_plugin_active' ) ) { + include_once ABSPATH . 'wp-admin/includes/plugin.php'; + } + $is_wcs_shipping_plugin_active = is_plugin_active( 'woocommerce-shipping/woocommerce-shipping.php' ); + $store_country = WC()->countries->get_base_country(); + $banner_to_display = self::get_banner_type_to_display( array( - 'jetpack_connection_status' => $jetpack_install_status, - 'tos_accepted' => WC_Connect_Options::get_option( 'tos_accepted' ), - 'can_accept_tos' => WC_Connect_Jetpack::is_current_user_connection_owner() || WC_Connect_Jetpack::is_offline_mode(), - 'should_display_after_cxn_banner' => WC_Connect_Options::get_option( self::SHOULD_SHOW_AFTER_CXN_BANNER ), + 'jetpack_connection_status' => $jetpack_install_status, + 'tos_accepted' => WC_Connect_Options::get_option( 'tos_accepted' ), + 'can_accept_tos' => WC_Connect_Jetpack::is_current_user_connection_owner() || WC_Connect_Jetpack::is_offline_mode(), + 'should_display_after_cxn_banner' => WC_Connect_Options::get_option( self::SHOULD_SHOW_AFTER_CXN_BANNER ), + 'should_display_contextual_banner' => WC_Connect_Options::get_option( self::SHOULD_SHOW_CONTEXTUAL_BANNER ), + 'store_country' => $store_country, + 'is_wcs_shipping_plugin_active' => $is_wcs_shipping_plugin_active, ) ); @@ -391,13 +427,25 @@ public function set_up_nux_notices() { wp_enqueue_style( 'wc_connect_banner' ); add_action( 'admin_notices', array( $this, 'show_banner_before_connection' ), 9 ); break; + case 'after_jetpack_connection': + wp_enqueue_style( 'wc_connect_banner' ); + add_action( 'admin_notices', array( $this, 'show_banner_after_connection' ) ); + break; case 'tos_only_banner': wp_enqueue_style( 'wc_connect_banner' ); add_action( 'admin_notices', array( $this, 'show_tos_banner' ) ); break; - case 'after_jetpack_connection': + case 'after_cxn_us_no_wcs_plugin': + case 'after_cxn_us_with_wcs_plugin': + case 'after_cxn_non_us': wp_enqueue_style( 'wc_connect_banner' ); - add_action( 'admin_notices', array( $this, 'show_banner_after_connection' ) ); + // Using a closure to correctly pass the argument to the new handler method. + add_action( + 'admin_notices', + function () use ( $banner_to_display ) { + $this->show_contextual_after_connection_banner( $banner_to_display ); + } + ); break; } @@ -452,8 +500,10 @@ public function show_banner_after_connection() { // Did the user just dismiss? if ( isset( $_GET['wcs-nux-notice'] ) && 'dismiss' === $_GET['wcs-nux-notice'] ) { - // No longer need to keep track of whether the before connection banner was displayed. + // Delete the flag for this banner WC_Connect_Options::delete_option( self::SHOULD_SHOW_AFTER_CXN_BANNER ); + // Set the flag for the next contextual banner + WC_Connect_Options::update_option( self::SHOULD_SHOW_CONTEXTUAL_BANNER, true ); wp_safe_redirect( remove_query_arg( 'wcs-nux-notice' ) ); exit; } @@ -487,6 +537,73 @@ public function show_banner_after_connection() { ); } + public function show_contextual_after_connection_banner( $banner_type ) { + $screen = get_current_screen(); + + // This specific banner should only appear on the plugins page. + if ( ! $screen || 'plugins' !== $screen->base ) { + return; + } + + // Still respect the store locale check. + if ( ! $this->should_display_nux_notice_for_current_store_locale() ) { + return; + } + + // Did the user just dismiss? + if ( isset( $_GET['wcs-nux-notice'] ) && 'dismiss' === $_GET['wcs-nux-notice'] ) { + // Delete the flag for this contextual banner + WC_Connect_Options::delete_option( self::SHOULD_SHOW_CONTEXTUAL_BANNER ); + wp_safe_redirect( remove_query_arg( 'wcs-nux-notice' ) ); + exit; + } + + // By going through the connection process, the user has accepted our TOS + WC_Connect_Options::update_option( 'tos_accepted', true ); + + // Using a generic tracks event, can be made more specific if needed. + $this->tracks->opted_in( 'contextual_connection_banner_viewed' ); + + $banner_title = ''; + $banner_description = ''; + + switch ( $banner_type ) { + case 'after_cxn_us_no_wcs_plugin': + $banner_title = __( 'US Store: WooCommerce Shipping Plugin Not Active - Title', 'woocommerce-services' ); + $banner_description = __( 'US Store: WooCommerce Shipping Plugin Not Active - Description.', 'woocommerce-services' ); + break; + case 'after_cxn_us_with_wcs_plugin': + $banner_title = __( 'US Store: WooCommerce Shipping Plugin Active - Title', 'woocommerce-services' ); + $banner_description = __( 'US Store: WooCommerce Shipping Plugin Active - Description.', 'woocommerce-services' ); + break; + case 'after_cxn_non_us': + $banner_title = __( 'Non-US Store - Title', 'woocommerce-services' ); + $banner_description = __( 'Non-US Store - Description.', 'woocommerce-services' ); + break; + default: + // Fallback for an unknown banner type, though this shouldn't be reached with current logic. + return; + } + + $this->show_nux_banner( + array( + 'title' => $banner_title, + 'description' => esc_html( $banner_description ), + 'button_text' => __( 'Got it, thanks!', 'woocommerce-services' ), + 'button_link' => add_query_arg( + array( + 'wcs-nux-notice' => 'dismiss', + ) + ), + 'image_url' => plugins_url( + 'images/wcs-notice.png', + __DIR__ + ), + 'should_show_terms' => false, + ) + ); + } + public function show_tos_banner() { if ( ! $this->should_display_nux_notice_for_current_store_locale() ) { return; @@ -498,6 +615,8 @@ public function show_tos_banner() { if ( isset( $_GET['wcs-nux-tos'] ) && 'accept' === $_GET['wcs-nux-tos'] ) { WC_Connect_Options::update_option( 'tos_accepted', true ); + // Signal that the contextual banner can now be shown + WC_Connect_Options::update_option( self::SHOULD_SHOW_CONTEXTUAL_BANNER, true ); $this->tracks->opted_in( 'tos_banner' ); @@ -625,6 +744,8 @@ public function register_woocommerce_services_jetpack() { // Make sure we always display the after-connection banner // after the before_connection button is clicked WC_Connect_Options::update_option( self::SHOULD_SHOW_AFTER_CXN_BANNER, true ); + // Ensure the contextual banner flag is not set prematurely + WC_Connect_Options::delete_option( self::SHOULD_SHOW_CONTEXTUAL_BANNER ); WC_Connect_Jetpack::connect_site( $redirect_url ); } From 50e47453362ec48680cb06975c61173d48da6cf3 Mon Sep 17 00:00:00 2001 From: Fernando Espinosa Date: Mon, 12 May 2025 16:14:07 +0200 Subject: [PATCH 02/11] Update migration banner copy --- classes/class-wc-connect-nux.php | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/classes/class-wc-connect-nux.php b/classes/class-wc-connect-nux.php index b214f0195..7a6984cc8 100644 --- a/classes/class-wc-connect-nux.php +++ b/classes/class-wc-connect-nux.php @@ -566,19 +566,31 @@ public function show_contextual_after_connection_banner( $banner_type ) { $banner_title = ''; $banner_description = ''; + $banner_button_text = ''; + $banner_button_link = null; switch ( $banner_type ) { case 'after_cxn_us_no_wcs_plugin': - $banner_title = __( 'US Store: WooCommerce Shipping Plugin Not Active - Title', 'woocommerce-services' ); - $banner_description = __( 'US Store: WooCommerce Shipping Plugin Not Active - Description.', 'woocommerce-services' ); + $banner_title = __( 'WooCommerce Shipping & Tax has been renamed to WooCommerce Tax', 'woocommerce-services' ); + $banner_description = __( 'Your tax functionality will continue to work as expected. The shipping functionality in this plugin will be discontinued on September 1, 2025. Please migrate to the new WooCommerce Shipping extension to get discounted labels for UPS, USPS, DHL Express— and more coming soon!', 'woocommerce-services' ); + $banner_button_text = __( 'Try WooCommerce Shipping ', 'woocommerce-services' ); + $banner_button_link = ''; break; case 'after_cxn_us_with_wcs_plugin': - $banner_title = __( 'US Store: WooCommerce Shipping Plugin Active - Title', 'woocommerce-services' ); - $banner_description = __( 'US Store: WooCommerce Shipping Plugin Active - Description.', 'woocommerce-services' ); + $banner_title = __( 'WooCommerce Shipping & Tax has been renamed to WooCommerce Tax', 'woocommerce-services' ); + $banner_description = __( 'Your tax functionality will continue to work as expected. Use WooCommerce Shipping to access deeply discounted UPS, USPS, and DHL shipping labels, reliable shipments, and on-time delivery options.', 'woocommerce-services' ); + $banner_button_text = __( 'Ship with UPS on WooCommerce', 'woocommerce-services' ); + $banner_button_link = ''; break; case 'after_cxn_non_us': - $banner_title = __( 'Non-US Store - Title', 'woocommerce-services' ); - $banner_description = __( 'Non-US Store - Description.', 'woocommerce-services' ); + $banner_title = __( 'WooCommerce Shipping & Tax has been renamed to WooCommerce Tax', 'woocommerce-services' ); + $banner_description = __( 'Your tax functionality will continue to work as expected. No action is required.', 'woocommerce-services' ); + $banner_button_text = __( 'Close', 'woocommerce-services' ); + $banner_button_link = add_query_arg( + array( + 'wcs-nux-notice' => 'dismiss', + ) + ); break; default: // Fallback for an unknown banner type, though this shouldn't be reached with current logic. @@ -589,12 +601,8 @@ public function show_contextual_after_connection_banner( $banner_type ) { array( 'title' => $banner_title, 'description' => esc_html( $banner_description ), - 'button_text' => __( 'Got it, thanks!', 'woocommerce-services' ), - 'button_link' => add_query_arg( - array( - 'wcs-nux-notice' => 'dismiss', - ) - ), + 'button_text' => $banner_button_text, + 'button_link' => $banner_button_link, 'image_url' => plugins_url( 'images/wcs-notice.png', __DIR__ From 3161463dccedd3ef2e7b767344d72d28d9cadbec Mon Sep 17 00:00:00 2001 From: Fernando Espinosa Date: Tue, 13 May 2025 09:21:45 +0200 Subject: [PATCH 03/11] Add WooCommerce Shipping Migration modal and contextual banner with dismissal control - Extend WC_Connect_Nux to support new service settings and schemas stores. - Add contextual after-connection banner for US users without WooCommerce Shipping plugin. - Enqueue and localize migration modal scripts and styles; render React modal container in admin notices. - Add dismissal logic with a shared option (`wcs_nux_any_banner_shown`) to prevent multiple simultaneous banners. - Enhance feature announcement React component to support forced open state. - Improve migration runner state handling for robustness. - Add safety checks in admin notice dismiss button event listeners. - Make `WC_Connect_Loader::get_wc_connect_base_url` public static for broader usage. - Instantiate `WC_Connect_Nux` with new dependencies in loader. - Add placeholder admin banner and modal manager classes. --- classes/class-wc-connect-nux.php | 148 ++++++++++++++++-- .../migration/feature-announcement.jsx | 5 +- .../components/migration/migration-runner.js | 9 +- client/wcshipping-migration-admin-notice.js | 20 ++- includes/admin/class-wc-connect-banner.php | 0 .../admin/class-wc-connect-modal-manager.php | 0 woocommerce-services.php | 4 +- 7 files changed, 161 insertions(+), 25 deletions(-) create mode 100644 includes/admin/class-wc-connect-banner.php create mode 100644 includes/admin/class-wc-connect-modal-manager.php diff --git a/classes/class-wc-connect-nux.php b/classes/class-wc-connect-nux.php index 7a6984cc8..c55520c26 100644 --- a/classes/class-wc-connect-nux.php +++ b/classes/class-wc-connect-nux.php @@ -29,9 +29,34 @@ class WC_Connect_Nux { */ private $shipping_label; - function __construct( WC_Connect_Tracks $tracks, WC_Connect_Shipping_Label $shipping_label ) { - $this->tracks = $tracks; - $this->shipping_label = $shipping_label; + /** + * @var WC_Connect_Service_Settings_Store + */ + protected $service_settings_store; + + /** + * @var WC_Connect_Payment_Methods_Store + */ + protected $payment_methods_store; + + /** + * @var WC_Connect_Service_Schemas_Store + */ + protected $service_schemas_store; + + + function __construct( + WC_Connect_Tracks $tracks, + WC_Connect_Shipping_Label $shipping_label, + WC_Connect_Service_Settings_Store $service_settings_store, + WC_Connect_Payment_Methods_Store $payment_methods_store, + WC_Connect_Service_Schemas_Store $service_schemas_store + ) { + $this->tracks = $tracks; + $this->shipping_label = $shipping_label; + $this->service_settings_store = $service_settings_store; + $this->payment_methods_store = $payment_methods_store; + $this->service_schemas_store = $service_schemas_store; $this->init_pointers(); } @@ -436,6 +461,68 @@ public function set_up_nux_notices() { add_action( 'admin_notices', array( $this, 'show_tos_banner' ) ); break; case 'after_cxn_us_no_wcs_plugin': + // Enqueue the migration modal assets specifically for this banner on the plugins page. + $plugin_version = WC_Connect_Loader::get_wcs_version(); + // Use the public static method from WC_Connect_Loader + $base_url = WC_Connect_Loader::get_wc_connect_base_url(); // Assuming get_wc_connect_base_url is static + + wp_register_style( 'wcst_wcshipping_migration_admin_notice', $base_url . 'woocommerce-services-wcshipping-migration-admin-notice-' . $plugin_version . '.css', array(), null ); // phpcs:ignore WordPress.WP.EnqueuedResourceParameters.MissingVersion + // Add 'wp-element' and 'wc_connect_admin' dependency for React and base script + wp_register_script( 'wcst_wcshipping_migration_admin_notice', $base_url . 'woocommerce-services-wcshipping-migration-admin-notice-' . $plugin_version . '.js', array( 'wc_connect_admin', 'wp-element' ), null, true ); // phpcs:ignore WordPress.WP.EnqueuedResourceParameters.MissingVersion + + // Localize script data - MATCHING the original register_wcshipping_migration_modal + // Note: The modal primarily uses data-args, localization is minimal here. + wp_localize_script( + 'wcst_wcshipping_migration_admin_notice', + 'wcsPluginData', // Ensure this matches the expected object name in the script + array( + 'assetPath' => $base_url, + 'adminPluginPath' => admin_url( 'plugins.php' ), + ) + ); + + // Enqueue scripts/styles needed for the banner and modal + wp_enqueue_script( 'wc_connect_admin' ); // Ensure base script is loaded first + wp_enqueue_script( 'wcst_wcshipping_migration_admin_notice' ); + wp_enqueue_style( 'wcst_wcshipping_migration_admin_notice' ); + wp_enqueue_style( 'wc_connect_banner' ); + + // Add the action to render the notice and container div + add_action( + 'admin_notices', + function () use ( $banner_to_display ) { + // Instantiate settings classes HERE, inside the closure, using stored dependencies + $account_settings = new WC_Connect_Account_Settings( + $this->service_settings_store, + $this->payment_methods_store + ); + $packages_settings = new WC_Connect_Package_Settings( + $this->service_settings_store, + $this->service_schemas_store + ); + + // Prepare the data for the data-args attribute by calling get() + $container_data_args = array( + 'nonce' => wp_create_nonce( 'wp_rest' ), + 'baseURL' => get_rest_url(), + 'accountSettings' => $account_settings->get(), // Get REAL data + 'packagesSettings' => $packages_settings->get(), // Get REAL data + ); + $encoded_container_args = wp_json_encode( $container_data_args ); + + // Echo the container div needed for the modal React component BEFORE the banner. + // Add 'display: none;' initially; the script should manage visibility. + printf( + '', + esc_attr( $encoded_container_args ) // Use the REAL encoded data + ); + + // Now show the banner itself + $this->show_contextual_after_connection_banner( $banner_to_display ); + } + ); + break; // End case 'after_cxn_us_no_wcs_plugin' + case 'after_cxn_us_with_wcs_plugin': case 'after_cxn_non_us': wp_enqueue_style( 'wc_connect_banner' ); @@ -453,6 +540,10 @@ function () use ( $banner_to_display ) { } public function show_banner_before_connection() { + if ( get_option( 'wcs_nux_any_banner_shown', false ) ) { + return; + } + if ( ! $this->should_display_nux_notice_for_current_store_locale() ) { return; } @@ -486,10 +577,16 @@ public function show_banner_before_connection() { 'should_show_terms' => true, ); + update_option( 'wcs_nux_any_banner_shown', true ); + $this->show_nux_banner( $banner_content ); } public function show_banner_after_connection() { + if ( get_option( 'wcs_nux_any_banner_shown', false ) ) { + return; + } + if ( ! $this->should_display_nux_notice_for_current_store_locale() ) { return; } @@ -504,6 +601,7 @@ public function show_banner_after_connection() { WC_Connect_Options::delete_option( self::SHOULD_SHOW_AFTER_CXN_BANNER ); // Set the flag for the next contextual banner WC_Connect_Options::update_option( self::SHOULD_SHOW_CONTEXTUAL_BANNER, true ); + delete_option( 'wcs_nux_any_banner_shown' ); wp_safe_redirect( remove_query_arg( 'wcs-nux-notice' ) ); exit; } @@ -518,6 +616,8 @@ public function show_banner_after_connection() { $description_base = __( 'You can now enjoy %s.', 'woocommerce-services' ); $feature_list = $this->get_feature_list_for_country( $country ); + update_option( 'wcs_nux_any_banner_shown', true ); + $this->show_nux_banner( array( 'title' => __( 'Setup complete.', 'woocommerce-services' ), @@ -538,6 +638,10 @@ public function show_banner_after_connection() { } public function show_contextual_after_connection_banner( $banner_type ) { + if ( get_option( 'wcs_nux_any_banner_shown', false ) ) { + return; + } + $screen = get_current_screen(); // This specific banner should only appear on the plugins page. @@ -554,6 +658,7 @@ public function show_contextual_after_connection_banner( $banner_type ) { if ( isset( $_GET['wcs-nux-notice'] ) && 'dismiss' === $_GET['wcs-nux-notice'] ) { // Delete the flag for this contextual banner WC_Connect_Options::delete_option( self::SHOULD_SHOW_CONTEXTUAL_BANNER ); + delete_option( 'wcs_nux_any_banner_shown' ); wp_safe_redirect( remove_query_arg( 'wcs-nux-notice' ) ); exit; } @@ -564,17 +669,21 @@ public function show_contextual_after_connection_banner( $banner_type ) { // Using a generic tracks event, can be made more specific if needed. $this->tracks->opted_in( 'contextual_connection_banner_viewed' ); + update_option( 'wcs_nux_any_banner_shown', true ); + $banner_title = ''; $banner_description = ''; $banner_button_text = ''; $banner_button_link = null; + update_option( 'wcshipping_migration_state', '0' ); switch ( $banner_type ) { case 'after_cxn_us_no_wcs_plugin': $banner_title = __( 'WooCommerce Shipping & Tax has been renamed to WooCommerce Tax', 'woocommerce-services' ); $banner_description = __( 'Your tax functionality will continue to work as expected. The shipping functionality in this plugin will be discontinued on September 1, 2025. Please migrate to the new WooCommerce Shipping extension to get discounted labels for UPS, USPS, DHL Express— and more coming soon!', 'woocommerce-services' ); $banner_button_text = __( 'Try WooCommerce Shipping ', 'woocommerce-services' ); - $banner_button_link = ''; + // Ensure this line uses the special trigger value: + $banner_button_link = '#trigger-migration-modal'; break; case 'after_cxn_us_with_wcs_plugin': $banner_title = __( 'WooCommerce Shipping & Tax has been renamed to WooCommerce Tax', 'woocommerce-services' ); @@ -613,6 +722,10 @@ public function show_contextual_after_connection_banner( $banner_type ) { } public function show_tos_banner() { + if ( get_option( 'wcs_nux_any_banner_shown', false ) ) { + return; + } + if ( ! $this->should_display_nux_notice_for_current_store_locale() ) { return; } @@ -628,6 +741,8 @@ public function show_tos_banner() { $this->tracks->opted_in( 'tos_banner' ); + delete_option( 'wcs_nux_any_banner_shown' ); + wp_safe_redirect( remove_query_arg( 'wcs-nux-tos' ) ); exit; } @@ -637,6 +752,8 @@ public function show_tos_banner() { $description_base = __( "WooCommerce Tax is almost ready to go! Once you connect your site to WordPress.com you'll have access to %s.", 'woocommerce-services' ); $feature_list = $this->get_feature_list_for_country( $country ); + update_option( 'wcs_nux_any_banner_shown', true ); + $this->show_nux_banner( array( 'title' => __( 'Connect your site to activate WooCommerce Tax', 'woocommerce-services' ), @@ -694,12 +811,23 @@ public function show_nux_banner( $content ) {

- - - + + + + + + + +
diff --git a/client/components/migration/feature-announcement.jsx b/client/components/migration/feature-announcement.jsx index 4fc56320f..44e035098 100644 --- a/client/components/migration/feature-announcement.jsx +++ b/client/components/migration/feature-announcement.jsx @@ -20,8 +20,9 @@ import { import { installAndActivatePlugins } from './migration-runner'; import { TIME_TO_REMMEMBER_DISMISSAL_SECONDS } from './constants'; -const FeatureAnnouncement = ( { translate, isEligable, previousMigrationState, onClose } ) => { - const [isOpen, setIsOpen] = useState(isEligable); +const FeatureAnnouncement = ( { translate, isEligable, previousMigrationState, onClose, forceOpen = false } ) => { + // Open if either normally eligible OR if forced open by the prop. + const [isOpen, setIsOpen] = useState( forceOpen || isEligable ); const [isUpdating, setIsUpdating] = useState(false); useEffect( () => { diff --git a/client/components/migration/migration-runner.js b/client/components/migration/migration-runner.js index 8c0d1c866..1a3b4cecd 100644 --- a/client/components/migration/migration-runner.js +++ b/client/components/migration/migration-runner.js @@ -228,11 +228,14 @@ const installAndActivatePlugins = async( previousMigrationState ) => { * @returns {string} The next state to run. The name of the state is the key in this object migrationStateTransitions. */ const getNextStateToRun = () => { - if ( ! previousMigrationState ) { - // stateInit + // Check if previousMigrationState is a valid key in the map. + // If not, or if it's falsy, default to the initial state (stateInit). + if ( ! previousMigrationState || ! MIGRATION_ENUM_TO_STATE_NAME_MAP.hasOwnProperty( previousMigrationState ) ) { + // stateInit (key 2) return MIGRATION_ENUM_TO_STATE_NAME_MAP[ 2 ]; } + // If it's a valid key, find the corresponding state name and return its success transition. const currentStateName = MIGRATION_ENUM_TO_STATE_NAME_MAP[ previousMigrationState ]; const nextMigrationState = getMigrationStateByName( currentStateName ); return nextMigrationState.success; // The next state is "success". @@ -258,4 +261,4 @@ const installAndActivatePlugins = async( previousMigrationState ) => { export { installAndActivatePlugins -} \ No newline at end of file +} diff --git a/client/wcshipping-migration-admin-notice.js b/client/wcshipping-migration-admin-notice.js index 15144045e..31dc46512 100644 --- a/client/wcshipping-migration-admin-notice.js +++ b/client/wcshipping-migration-admin-notice.js @@ -33,20 +33,24 @@ const wcstMigrationNoticeDimissButton = document.querySelector('.wcst-wcshipping * Prevent form submission when rendered in a form or alike that listens to button click */ evt.preventDefault(); - // Pop open feature announcement modal. + // Pop open feature announcement modal, forcing it open regardless of eligibility state. ReactDOM.render( - + , container ); }); // Dismiss it for 3 days, then remove it from view. - wcstMigrationNoticeDimissButton.addEventListener(eventName, () => { - // window.wpCookies API: wordpress/wp-includes/js/utils.js - window.wpCookies.set('wcst-wcshipping-migration-dismissed', 1, TIME_TO_REMMEMBER_DISMISSAL_SECONDS) - const wcstMigrationAdminNotice = document.querySelector('.wcst-wcshipping-migration-notice'); - wcstMigrationAdminNotice.remove(); - }); + if (wcstMigrationNoticeDimissButton) { + wcstMigrationNoticeDimissButton.addEventListener(eventName, () => { + // window.wpCookies API: wordpress/wp-includes/js/utils.js + window.wpCookies.set('wcst-wcshipping-migration-dismissed', 1, TIME_TO_REMMEMBER_DISMISSAL_SECONDS) + const wcstMigrationAdminNotice = document.querySelector('.wcst-wcshipping-migration-notice'); + if (wcstMigrationAdminNotice) { + wcstMigrationAdminNotice.remove(); + } + }); + } }); diff --git a/includes/admin/class-wc-connect-banner.php b/includes/admin/class-wc-connect-banner.php new file mode 100644 index 000000000..e69de29bb diff --git a/includes/admin/class-wc-connect-modal-manager.php b/includes/admin/class-wc-connect-modal-manager.php new file mode 100644 index 000000000..e69de29bb diff --git a/woocommerce-services.php b/woocommerce-services.php index aef74b271..cb37532cc 100644 --- a/woocommerce-services.php +++ b/woocommerce-services.php @@ -337,7 +337,7 @@ public static function get_wcs_version() { * * @return string */ - private static function get_wc_connect_base_url() { + public static function get_wc_connect_base_url() { return trailingslashit( defined( 'WOOCOMMERCE_CONNECT_DEV_SERVER_URL' ) ? WOOCOMMERCE_CONNECT_DEV_SERVER_URL : plugins_url( 'dist/', __FILE__ ) ); } @@ -814,7 +814,7 @@ public function load_dependencies() { $payment_methods_store = new WC_Connect_Payment_Methods_Store( $settings_store, $api_client, $logger ); $tracks = new WC_Connect_Tracks( $logger, __FILE__ ); $shipping_label = new WC_Connect_Shipping_Label( $api_client, $settings_store, $schemas_store, $payment_methods_store ); - $nux = new WC_Connect_Nux( $tracks, $shipping_label ); + $nux = new WC_Connect_Nux( $tracks, $shipping_label, $settings_store, $payment_methods_store, $schemas_store ); $taxjar = new WC_Connect_TaxJar_Integration( $api_client, $taxes_logger, $this->wc_connect_base_url ); $paypal_ec = new WC_Connect_PayPal_EC( $api_client, $nux ); $label_reports = new WC_Connect_Label_Reports( $settings_store ); From 8b3ea8d237e63904506449c0206f746d681d4956 Mon Sep 17 00:00:00 2001 From: Fernando Espinosa Date: Tue, 13 May 2025 09:49:37 +0200 Subject: [PATCH 04/11] Fix php unit tests --- classes/class-wc-connect-nux.php | 11 +++++++++++ classes/class-wc-connect-options.php | 1 + 2 files changed, 12 insertions(+) diff --git a/classes/class-wc-connect-nux.php b/classes/class-wc-connect-nux.php index c55520c26..4d913ab9d 100644 --- a/classes/class-wc-connect-nux.php +++ b/classes/class-wc-connect-nux.php @@ -291,6 +291,17 @@ public static function get_banner_type_to_display( $status = array() ) { $status['should_display_contextual_banner'] = true; } + // Fallback for non-US stores if contextual banner flag is not set + if ( isset( $status['tos_accepted'] ) && $status['tos_accepted'] && + ( ! isset( $status['should_display_after_cxn_banner'] ) || ! $status['should_display_after_cxn_banner'] ) && + ( ! isset( $status['should_display_contextual_banner'] ) || ! $status['should_display_contextual_banner'] ) + ) { + $is_us_store = ( isset( $status['store_country'] ) && 'US' === $status['store_country'] ); + if ( ! $is_us_store ) { + return 'after_cxn_non_us'; + } + } + // Priority 3: Contextual banners (if standard "after connection" is done or was not applicable, // TOS is accepted, and the contextual flag is set - either previously or by the block above). if ( isset( $status['should_display_contextual_banner'] ) && $status['should_display_contextual_banner'] ) { diff --git a/classes/class-wc-connect-options.php b/classes/class-wc-connect-options.php index e048f5d77..5396b472f 100644 --- a/classes/class-wc-connect-options.php +++ b/classes/class-wc-connect-options.php @@ -51,6 +51,7 @@ public static function get_option_names( $type = 'compact' ) { 'predefined_packages', 'shipping_methods_migrated', 'should_display_nux_after_jp_cxn_banner', + 'should_display_nux_contextual_banner', 'needs_tax_environment_setup', 'banner_ppec', ); From 2c27bb2adfd7a8fbc3c0ae5adb8e8f4cc3e9e16c Mon Sep 17 00:00:00 2001 From: Fernando Espinosa Date: Wed, 14 May 2025 08:50:54 +0200 Subject: [PATCH 05/11] Fix broken phpunit tests --- tests/php/test-class_wc-connect-nux.php | 26 ++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/tests/php/test-class_wc-connect-nux.php b/tests/php/test-class_wc-connect-nux.php index 485259784..052d93ec2 100644 --- a/tests/php/test-class_wc-connect-nux.php +++ b/tests/php/test-class_wc-connect-nux.php @@ -3,7 +3,7 @@ class WP_Test_WC_Connect_NUX extends WC_Unit_Test_Case { public static function set_up_before_class() { - require_once dirname( __FILE__ ) . '/../../classes/class-wc-connect-nux.php'; + require_once __DIR__ . '/../../classes/class-wc-connect-nux.php'; } public function test_get_banner_type_to_display_dev_jp() { @@ -22,13 +22,15 @@ public function test_get_banner_type_to_display_dev_jp() { $this->assertEquals( WC_Connect_Nux::get_banner_type_to_display( array( - 'jetpack_connection_status' => WC_Connect_Nux::JETPACK_OFFLINE_MODE, - 'tos_accepted' => true, - 'can_accept_tos' => null, // irrelevant here, TOS is accepted (DEV) - 'should_display_after_cxn_banner' => false, + 'jetpack_connection_status' => WC_Connect_Nux::JETPACK_OFFLINE_MODE, + 'tos_accepted' => true, + 'can_accept_tos' => null, // irrelevant here, TOS is accepted (DEV) + 'should_display_after_cxn_banner' => false, + 'store_country' => 'JP', + 'should_display_contextual_banner' => true, ) ), - false + 'after_cxn_non_us' ); $this->assertEquals( @@ -158,13 +160,15 @@ public function test_get_banner_type_to_display_with_jp_cxn_with_tos_acceptance( $this->assertEquals( WC_Connect_Nux::get_banner_type_to_display( array( - 'jetpack_connection_status' => WC_Connect_Nux::JETPACK_CONNECTED, - 'tos_accepted' => true, - 'can_accept_tos' => true, - 'should_display_after_cxn_banner' => false, + 'jetpack_connection_status' => WC_Connect_Nux::JETPACK_CONNECTED, + 'tos_accepted' => true, + 'can_accept_tos' => true, + 'should_display_after_cxn_banner' => false, + 'store_country' => 'JP', + 'should_display_contextual_banner' => true, ) ), - false + 'after_cxn_non_us' ); } } From 9466a6f02fb6dfde3c238ecf299681c94457f904 Mon Sep 17 00:00:00 2001 From: Fernando Espinosa Date: Wed, 14 May 2025 08:51:12 +0200 Subject: [PATCH 06/11] Add test docker environment to run phpunit tests --- tests/docker/Dockerfile | 44 +++++++++++++++++++++++++++++++++ tests/docker/docker-compose.yml | 36 +++++++++++++++++++++++++++ tests/docker/entrypoint.sh | 3 +++ tests/docker/run-tests.sh | 35 ++++++++++++++++++++++++++ 4 files changed, 118 insertions(+) create mode 100644 tests/docker/Dockerfile create mode 100644 tests/docker/docker-compose.yml create mode 100644 tests/docker/entrypoint.sh create mode 100755 tests/docker/run-tests.sh diff --git a/tests/docker/Dockerfile b/tests/docker/Dockerfile new file mode 100644 index 000000000..8e8fc0ec0 --- /dev/null +++ b/tests/docker/Dockerfile @@ -0,0 +1,44 @@ +FROM ubuntu:22.04 + +ENV DEBIAN_FRONTEND=noninteractive + +RUN apt-get update && apt-get install -y software-properties-common curl gnupg2 lsb-release + +# Add ondrej/php PPA for PHP 8.2 packages +RUN add-apt-repository ppa:ondrej/php -y \ + && apt-get update + +# Install PHP 8.2 and extensions +RUN apt-get install -y \ + php8.2 \ + php8.2-cli \ + php8.2-mysql \ + php8.2-xml \ + php8.2-mbstring \ + php8.2-curl \ + php8.2-zip \ + php8.2-intl \ + php8.2-bcmath \ + php8.2-simplexml \ + php8.2-tokenizer \ + php8.2-xdebug \ + php-pear \ + git \ + subversion \ + mariadb-client \ + nodejs \ + npm \ + unzip \ + && npm install -g pnpm \ + && apt-get clean && rm -rf /var/lib/apt/lists/* + +# Install composer globally +RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer + +WORKDIR /workspace + +COPY entrypoint.sh /entrypoint.sh +RUN chmod +x /entrypoint.sh + +ENTRYPOINT ["/entrypoint.sh"] +CMD ["bash"] diff --git a/tests/docker/docker-compose.yml b/tests/docker/docker-compose.yml new file mode 100644 index 000000000..3502ee623 --- /dev/null +++ b/tests/docker/docker-compose.yml @@ -0,0 +1,36 @@ +version: "3.8" + +services: + mariadb: + image: mariadb:10.9 + container_name: mariadb_container + environment: + MYSQL_USER: wp_test + MYSQL_PASSWORD: wp_test + MYSQL_DATABASE: wordpress_default + MYSQL_ROOT_PASSWORD: root + ports: + - 3307:3306 + healthcheck: + test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] + interval: 10s + timeout: 5s + retries: 3 + + php-tests: + build: . + container_name: php_tests_container + depends_on: + - mariadb + working_dir: /workspace + tty: true + stdin_open: true + volumes: + - ../../:/workspace:cached + environment: + MYSQL_USER: wp_test + MYSQL_PASSWORD: wp_test + MYSQL_DATABASE: wordpress_default + MYSQL_ROOT_PASSWORD: root + WP_VERSION: "6.3.0" # adjust as needed + WC_VERSION: "7.6.1" # adjust as needed diff --git a/tests/docker/entrypoint.sh b/tests/docker/entrypoint.sh new file mode 100644 index 000000000..d8e07d2e2 --- /dev/null +++ b/tests/docker/entrypoint.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -e +exec "$@" diff --git a/tests/docker/run-tests.sh b/tests/docker/run-tests.sh new file mode 100755 index 000000000..838aa1e22 --- /dev/null +++ b/tests/docker/run-tests.sh @@ -0,0 +1,35 @@ +#!/bin/bash +set -e + +WC_VERSION=${WC_VERSION:-"7.6.1"} +WP_VERSION=${WP_VERSION:-"6.3.0"} + +echo "Cleaning previous WooCommerce clone..." +if [ -d /tmp/woocommerce ]; then + chmod -R u+w /tmp/woocommerce || true + rm -rf /tmp/woocommerce +fi + +echo "Cloning WooCommerce $WC_VERSION..." +git clone --depth=1 --branch="$WC_VERSION" https://github.com/woocommerce/woocommerce.git /tmp/woocommerce + +echo "Installing WooCommerce dependencies..." +cd /tmp/woocommerce/plugins/woocommerce +composer install +php bin/generate-feature-config.php + +echo "Setting up WordPress test environment..." +mysql -h mariadb -u root -proot -e "DROP DATABASE IF EXISTS wp_test;" +bash tests/bin/install.sh wp_test root root mariadb "${WP_VERSION}" + +if [[ "$WC_VERSION" == "7.5.1" || "$WC_VERSION" == "7.6.1" ]]; then + echo "Installing PHPUnit 8 for legacy WC versions..." + composer require -W phpunit/phpunit:^8 +fi + +echo "Installing plugin dependencies..." +cd /workspace +composer install + +echo "Running PHPUnit tests..." +./vendor/bin/phpunit -c phpunit.xml.dist From 4f8a8e69c2d41e2136bad10efe860e72078c57e8 Mon Sep 17 00:00:00 2001 From: Fernando Espinosa Date: Wed, 14 May 2025 10:15:50 +0200 Subject: [PATCH 07/11] Fix broken e2e tests --- client/wcshipping-migration-admin-notice.js | 42 +++++++++++---------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/client/wcshipping-migration-admin-notice.js b/client/wcshipping-migration-admin-notice.js index 31dc46512..494f0c095 100644 --- a/client/wcshipping-migration-admin-notice.js +++ b/client/wcshipping-migration-admin-notice.js @@ -25,25 +25,29 @@ const store = createStore(ShippingLabelStore.getReducer(), ShippingLabelStore.ge const wcstWCShippingMigrationNoticeButton = document.getElementById('wcst-wcshipping-migration-notice__click'); const wcstMigrationNoticeDimissButton = document.querySelector('.wcst-wcshipping-migration-notice button.notice-dismiss'); -// Add all button events -["click", "keydown"].forEach(eventName => { - // Clicking "Confirm update" will start the migration. This is the same as popping up the modal and clicking the "Update" button there. - wcstWCShippingMigrationNoticeButton.addEventListener(eventName, (evt) => { - /** - * Prevent form submission when rendered in a form or alike that listens to button click - */ - evt.preventDefault(); - // Pop open feature announcement modal, forcing it open regardless of eligibility state. - ReactDOM.render( - - - , - container - ); +if (wcstWCShippingMigrationNoticeButton) { + // Add all button events + ["click", "keydown"].forEach(eventName => { + // Clicking "Confirm update" will start the migration. This is the same as popping up the modal and clicking the "Update" button there. + wcstWCShippingMigrationNoticeButton.addEventListener(eventName, (evt) => { + /** + * Prevent form submission when rendered in a form or alike that listens to button click + */ + evt.preventDefault(); + // Pop open feature announcement modal, forcing it open regardless of eligibility state. + ReactDOM.render( + + + , + container + ); + }); }); +} - // Dismiss it for 3 days, then remove it from view. - if (wcstMigrationNoticeDimissButton) { +// Dismiss it for 3 days, then remove it from view. +if (wcstMigrationNoticeDimissButton) { + ["click", "keydown"].forEach(eventName => { wcstMigrationNoticeDimissButton.addEventListener(eventName, () => { // window.wpCookies API: wordpress/wp-includes/js/utils.js window.wpCookies.set('wcst-wcshipping-migration-dismissed', 1, TIME_TO_REMMEMBER_DISMISSAL_SECONDS) @@ -52,5 +56,5 @@ const wcstMigrationNoticeDimissButton = document.querySelector('.wcst-wcshipping wcstMigrationAdminNotice.remove(); } }); - } -}); + }); +} From 111fec4f01b4469c7672923855dc818a83987201 Mon Sep 17 00:00:00 2001 From: Fernando Espinosa Date: Wed, 14 May 2025 10:43:18 +0200 Subject: [PATCH 08/11] Delete unneeded files --- includes/admin/class-wc-connect-banner.php | 0 includes/admin/class-wc-connect-modal-manager.php | 0 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 includes/admin/class-wc-connect-banner.php delete mode 100644 includes/admin/class-wc-connect-modal-manager.php diff --git a/includes/admin/class-wc-connect-banner.php b/includes/admin/class-wc-connect-banner.php deleted file mode 100644 index e69de29bb..000000000 diff --git a/includes/admin/class-wc-connect-modal-manager.php b/includes/admin/class-wc-connect-modal-manager.php deleted file mode 100644 index e69de29bb..000000000 From bd381739f79c26a3205d10a4d5579c9e0f0e4c1c Mon Sep 17 00:00:00 2001 From: Fernando Espinosa Date: Thu, 15 May 2025 11:12:46 +0200 Subject: [PATCH 09/11] Add pending link to migration banner --- classes/class-wc-connect-nux.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/classes/class-wc-connect-nux.php b/classes/class-wc-connect-nux.php index 4d913ab9d..30e02510c 100644 --- a/classes/class-wc-connect-nux.php +++ b/classes/class-wc-connect-nux.php @@ -700,7 +700,7 @@ public function show_contextual_after_connection_banner( $banner_type ) { $banner_title = __( 'WooCommerce Shipping & Tax has been renamed to WooCommerce Tax', 'woocommerce-services' ); $banner_description = __( 'Your tax functionality will continue to work as expected. Use WooCommerce Shipping to access deeply discounted UPS, USPS, and DHL shipping labels, reliable shipments, and on-time delivery options.', 'woocommerce-services' ); $banner_button_text = __( 'Ship with UPS on WooCommerce', 'woocommerce-services' ); - $banner_button_link = ''; + $banner_button_link = 'https://woocommerce.com/document/woocommerce-shipping/#creating-shipping-labels'; break; case 'after_cxn_non_us': $banner_title = __( 'WooCommerce Shipping & Tax has been renamed to WooCommerce Tax', 'woocommerce-services' ); From 801bceaa49b4360640a76495b7035de75b498023 Mon Sep 17 00:00:00 2001 From: Fernando Espinosa Date: Mon, 19 May 2025 13:01:57 +0200 Subject: [PATCH 10/11] Address PR comments --- .gitignore | 1 + classes/class-wc-connect-nux.php | 25 +++++++++---------------- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/.gitignore b/.gitignore index 955c02cea..999d83b60 100644 --- a/.gitignore +++ b/.gitignore @@ -27,6 +27,7 @@ woocommerce-services.zip dist/ .cache/ tests/e2e-tests/screenshots +tests/docker/docker-compose.override.yml # docker data for local development docker/data diff --git a/classes/class-wc-connect-nux.php b/classes/class-wc-connect-nux.php index 30e02510c..ddeda749e 100644 --- a/classes/class-wc-connect-nux.php +++ b/classes/class-wc-connect-nux.php @@ -267,6 +267,8 @@ public static function get_banner_type_to_display( $status = array() ) { return 'before_jetpack_connection'; case self::JETPACK_CONNECTED: case self::JETPACK_OFFLINE_MODE: + $is_us_store = ( isset( $status['store_country'] ) && 'US' === $status['store_country'] ); + // Priority 1: Standard "after connection" banner (if pending from NUX flow). // This banner also handles initial TOS acceptance if coming from the NUX connection flow. if ( isset( $status['should_display_after_cxn_banner'] ) && $status['should_display_after_cxn_banner'] ) { @@ -276,27 +278,20 @@ public static function get_banner_type_to_display( $status = array() ) { // Priority 2: TOS acceptance banner (if Jetpack connected, but TOS not yet accepted, // and the standard "after connection" banner is not pending). if ( isset( $status['tos_accepted'] ) && ! $status['tos_accepted'] && - isset( $status['can_accept_tos'] ) && $status['can_accept_tos'] ) { + isset( $status['can_accept_tos'] ) && $status['can_accept_tos'] ) { return 'tos_only_banner'; } // For existing users: if TOS accepted, after_cxn_banner done, but contextual_banner flag not yet set, set it now. if ( isset( $status['tos_accepted'] ) && $status['tos_accepted'] && - ( ! isset( $status['should_display_after_cxn_banner'] ) || ! $status['should_display_after_cxn_banner'] ) && - ( ! isset( $status['should_display_contextual_banner'] ) || ! $status['should_display_contextual_banner'] ) + ( ! isset( $status['should_display_after_cxn_banner'] ) || ! $status['should_display_after_cxn_banner'] ) && + ( ! isset( $status['should_display_contextual_banner'] ) || ! $status['should_display_contextual_banner'] ) ) { // This user is eligible for contextual banners but the flag isn't set. Set it now. WC_Connect_Options::update_option( self::SHOULD_SHOW_CONTEXTUAL_BANNER, true ); // Update the status for the current execution path, so Priority 3 check below can pick it up. $status['should_display_contextual_banner'] = true; - } - - // Fallback for non-US stores if contextual banner flag is not set - if ( isset( $status['tos_accepted'] ) && $status['tos_accepted'] && - ( ! isset( $status['should_display_after_cxn_banner'] ) || ! $status['should_display_after_cxn_banner'] ) && - ( ! isset( $status['should_display_contextual_banner'] ) || ! $status['should_display_contextual_banner'] ) - ) { - $is_us_store = ( isset( $status['store_country'] ) && 'US' === $status['store_country'] ); + // Fallback for non-US stores if contextual banner flag is not set if ( ! $is_us_store ) { return 'after_cxn_non_us'; } @@ -306,8 +301,6 @@ public static function get_banner_type_to_display( $status = array() ) { // TOS is accepted, and the contextual flag is set - either previously or by the block above). if ( isset( $status['should_display_contextual_banner'] ) && $status['should_display_contextual_banner'] ) { // Determine which specific contextual banner to show. - $is_us_store = ( isset( $status['store_country'] ) && 'US' === $status['store_country'] ); - if ( $is_us_store ) { if ( isset( $status['is_wcs_shipping_plugin_active'] ) && ! $status['is_wcs_shipping_plugin_active'] ) { return 'after_cxn_us_no_wcs_plugin'; @@ -477,9 +470,9 @@ public function set_up_nux_notices() { // Use the public static method from WC_Connect_Loader $base_url = WC_Connect_Loader::get_wc_connect_base_url(); // Assuming get_wc_connect_base_url is static - wp_register_style( 'wcst_wcshipping_migration_admin_notice', $base_url . 'woocommerce-services-wcshipping-migration-admin-notice-' . $plugin_version . '.css', array(), null ); // phpcs:ignore WordPress.WP.EnqueuedResourceParameters.MissingVersion + wp_register_style( 'wcst_wcshipping_migration_admin_notice', $base_url . 'woocommerce-services-wcshipping-migration-admin-notice-' . $plugin_version . '.css', array() ); // phpcs:ignore WordPress.WP.EnqueuedResourceParameters.MissingVersion // Add 'wp-element' and 'wc_connect_admin' dependency for React and base script - wp_register_script( 'wcst_wcshipping_migration_admin_notice', $base_url . 'woocommerce-services-wcshipping-migration-admin-notice-' . $plugin_version . '.js', array( 'wc_connect_admin', 'wp-element' ), null, true ); // phpcs:ignore WordPress.WP.EnqueuedResourceParameters.MissingVersion + wp_register_script( 'wcst_wcshipping_migration_admin_notice', $base_url . 'woocommerce-services-wcshipping-migration-admin-notice-' . $plugin_version . '.js', array( 'wc_connect_admin', 'wp-element' ), false, true ); // phpcs:ignore WordPress.WP.EnqueuedResourceParameters.MissingVersion // Localize script data - MATCHING the original register_wcshipping_migration_modal // Note: The modal primarily uses data-args, localization is minimal here. @@ -713,7 +706,7 @@ public function show_contextual_after_connection_banner( $banner_type ) { ); break; default: - // Fallback for an unknown banner type, though this shouldn't be reached with current logic. + $this->tracks->opted_in( 'contextual_connection_banner_viewed_unknown' ); return; } From 2c9f3c448d29859ca004a83b9af250da4f7d9e9f Mon Sep 17 00:00:00 2001 From: Fernando Espinosa Date: Mon, 19 May 2025 15:31:30 +0200 Subject: [PATCH 11/11] Fix a bug showing the migration banner --- classes/class-wc-connect-nux.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/classes/class-wc-connect-nux.php b/classes/class-wc-connect-nux.php index ddeda749e..12d5c69b9 100644 --- a/classes/class-wc-connect-nux.php +++ b/classes/class-wc-connect-nux.php @@ -581,8 +581,6 @@ public function show_banner_before_connection() { 'should_show_terms' => true, ); - update_option( 'wcs_nux_any_banner_shown', true ); - $this->show_nux_banner( $banner_content ); } @@ -620,8 +618,6 @@ public function show_banner_after_connection() { $description_base = __( 'You can now enjoy %s.', 'woocommerce-services' ); $feature_list = $this->get_feature_list_for_country( $country ); - update_option( 'wcs_nux_any_banner_shown', true ); - $this->show_nux_banner( array( 'title' => __( 'Setup complete.', 'woocommerce-services' ), @@ -756,8 +752,6 @@ public function show_tos_banner() { $description_base = __( "WooCommerce Tax is almost ready to go! Once you connect your site to WordPress.com you'll have access to %s.", 'woocommerce-services' ); $feature_list = $this->get_feature_list_for_country( $country ); - update_option( 'wcs_nux_any_banner_shown', true ); - $this->show_nux_banner( array( 'title' => __( 'Connect your site to activate WooCommerce Tax', 'woocommerce-services' ),