Commit 04eaffb3dc6 for woocommerce

commit 04eaffb3dc6940e75bd990158802caace099687f
Author: ThelmaChido <41231764+Thelmachido@users.noreply.github.com>
Date:   Thu Jul 16 12:21:09 2026 +0200

    Fix broken paid extensions link on update-core.php (#66075) (#66076)

    * Fix broken paid extensions link on update-core.php (#66075)

    The WooCommerce notice on the Updates screen built the helper URL as
    'admin.php?page=' . self::get_source_page() . ' &section=helper', and the
    stray space before &section was URL-encoded to %20, producing
    admin.php?page=wc-admin%20&section=helper and an access-denied error.

    Remove the space so the link resolves correctly. get_source_page() is kept,
    so both the wc-admin and wc-addons destinations still work.

    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

    * Add regression test for the paid extensions helper link (#66075)

    Extract the My Subscriptions URL into WC_Helper::get_subscriptions_url()
    so it has a testable seam, and add a WC_Helper_Test regression test that
    asserts the URL query contains no stray whitespace and targets
    section=helper for both the wc-admin and wc-addons source pages. This
    guards the exact regression fixed here (a space encoding to %20).

    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

    * Point paid-extensions notice to Extensions › My Subscriptions

    Replace the legacy `&section=helper` target (which only opened the
    WooCommerce landing page, and errored due to a stray space) with the
    modern `wc-admin` My Subscriptions route via add_query_arg(). Escape the
    URL at the notice call site with esc_url(), and update WC_Helper_Test to
    assert the new destination. (#66075)

    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

    ---------

    Co-authored-by: Thelmachido <thelma.mutete@a8c.com>
    Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

diff --git a/plugins/woocommerce/changelog/66075-fix-paid-extensions-helper-link b/plugins/woocommerce/changelog/66075-fix-paid-extensions-helper-link
new file mode 100644
index 00000000000..206de0cb5b8
--- /dev/null
+++ b/plugins/woocommerce/changelog/66075-fix-paid-extensions-helper-link
@@ -0,0 +1,3 @@
+Significance: patch
+Type: fix
+Comment: Fix the broken paid extensions link in the WooCommerce notice on the Updates screen so it opens Extensions › My Subscriptions instead of an access-denied page.
diff --git a/plugins/woocommerce/includes/admin/helper/class-wc-helper.php b/plugins/woocommerce/includes/admin/helper/class-wc-helper.php
index 0b6445ead60..68ddf082126 100644
--- a/plugins/woocommerce/includes/admin/helper/class-wc-helper.php
+++ b/plugins/woocommerce/includes/admin/helper/class-wc-helper.php
@@ -136,6 +136,22 @@ class WC_Helper {
 		return in_array( $page, array( 'wc-admin', 'wc-addons' ), true ) ? $page : 'wc-admin';
 	}

+	/**
+	 * Get the URL of the My Subscriptions screen used in admin notices.
+	 *
+	 * @return string
+	 */
+	private static function get_subscriptions_url() {
+		return add_query_arg(
+			array(
+				'page' => 'wc-admin',
+				'tab'  => 'my-subscriptions',
+				'path' => rawurlencode( '/extensions' ),
+			),
+			admin_url( 'admin.php' )
+		);
+	}
+
 	/**
 	 * Include supporting helper classes.
 	 *
@@ -2523,7 +2539,7 @@ class WC_Helper {
 		return sprintf(
 			/* translators: %1$s: helper url, %2$d: number of extensions */
 			_n( 'Note: You currently have <a href="%1$s">%2$d paid extension</a> which should be updated first before updating WooCommerce.', 'Note: You currently have <a href="%1$s">%2$d paid extensions</a> which should be updated first before updating WooCommerce.', $available, 'woocommerce' ),
-			admin_url( 'admin.php?page=' . self::get_source_page() . ' &section=helper' ),
+			esc_url( self::get_subscriptions_url() ),
 			$available
 		);
 	}
diff --git a/plugins/woocommerce/tests/php/includes/admin/helper/class-wc-helper-test.php b/plugins/woocommerce/tests/php/includes/admin/helper/class-wc-helper-test.php
index 8209f1bbacc..faa88bad370 100644
--- a/plugins/woocommerce/tests/php/includes/admin/helper/class-wc-helper-test.php
+++ b/plugins/woocommerce/tests/php/includes/admin/helper/class-wc-helper-test.php
@@ -19,6 +19,7 @@ class WC_Helper_Test extends \WC_Unit_Test_Case {
 	 */
 	public function tearDown(): void {
 		$this->cleanup_helper_transients();
+		unset( $_GET['page'] );
 		parent::tearDown();
 	}

@@ -291,4 +292,37 @@ class WC_Helper_Test extends \WC_Unit_Test_Case {
 		$this->assertArrayHasKey( $woocommerce_key, $woo_plugins );
 	}

+	/**
+	 * Invoke the private static WC_Helper::get_subscriptions_url().
+	 *
+	 * @return string
+	 */
+	private function get_subscriptions_url(): string {
+		$method = new ReflectionMethod( WC_Helper::class, 'get_subscriptions_url' );
+		$method->setAccessible( true );
+		return (string) $method->invoke( null );
+	}
+
+	/**
+	 * @testdox get_subscriptions_url query contains no stray whitespace (regression: GH #66075).
+	 */
+	public function test_subscriptions_url_query_has_no_whitespace(): void {
+		$_GET['page'] = 'wc-admin';
+
+		$query = wp_parse_url( $this->get_subscriptions_url(), PHP_URL_QUERY );
+
+		$this->assertIsString( $query );
+		$this->assertStringNotContainsString( ' ', $query );
+		$this->assertStringNotContainsString( '%20', $query );
+	}
+
+	/**
+	 * @testdox get_subscriptions_url targets the Extensions - My Subscriptions screen.
+	 */
+	public function test_subscriptions_url_targets_my_subscriptions(): void {
+		$this->assertStringEndsWith(
+			'admin.php?page=wc-admin&tab=my-subscriptions&path=%2Fextensions',
+			$this->get_subscriptions_url()
+		);
+	}
 }