Commit f6a8c2586a6 for woocommerce
commit f6a8c2586a6121e244ce6a391e344a7aac6924ed
Author: verofasulo <98944206+verofasulo@users.noreply.github.com>
Date: Thu May 14 00:04:04 2026 +0200
Redesign the experimental products app header (#64851)
* Replace Add new product button with a product-type dropdown menu
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Fix Add new dropdown layout to match the Figma design
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Widen Add new dropdown and adjust item spacing
* Make Add new menu items stretch to popover width
* Force popover content to fill width so menu items have room
* Tighten Add new menu to 300px, 12px icon gap, white chevron
* Beat WP design-system specificity on Add new menu padding and gap
* Set 16px spacing between Add new menu items
* Set 16px padding at top/bottom of Add new menu
* Use 16px padding between Add new menu items and popover edges
* Reduce Add new menu top/bottom padding to 8px (16px total to content)
* Swap Add new menu icons: link, alignNone, category
* Rename first menu item to 'Simple product'
* Avoid widows in Add new menu descriptions with text-wrap: pretty
* Use inset focus ring on Add new menu items so it isn't clipped
* Pre-select product type from URL params on classic product editor
* Match prototype header: tighter bottom padding, divider below tabs, shorter search label
* Add 16px gap between toolbar divider and filter chip row
* Add 16px gap between filter chips and table header
* Bump filter row padding-bottom so chip-to-table gap is 16px
* remove not necessary changes
* remove custom CSS
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Luigi Teschio <gigitux@gmail.com>
diff --git a/packages/js/experimental-products-app/changelog/update-products-app-add-new-menu b/packages/js/experimental-products-app/changelog/update-products-app-add-new-menu
new file mode 100644
index 00000000000..5950aecd5c9
--- /dev/null
+++ b/packages/js/experimental-products-app/changelog/update-products-app-add-new-menu
@@ -0,0 +1,4 @@
+Significance: minor
+Type: update
+
+Replace the single "Add new product" button with a dropdown menu offering physical, variable, grouped, downloadable, and affiliate product types in the experimental products app header.
diff --git a/packages/js/experimental-products-app/src/product-list/index.tsx b/packages/js/experimental-products-app/src/product-list/index.tsx
index 1b94e33492f..afb659e200c 100644
--- a/packages/js/experimental-products-app/src/product-list/index.tsx
+++ b/packages/js/experimental-products-app/src/product-list/index.tsx
@@ -7,12 +7,21 @@ import { privateApis as routerPrivateApis } from '@wordpress/router';
import { store as coreStore } from '@wordpress/core-data';
import { useSelect } from '@wordpress/data';
import clsx from 'clsx';
-import { Button, Stack, Tabs } from '@wordpress/ui';
+import { Button, Icon, Stack, Tabs } from '@wordpress/ui';
+import { privateApis as componentsPrivateApis } from '@wordpress/components';
import { privateApis as editorPrivateApis } from '@wordpress/editor';
import { Page } from '@wordpress/admin-ui';
import { addQueryArgs } from '@wordpress/url';
import { getAdminLink } from '@woocommerce/settings';
import { __ } from '@wordpress/i18n';
+import {
+ tag,
+ alignNone,
+ category,
+ link,
+ chevronDown,
+ chevronUp,
+} from '@wordpress/icons';
/**
* Internal dependencies
@@ -37,9 +46,47 @@ import {
} from './utils';
import { useProductActions } from '../dataviews-actions';
+const { Menu } = unlock( componentsPrivateApis );
const { usePostActions } = unlock( editorPrivateApis );
const { useHistory, useLocation } = unlock( routerPrivateApis );
+const PRODUCT_TYPE_MENU_ITEMS = [
+ {
+ key: 'simple',
+ icon: tag,
+ label: __( 'Simple product', 'woocommerce' ),
+ info: __( 'A standalone item with no variations.', 'woocommerce' ),
+ queryArgs: {},
+ },
+ {
+ key: 'variable',
+ icon: alignNone,
+ label: __( 'Variable product', 'woocommerce' ),
+ info: __(
+ 'An item with variations like color or size.',
+ 'woocommerce'
+ ),
+ queryArgs: { product_type: 'variable' },
+ },
+ {
+ key: 'grouped',
+ icon: category,
+ label: __( 'Grouped product', 'woocommerce' ),
+ info: __( 'A collection of related products.', 'woocommerce' ),
+ queryArgs: { product_type: 'grouped' },
+ },
+ {
+ key: 'external',
+ icon: link,
+ label: __( 'Affiliate product', 'woocommerce' ),
+ info: __(
+ 'A product you promote and earn commission on.',
+ 'woocommerce'
+ ),
+ queryArgs: { product_type: 'external' },
+ },
+] as const;
+
export type ProductListProps = {
subTitle?: string;
className?: string;
@@ -82,6 +129,7 @@ export default function ProductList( {
const [ selection, setSelection ] = useState( () =>
getSelectionFromPostId( postId )
);
+ const [ isMenuOpen, setIsMenuOpen ] = useState( false );
useEffect( () => {
setSelection( getSelectionFromPostId( postId ) );
@@ -223,19 +271,40 @@ export default function ProductList( {
>
{ __( 'Import', 'woocommerce' ) }
</Button>
- <Button
- size="compact"
- disabled={ canCreateRecord === false }
- onClick={ () =>
- ( window.location.href = getAdminLink(
- addQueryArgs( 'post-new.php', {
- post_type: 'product',
- } )
- ) )
- }
- >
- { __( 'Add new product', 'woocommerce' ) }
- </Button>
+ <Menu onOpenChange={ setIsMenuOpen } placement="bottom-end">
+ <Menu.TriggerButton
+ disabled={ canCreateRecord === false }
+ render={ <Button variant="solid" size="compact" /> }
+ >
+ { __( 'Add new', 'woocommerce' ) }
+ <Button.Icon
+ icon={ isMenuOpen ? chevronUp : chevronDown }
+ />
+ </Menu.TriggerButton>
+ <Menu.Popover>
+ <Menu.Group>
+ { PRODUCT_TYPE_MENU_ITEMS.map( ( item ) => (
+ <Menu.Item
+ key={ item.key }
+ prefix={ <Icon icon={ item.icon } /> }
+ onClick={ () => {
+ window.location.href = getAdminLink(
+ addQueryArgs( 'post-new.php', {
+ post_type: 'product',
+ ...item.queryArgs,
+ } )
+ );
+ } }
+ >
+ <Menu.ItemLabel>{ item.label }</Menu.ItemLabel>
+ <Menu.ItemHelpText>
+ { item.info }
+ </Menu.ItemHelpText>
+ </Menu.Item>
+ ) ) }
+ </Menu.Group>
+ </Menu.Popover>
+ </Menu>
</Stack>
);
@@ -244,7 +313,7 @@ export default function ProductList( {
className={ classes }
ariaLabel={ __( 'Products', 'woocommerce' ) }
subTitle={ __(
- 'Add, edit, and manage the products you sell in your store',
+ 'Add, edit, and manage the products you sell in your store.',
'woocommerce'
) }
title={ __( 'Products', 'woocommerce' ) }
@@ -307,14 +376,14 @@ export default function ProductList( {
</Tabs.Root>
<Stack direction="row" align="center" gap="xs">
<DataViews.Search
- label={ __( 'Search products', 'woocommerce' ) }
+ label={ __( 'Search', 'woocommerce' ) }
/>
<DataViews.FiltersToggle />
<DataViews.LayoutSwitcher />
<DataViews.ViewConfig />
</Stack>
</Stack>
- <DataViews.FiltersToggled />
+ <DataViews.FiltersToggled className="woocommerce-product-list__filters" />
<DataViews.Layout />
<DataViews.Footer />
</DataViews>