Commit 0e47e04c3b4 for woocommerce
commit 0e47e04c3b4566ccd47234980a4c8f88ce0047cb
Author: Luigi Teschio <gigitux@gmail.com>
Date: Mon Aug 17 14:55:23 2026 +0200
Fix product menu highlighting in empty catalog flow (#67655)
* Fix product task menu highlighting
* Add changelog entry for product task menu fix
* improve comment
* address feedback
diff --git a/plugins/woocommerce/changelog/fix-56112-product-task-menu b/plugins/woocommerce/changelog/fix-56112-product-task-menu
new file mode 100644
index 00000000000..9838de8a947
--- /dev/null
+++ b/plugins/woocommerce/changelog/fix-56112-product-task-menu
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Correctly highlight Products submenu items throughout the empty All Products add-product flow.
diff --git a/plugins/woocommerce/client/admin/client/layout/controller.js b/plugins/woocommerce/client/admin/client/layout/controller.js
index a76c6de8f1f..15d45da1a95 100644
--- a/plugins/woocommerce/client/admin/client/layout/controller.js
+++ b/plugins/woocommerce/client/admin/client/layout/controller.js
@@ -91,6 +91,18 @@ export const getPages = ( reports = [] ) => {
capability: 'manage_woocommerce',
} );
+ pages.push( {
+ container: Homescreen,
+ path: '/add-product',
+ breadcrumbs: [ ...initialBreadcrumbs, __( 'Products', 'woocommerce' ) ],
+ wpMenuUrl: 'edit.php?post_type=product',
+ wpOpenMenu: 'menu-posts-product',
+ navArgs: {
+ id: 'woocommerce-home',
+ },
+ capability: 'manage_woocommerce',
+ } );
+
if ( isFeatureEnabled( 'analytics' ) ) {
pages.push( {
container: Dashboard,
@@ -494,6 +506,10 @@ window.wpNavMenuClassChange = function ( page, url ) {
? `li > a[href$="${ pageUrl }"], li > a[href*="${ pageUrl }?"]`
: `li > a[href*="${ pageUrl }"]`;
+ if ( page.wpMenuUrl ) {
+ currentItemsSelector = `li > a[href$="${ page.wpMenuUrl }"]`;
+ }
+
// 3. Handle parent paths with proper hierarchy
const parentPath = page.navArgs?.parentPath;
if ( parentPath ) {
diff --git a/plugins/woocommerce/client/admin/client/task-lists/components/back-button.tsx b/plugins/woocommerce/client/admin/client/task-lists/components/back-button.tsx
index 2ee755a117c..9f548b95163 100644
--- a/plugins/woocommerce/client/admin/client/task-lists/components/back-button.tsx
+++ b/plugins/woocommerce/client/admin/client/task-lists/components/back-button.tsx
@@ -4,7 +4,7 @@
import { __ } from '@wordpress/i18n';
import { Tooltip } from '@wordpress/components';
import { Icon, chevronLeft } from '@wordpress/icons';
-import { getHistory, updateQueryString } from '@woocommerce/navigation';
+import { updateQueryString } from '@woocommerce/navigation';
import { ENTER, SPACE } from '@wordpress/keycodes';
import { recordEvent } from '@woocommerce/tracks';
@@ -24,7 +24,7 @@ export const BackButton = ( { title }: BackButtonProps ) => {
recordEvent( 'topbar_back_button', {
page_name: title,
} );
- updateQueryString( {}, getHistory().location.pathname, {} );
+ updateQueryString( {}, '/', {} );
};
// if it's a task list page, render a back button to the homescreen
diff --git a/plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/Products.php b/plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/Products.php
index 978c3fe95de..e040331b017 100644
--- a/plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/Products.php
+++ b/plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/Products.php
@@ -31,6 +31,8 @@ class Products extends Task {
parent::__construct( $task_list );
add_action( 'admin_enqueue_scripts', array( $this, 'possibly_add_import_return_notice_script' ) );
add_action( 'admin_enqueue_scripts', array( $this, 'possibly_add_load_sample_return_notice_script' ) );
+ // Onboarding tasks open a pre-created draft via post.php, which WordPress otherwise highlights as All Products.
+ add_filter( 'submenu_file', array( $this, 'highlight_add_product_menu' ) );
add_action( 'woocommerce_update_product', array( $this, 'maybe_set_has_product_transient' ), 10, 2 );
add_action( 'woocommerce_new_product', array( $this, 'maybe_set_has_product_transient' ), 10, 2 );
@@ -44,6 +46,26 @@ class Products extends Task {
add_action( 'deleted_post_product', array( $this, 'on_product_deleted' ) );
}
+ /**
+ * Highlight Add product while creating a product from the onboarding task.
+ *
+ * @internal
+ *
+ * @param mixed $submenu_file Current submenu file.
+ * @return mixed
+ */
+ public function highlight_add_product_menu( $submenu_file ) {
+ $screen = get_current_screen();
+ $tutorial = wc_clean( wp_unslash( $_GET['tutorial'] ?? '' ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
+ $tutorial = is_string( $tutorial ) ? $tutorial : '';
+
+ if ( ! $this->is_active() || ! wc_string_to_bool( $tutorial ) || ! $screen || 'post' !== $screen->base || 'product' !== $screen->post_type ) {
+ return $submenu_file;
+ }
+
+ return 'post-new.php?post_type=product';
+ }
+
/**
* ID.
*
@@ -308,7 +330,7 @@ class Products extends Task {
return;
}
- wp_safe_redirect( admin_url( 'admin.php?page=wc-admin&task=products' ) );
+ wp_safe_redirect( admin_url( 'admin.php?page=wc-admin&path=/add-product&task=products' ) );
exit;
}
}
diff --git a/plugins/woocommerce/tests/e2e/tests/onboarding/add-product-task.spec.ts b/plugins/woocommerce/tests/e2e/tests/onboarding/add-product-task.spec.ts
index 264a6b019ef..5bf49547d42 100644
--- a/plugins/woocommerce/tests/e2e/tests/onboarding/add-product-task.spec.ts
+++ b/plugins/woocommerce/tests/e2e/tests/onboarding/add-product-task.spec.ts
@@ -12,7 +12,6 @@ import {
import { expect, test } from '../../fixtures/fixtures';
import { ADMIN_STATE_PATH } from '../../playwright.config';
-// eslint-disable-next-line @typescript-eslint/no-explicit-any
const hide_task_list = async ( restApi: any, task_list_name: string ) => {
const {
status,
@@ -26,7 +25,6 @@ const hide_task_list = async ( restApi: any, task_list_name: string ) => {
return isHidden === true;
};
-// eslint-disable-next-line @typescript-eslint/no-explicit-any
const show_task_list = async ( restApi: any, task_list_name: string ) => {
const {
status,
@@ -104,6 +102,21 @@ test.describe( 'Add Product Task', () => {
await expect(
page.getByRole( 'menuitem', { name: 'Grouped product' } )
).toBeVisible();
+ await expect(
+ page.locator( '#toplevel_page_woocommerce' )
+ ).toHaveClass( /wp-has-current-submenu/ );
+ await expect( page.locator( '#menu-posts-product' ) ).not.toHaveClass(
+ /wp-has-current-submenu/
+ );
+
+ await page
+ .getByRole( 'menuitem', { name: 'Physical product' } )
+ .click();
+ await expect(
+ page.locator(
+ '#menu-posts-product .wp-submenu li.current > a[href="post-new.php?post_type=product"]'
+ )
+ ).toBeVisible();
} );
test( 'Products page redirects to add product task when no products exist', async ( {
@@ -113,7 +126,9 @@ test.describe( 'Add Product Task', () => {
await page.goto( 'wp-admin/edit.php?post_type=product' );
// Verify redirect to add product task
- await expect( page ).toHaveURL( /.+task=products/ );
+ await expect( page ).toHaveURL(
+ /.+path=%2Fadd-product.+task=products/
+ );
await expect(
page.getByRole( 'menuitem', { name: 'Physical product' } )
).toBeVisible();
@@ -123,6 +138,20 @@ test.describe( 'Add Product Task', () => {
await expect(
page.getByRole( 'menuitem', { name: 'Grouped product' } )
).toBeVisible();
+ await expect( page.locator( '#menu-posts-product' ) ).toHaveClass(
+ /wp-has-current-submenu/
+ );
+ await expect(
+ page.locator(
+ '#menu-posts-product .wp-submenu li.current > a[href="edit.php?post_type=product"]'
+ )
+ ).toBeVisible();
+
+ await page.getByTestId( 'header-back-button' ).click();
+ await expect( page ).toHaveURL( /admin\.php\?page=wc-admin$/ );
+ await expect(
+ page.locator( '#toplevel_page_woocommerce' )
+ ).toHaveClass( /wp-has-current-submenu/ );
} );
test( 'Products page shows products table when products exist', async ( {
@@ -174,7 +203,9 @@ test.describe( 'Add Product Task', () => {
await page.goto( 'wp-admin/edit.php?post_type=product' );
// Verify redirect to add product task
- await expect( page ).toHaveURL( /.+task=products/ );
+ await expect( page ).toHaveURL(
+ /.+path=%2Fadd-product.+task=products/
+ );
await expect(
page.getByRole( 'menuitem', { name: 'Physical product' } )
).toBeVisible();