Commit 56202f48429 for woocommerce

commit 56202f48429b020b826a149b23c289663a5a21ad
Author: Luigi Teschio <gigitux@gmail.com>
Date:   Fri May 29 16:01:32 2026 +0200

    Deprecate Product Editor v2 (#65333)

    * Add deprecation notices for the product editor and its APIs ahead of removal in WooCommerce 11.0

    * improve copy

    * update copy after feedback

    * deprecated registerProductEditorBlockType

    * deprecated hooks

    * add changelog

    * clean up codebase

    * lint code and remove not necessary test

    * use wc_do_deprecated_action

    * Add deprecation warnings for block template actions in tests

    * remove feedback bar

diff --git a/packages/js/product-editor/changelog/add-product-editor-deprecation-notices b/packages/js/product-editor/changelog/add-product-editor-deprecation-notices
new file mode 100644
index 00000000000..d472acf2e2d
--- /dev/null
+++ b/packages/js/product-editor/changelog/add-product-editor-deprecation-notices
@@ -0,0 +1,4 @@
+Significance: minor
+Type: add
+
+Add WooCommerce 11.0 removal notices for the deprecated product editor package and extension APIs.
diff --git a/packages/js/product-editor/src/components/block-editor/block-editor.tsx b/packages/js/product-editor/src/components/block-editor/block-editor.tsx
index 2dcc2f6ec2f..61a26166346 100644
--- a/packages/js/product-editor/src/components/block-editor/block-editor.tsx
+++ b/packages/js/product-editor/src/components/block-editor/block-editor.tsx
@@ -17,10 +17,13 @@ import {
 import { dispatch, select, useDispatch, useSelect } from '@wordpress/data';
 import { uploadMedia } from '@wordpress/media-utils';
 import { __ } from '@wordpress/i18n';
+import { Button } from '@wordpress/components';
+import apiFetch from '@wordpress/api-fetch';
 import { useLayoutTemplate } from '@woocommerce/block-templates';
 import { store as keyboardShortcutsStore } from '@wordpress/keyboard-shortcuts';
 import { Product } from '@woocommerce/data';
 import { getPath, getQuery } from '@woocommerce/navigation';
+import { getAdminLink, getSetting } from '@woocommerce/settings';
 import {
 	BlockContextProvider,
 	BlockEditorKeyboardShortcuts,
@@ -41,10 +44,14 @@ import { useProductTemplate } from '../../hooks/use-product-template';
 import { PostTypeContext } from '../../contexts/post-type-context';
 import { wooProductEditorUiStore } from '../../store/product-editor-ui';
 import { ProductEditorSettings } from '../editor';
+import { Notice } from '../notice';
 import { BlockEditorProps } from './types';
 import { LoadingState } from './loading-state';
 import type { ProductTemplate } from '../../types';

+const PRODUCT_BLOCK_EDITOR_FEATURE_OPTION =
+	'woocommerce_feature_product_block_editor_enabled';
+
 const PluginArea = lazy( () =>
 	import( '@wordpress/plugins' ).then( ( module ) => ( {
 		default: module.PluginArea,
@@ -73,6 +80,26 @@ function getLayoutTemplateId(
 	return 'simple-product';
 }

+function getClassicProductEditorUrl(
+	productId: number,
+	postType: string,
+	product: Partial< Product > | undefined
+) {
+	const parentProductId =
+		postType === 'product_variation' &&
+		product &&
+		'parent_id' in product &&
+		typeof product.parent_id === 'number'
+			? product.parent_id
+			: productId;
+
+	if ( parentProductId > 0 ) {
+		return getAdminLink( `post.php?post=${ parentProductId }&action=edit` );
+	}
+
+	return getAdminLink( 'post-new.php?post_type=product' );
+}
+
 export function BlockEditor( {
 	context,
 	postType,
@@ -176,6 +203,52 @@ export function BlockEditor( {
 		{ enabled: productId !== -1 }
 	);

+	const { _feature_nonce: featureNonce = '' } = getSetting< {
+		_feature_nonce?: string;
+	} >( 'admin', {} );
+	const classicProductEditorUrl = getClassicProductEditorUrl(
+		productId,
+		postType,
+		product
+	);
+	const disableProductBlockEditorUrl = new URL( classicProductEditorUrl );
+	disableProductBlockEditorUrl.searchParams.set(
+		'product_block_editor',
+		'0'
+	);
+	disableProductBlockEditorUrl.searchParams.set(
+		'_feature_nonce',
+		featureNonce
+	);
+	const [ isDisablingProductBlockEditor, setIsDisablingProductBlockEditor ] =
+		useState( false );
+
+	const disableProductBlockEditor = async (
+		event: React.MouseEvent< HTMLAnchorElement >
+	) => {
+		event.preventDefault();
+
+		if ( isDisablingProductBlockEditor ) {
+			return;
+		}
+
+		setIsDisablingProductBlockEditor( true );
+
+		try {
+			await apiFetch( {
+				path: `/wc/v3/settings/advanced/${ PRODUCT_BLOCK_EDITOR_FEATURE_OPTION }`,
+				method: 'POST',
+				data: {
+					value: 'no',
+				},
+			} );
+
+			window.location.href = classicProductEditorUrl;
+		} catch {
+			window.location.href = disableProductBlockEditorUrl.toString();
+		}
+	};
+
 	const productTemplateId = useMemo(
 		() =>
 			product?.meta_data?.find(
@@ -310,6 +383,28 @@ export function BlockEditor( {

 	return (
 		<div className="woocommerce-product-block-editor">
+			<Notice
+				className="woocommerce-product-block-editor__deprecation-notice"
+				type="warning"
+				title={ __(
+					'Switch to the classic editor before WooCommerce 11.0',
+					'woocommerce'
+				) }
+				content={ __(
+					"We're removing this version of the product editor in WooCommerce 11.0. The classic editor has the same features and your products won't change, so we recommend switching now.",
+					'woocommerce'
+				) }
+			>
+				<Button
+					className="woocommerce-product-block-editor__deprecation-notice-action"
+					href={ disableProductBlockEditorUrl.toString() }
+					isBusy={ isDisablingProductBlockEditor }
+					onClick={ disableProductBlockEditor }
+					variant="secondary"
+				>
+					{ __( 'Switch to classic editor', 'woocommerce' ) }
+				</Button>
+			</Notice>
 			<BlockContextProvider value={ context }>
 				<BlockEditorProvider
 					value={ blocks }
diff --git a/packages/js/product-editor/src/components/block-editor/style.scss b/packages/js/product-editor/src/components/block-editor/style.scss
index 6f6dc099faf..94f915d3988 100644
--- a/packages/js/product-editor/src/components/block-editor/style.scss
+++ b/packages/js/product-editor/src/components/block-editor/style.scss
@@ -28,6 +28,23 @@
 		text-decoration: none;
 	}

+	&__deprecation-notice {
+		box-sizing: border-box;
+		max-width: 650px;
+		margin: 0 calc(2 * $gap) $gap-large;
+		background-color: #fff8e5;
+		border-left: 4px solid #b26200;
+
+		@include breakpoint(">782px") {
+			margin-left: auto;
+			margin-right: auto;
+		}
+	}
+
+	&__deprecation-notice-action {
+		margin-top: $gap-small;
+	}
+
 	/*
 	 * Override default block margins and layout applied for themes without a theme.json file.
 	 *
diff --git a/packages/js/product-editor/src/components/feedback-bar/feedback-bar.tsx b/packages/js/product-editor/src/components/feedback-bar/feedback-bar.tsx
deleted file mode 100644
index 007ceb75779..00000000000
--- a/packages/js/product-editor/src/components/feedback-bar/feedback-bar.tsx
+++ /dev/null
@@ -1,238 +0,0 @@
-/**
- * External dependencies
- */
-import { __ } from '@wordpress/i18n';
-import {
-	BaseControl,
-	Button,
-	TextControl,
-	TextareaControl,
-} from '@wordpress/components';
-import {
-	createElement,
-	createInterpolateElement,
-	Fragment,
-} from '@wordpress/element';
-import { closeSmall } from '@wordpress/icons';
-import { Pill } from '@woocommerce/components';
-import { useCustomerEffortScoreModal } from '@woocommerce/customer-effort-score';
-import { recordEvent } from '@woocommerce/tracks';
-
-/**
- * Internal dependencies
- */
-import { PRODUCT_EDITOR_FEEDBACK_CES_ACTION } from '../../constants';
-import { useFeedbackBar } from '../../hooks/use-feedback-bar';
-import { isValidEmail } from '../../utils';
-
-export type FeedbackBarProps = {
-	productType?: string;
-};
-
-export function FeedbackBar( { productType }: FeedbackBarProps ) {
-	const { hideFeedbackBar, shouldShowFeedbackBar } = useFeedbackBar();
-	const { showCesModal, showProductMVPFeedbackModal } =
-		useCustomerEffortScoreModal();
-
-	const getProductTracksProps = () => {
-		const tracksProps = {
-			product_type: productType,
-		};
-
-		return tracksProps;
-	};
-
-	const onShareFeedbackClick = () => {
-		recordEvent( 'product_editor_feedback_bar_share_feedback_click', {
-			...getProductTracksProps(),
-		} );
-
-		showCesModal(
-			{
-				action: PRODUCT_EDITOR_FEEDBACK_CES_ACTION,
-				showDescription: false,
-				title: __(
-					'What do you think of the new product editor?',
-					'woocommerce'
-				),
-				firstQuestion: __(
-					'The product editing screen is easy to use',
-					'woocommerce'
-				),
-				secondQuestion: __(
-					'Product editor is easy to use',
-					'woocommerce'
-				),
-				onsubmitLabel: __(
-					"Thanks for the feedback — we'll put it to good use!",
-					'woocommerce'
-				),
-				shouldShowComments: () => false,
-				getExtraFieldsToBeShown: (
-					values: {
-						email?: string;
-						additional_thoughts?: string;
-					},
-					setValues: ( value: {
-						email?: string;
-						additional_thoughts?: string;
-					} ) => void,
-					errors: Record< string, string > | undefined
-				) => (
-					<Fragment>
-						<BaseControl
-							id={ 'feedback_additional_thoughts' }
-							className="woocommerce-product-feedback__additional-thoughts"
-							label={ createInterpolateElement(
-								__(
-									'ADDITIONAL THOUGHTS <optional />',
-									'woocommerce'
-								),
-								{
-									optional: (
-										<span className="woocommerce-product-feedback__optional-input">
-											{ __(
-												'(OPTIONAL)',
-												'woocommerce'
-											) }
-										</span>
-									),
-								}
-							) }
-						>
-							<TextareaControl
-								value={ values.additional_thoughts || '' }
-								onChange={ ( value: string ) =>
-									setValues( {
-										...values,
-										additional_thoughts: value,
-									} )
-								}
-								help={ errors?.additional_thoughts || '' }
-							/>
-						</BaseControl>
-						<BaseControl
-							id={ 'feedback_email' }
-							className="woocommerce-product-feedback__email"
-							label={ createInterpolateElement(
-								__(
-									'YOUR EMAIL ADDRESS <optional />',
-									'woocommerce'
-								),
-								{
-									optional: (
-										<span className="woocommerce-product-feedback__optional-input">
-											{ __(
-												'(OPTIONAL)',
-												'woocommerce'
-											) }
-										</span>
-									),
-								}
-							) }
-						>
-							<TextControl
-								value={ values.email || '' }
-								onChange={ ( value: string ) =>
-									setValues( { ...values, email: value } )
-								}
-								help={ errors?.email || '' }
-							/>
-							<span>
-								{ __(
-									'In case you want to participate in further discussion and future user research.',
-									'woocommerce'
-								) }
-							</span>
-						</BaseControl>
-					</Fragment>
-				),
-				validateExtraFields: ( {
-					email = '',
-					additional_thoughts = '',
-				}: {
-					email?: string;
-					additional_thoughts?: string;
-				} ) => {
-					const errors: Record< string, string > | undefined = {};
-					if ( email.length > 0 && ! isValidEmail( email ) ) {
-						errors.email = __(
-							'Please enter a valid email address.',
-							'woocommerce'
-						);
-					}
-					if ( additional_thoughts?.length > 500 ) {
-						errors.additional_thoughts = __(
-							'Please enter no more than 500 characters.',
-							'woocommerce'
-						);
-					}
-					return errors;
-				},
-			},
-			{},
-			{
-				type: 'snackbar',
-			}
-		);
-	};
-
-	const onTurnOffEditorClick = () => {
-		recordEvent( 'product_editor_feedback_bar_turnoff_editor_click', {
-			...getProductTracksProps(),
-		} );
-
-		hideFeedbackBar();
-
-		showProductMVPFeedbackModal();
-	};
-
-	const onHideFeedbackBarClick = () => {
-		recordEvent( 'product_editor_feedback_bar_dismiss_click', {
-			...getProductTracksProps(),
-		} );
-
-		hideFeedbackBar();
-	};
-
-	return (
-		<>
-			{ shouldShowFeedbackBar && (
-				<div className="woocommerce-product-mvp-ces-footer">
-					<Pill>Beta</Pill>
-					<div className="woocommerce-product-mvp-ces-footer__message">
-						{ createInterpolateElement(
-							__(
-								'How is your experience with the new product editor? <span><shareButton>Share feedback</shareButton> or <turnOffButton>turn it off</turnOffButton></span>',
-								'woocommerce'
-							),
-							{
-								span: (
-									<span className="woocommerce-product-mvp-ces-footer__message-buttons" />
-								),
-								shareButton: (
-									<Button
-										variant="link"
-										onClick={ onShareFeedbackClick }
-									/>
-								),
-								turnOffButton: (
-									<Button
-										onClick={ onTurnOffEditorClick }
-										variant="link"
-									/>
-								),
-							}
-						) }
-					</div>
-					<Button
-						className="woocommerce-product-mvp-ces-footer__close-button"
-						icon={ closeSmall }
-						label={ __( 'Hide this message', 'woocommerce' ) }
-						onClick={ onHideFeedbackBarClick }
-					></Button>
-				</div>
-			) }
-		</>
-	);
-}
diff --git a/packages/js/product-editor/src/components/feedback-bar/index.ts b/packages/js/product-editor/src/components/feedback-bar/index.ts
deleted file mode 100644
index a2f6666382f..00000000000
--- a/packages/js/product-editor/src/components/feedback-bar/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from './feedback-bar';
diff --git a/packages/js/product-editor/src/components/feedback-bar/style.scss b/packages/js/product-editor/src/components/feedback-bar/style.scss
deleted file mode 100644
index 0db484d63df..00000000000
--- a/packages/js/product-editor/src/components/feedback-bar/style.scss
+++ /dev/null
@@ -1,101 +0,0 @@
-$gutenberg-blue: var(--wp-admin-theme-color);
-
-.woocommerce-product-mvp-ces-footer {
-	display: flex;
-	flex-direction: row;
-	justify-content: center;
-	align-items: center;
-	// the left/right padding is set to this to match the padding of
-	// .block-editor-block-list__layout.is-root-container and
-	// .editor-styles-wrapper combined
-	padding: $gap calc(2 * $gap + $gap-small);
-	gap: $gap;
-
-	@include breakpoint(">782px") {
-		padding: $gap 0;
-		max-width: 650px;
-		margin: 0 auto;
-	}
-
-	.woocommerce-pill {
-		background-color: $studio-yellow-5;
-		border: 0;
-		font-size: 1em;
-	}
-
-	&__close-button {
-		padding: 0;
-	}
-
-	&__message {
-		flex: 1;
-		flex-wrap: wrap;
-		align-items: center;
-		white-space: pre-wrap;
-	}
-
-	&__message-buttons {
-		white-space: nowrap;
-
-		button.is-link {
-			text-decoration: none;
-		}
-	}
-}
-.woocommerce-customer-effort-score {
-	.components-modal__content {
-		> p {
-			text-transform: uppercase;
-			color: $gray-900;
-		}
-		> .components-base-control {
-			margin-top: $gap-small;
-		}
-
-		.woocommerce-product-feedback__additional-thoughts,
-		.woocommerce-product-feedback__email {
-			.components-base-control__help {
-				color: $error-red;
-			}
-			.components-base-control__label {
-				color: $gray-900;
-				line-height: 16px;
-				text-transform: uppercase;
-				.woocommerce-product-feedback__optional-input {
-					color: $gray-700;
-				}
-			}
-			.components-base-control__field {
-				> span {
-					font-size: 12px;
-					line-height: 16px;
-					color: $gray-700;
-				}
-			}
-		}
-	}
-	&__selection {
-		.components-radio-control__option {
-			margin-right: 0;
-			label {
-				color: $gray-900;
-				padding: 1em 0;
-				width: 8.8em;
-				height: 80px;
-				&::before {
-					margin: $gap-smaller 0;
-				}
-				&:hover {
-					box-shadow: 0 0 0 1.5px $gutenberg-blue;
-					border-radius: 2px;
-					background-color: #fff;
-				}
-			}
-		}
-	}
-	&__errors {
-		> p {
-			color: $error-red;
-		}
-	}
-}
diff --git a/packages/js/product-editor/src/components/feedback-bar/test/feedback-bar.test.tsx b/packages/js/product-editor/src/components/feedback-bar/test/feedback-bar.test.tsx
deleted file mode 100644
index 1d3059f7845..00000000000
--- a/packages/js/product-editor/src/components/feedback-bar/test/feedback-bar.test.tsx
+++ /dev/null
@@ -1,43 +0,0 @@
-/**
- * External dependencies
- */
-import { act, fireEvent, render, screen } from '@testing-library/react';
-import { createElement } from '@wordpress/element';
-import { recordEvent } from '@woocommerce/tracks';
-
-/**
- * Internal dependencies
- */
-import { FeedbackBar } from '../feedback-bar';
-import { useFeedbackBar } from '../../../hooks/use-feedback-bar';
-
-jest.mock( '../../../hooks/use-feedback-bar', () => ( {
-	...jest.requireActual( '../../../hooks/use-feedback-bar' ),
-	useFeedbackBar: jest.fn(),
-} ) );
-
-jest.mock( '@woocommerce/tracks', () => ( {
-	...jest.requireActual( '@woocommerce/tracks' ),
-	recordEvent: jest.fn(),
-} ) );
-
-describe( 'FeedbackBar', () => {
-	beforeEach( () => {
-		jest.clearAllMocks();
-	} );
-	it( 'should trigger product_editor_feedback_bar_turnoff_editor_click event when clicking turn off editor', () => {
-		( useFeedbackBar as jest.Mock ).mockImplementation( () => ( {
-			hideFeedbackBar: () => {},
-			shouldShowFeedbackBar: true,
-		} ) );
-		render( <FeedbackBar productType={ 'testing' } /> );
-
-		act( () => {
-			fireEvent.click( screen.getByText( 'turn it off' ) );
-		} );
-		expect( recordEvent ).toBeCalledWith(
-			'product_editor_feedback_bar_turnoff_editor_click',
-			{ product_type: 'testing' }
-		);
-	} );
-} );
diff --git a/packages/js/product-editor/src/components/index.ts b/packages/js/product-editor/src/components/index.ts
index 20fcbefa264..9721a8bd65f 100644
--- a/packages/js/product-editor/src/components/index.ts
+++ b/packages/js/product-editor/src/components/index.ts
@@ -19,7 +19,6 @@ export {
 	BlockIcon as __experimentalBlockIcon,
 	type BlockIconProps,
 } from './block-icon';
-export { FeedbackBar as __experimentalProductMVPCESFooter } from './feedback-bar';
 export { ProductMVPFeedbackModal as __experimentalProductMVPFeedbackModal } from './product-mvp-feedback-modal';
 export { ProductMVPFeedbackModalContainer as __experimentalProductMVPFeedbackModalContainer } from './product-mvp-feedback-modal-container';
 export {
diff --git a/packages/js/product-editor/src/index.ts b/packages/js/product-editor/src/index.ts
index be6145a3587..9fe4ec65fbd 100644
--- a/packages/js/product-editor/src/index.ts
+++ b/packages/js/product-editor/src/index.ts
@@ -1,9 +1,20 @@
+/**
+ * External dependencies
+ */
+import deprecated from '@wordpress/deprecated';
+
 /**
  * Internal dependencies
  */
 import registerProductEditorUiStore from './store/product-editor-ui';
 import registerProductEditorHooks from './wp-hooks';

+deprecated( '@woocommerce/product-editor', {
+	version: '10.9.0',
+	plugin: 'WooCommerce',
+	hint: 'The new product editor and its extension APIs are deprecated and will be removed in WooCommerce 11.0.',
+} );
+
 export * from './components';
 export { DETAILS_SECTION_ID, TAB_GENERAL_ID, TRACKS_SOURCE } from './constants';

diff --git a/packages/js/product-editor/src/style.scss b/packages/js/product-editor/src/style.scss
index 11c6d8dde4d..cad993ba8e5 100644
--- a/packages/js/product-editor/src/style.scss
+++ b/packages/js/product-editor/src/style.scss
@@ -18,7 +18,6 @@
 @import "components/notice/style.scss";
 @import "components/iframe-editor/style.scss";
 @import "components/modal-editor/style.scss";
-@import "components/feedback-bar/style.scss";
 @import "components/product-mvp-feedback-modal/style.scss";
 @import "components/edit-product-link-modal/style.scss";
 @import "components/edit-product-link-modal/style.scss";
diff --git a/packages/js/product-editor/src/utils/init-block.ts b/packages/js/product-editor/src/utils/init-block.ts
index a0833892444..9b754c05dab 100644
--- a/packages/js/product-editor/src/utils/init-block.ts
+++ b/packages/js/product-editor/src/utils/init-block.ts
@@ -27,6 +27,9 @@ export function initBlock<
 >( block: BlockRepresentation< T > ): Block< T > | undefined {
 	deprecated( 'initBlock()', {
 		alternative: 'registerProductEditorBlockType()',
+		version: '10.9.0',
+		plugin: 'WooCommerce',
+		hint: 'Product editor extension APIs are deprecated and will be removed in WooCommerce 11.0.',
 	} );

 	if ( ! block ) {
diff --git a/packages/js/product-editor/src/utils/register-product-editor-block-type.ts b/packages/js/product-editor/src/utils/register-product-editor-block-type.ts
index 81d589cc7ff..4d375b9628f 100644
--- a/packages/js/product-editor/src/utils/register-product-editor-block-type.ts
+++ b/packages/js/product-editor/src/utils/register-product-editor-block-type.ts
@@ -4,6 +4,7 @@
 import { Block, BlockConfiguration } from '@wordpress/blocks';
 import { registerWooBlockType } from '@woocommerce/block-templates';
 import { useEntityId } from '@wordpress/core-data';
+import deprecated from '@wordpress/deprecated';

 interface BlockRepresentation< T extends Record< string, object > > {
 	name?: string;
@@ -51,10 +52,21 @@ function augmentUsesContext( usesContext?: string[] ) {
 	return [ ...( usesContext || [] ), 'postType' ];
 }

+/**
+ * Register a block type for the product editor.
+ *
+ * @deprecated since WooCommerce 10.9.0. Product editor extension APIs will be removed in WooCommerce 11.0.
+ */
 export function registerProductEditorBlockType<
 	// eslint-disable-next-line @typescript-eslint/no-explicit-any
 	T extends Record< string, any > = Record< string, any >
 >( block: BlockRepresentation< T > ): Block< T > | undefined {
+	deprecated( 'registerProductEditorBlockType()', {
+		version: '10.9.0',
+		plugin: 'WooCommerce',
+		hint: 'Product editor extension APIs are deprecated and will be removed in WooCommerce 11.0.',
+	} );
+
 	const { metadata, settings, name } = block;

 	const augmentedMetadata = {
diff --git a/plugins/woocommerce/changelog/add-product-editor-deprecation-notices b/plugins/woocommerce/changelog/add-product-editor-deprecation-notices
new file mode 100644
index 00000000000..5610b94cd58
--- /dev/null
+++ b/plugins/woocommerce/changelog/add-product-editor-deprecation-notices
@@ -0,0 +1,4 @@
+Significance: minor
+Type: add
+
+Add WooCommerce 11.0 removal notices for the deprecated product editor feature, extension APIs, and public PHP classes.
diff --git a/plugins/woocommerce/changelog/deprecate-product-editor b/plugins/woocommerce/changelog/deprecate-product-editor
new file mode 100644
index 00000000000..87b084acd42
--- /dev/null
+++ b/plugins/woocommerce/changelog/deprecate-product-editor
@@ -0,0 +1,4 @@
+Significance: minor
+Type: update
+
+Deprecate Product Editor v2
diff --git a/plugins/woocommerce/client/admin/client/products/product-page.tsx b/plugins/woocommerce/client/admin/client/products/product-page.tsx
index 65a64831d10..0db882e55e1 100644
--- a/plugins/woocommerce/client/admin/client/products/product-page.tsx
+++ b/plugins/woocommerce/client/admin/client/products/product-page.tsx
@@ -8,7 +8,6 @@ import {
 	productApiFetchMiddleware,
 	productEditorHeaderApiFetchMiddleware,
 	TRACKS_SOURCE,
-	__experimentalProductMVPCESFooter as FeedbackBar,
 	__experimentalEditorLoadingContext as EditorLoadingContext,
 } from '@woocommerce/product-editor';
 import { Spinner } from '@woocommerce/components';
@@ -78,7 +77,6 @@ export default function ProductPage() {

 						<WooFooterItem>
 							<>
-								<FeedbackBar productType="product" />
 								<Suspense fallback={ <Spinner /> }>
 									<ProductMVPFeedbackModalContainer
 										productId={
diff --git a/plugins/woocommerce/src/Admin/Features/ProductBlockEditor/BlockRegistry.php b/plugins/woocommerce/src/Admin/Features/ProductBlockEditor/BlockRegistry.php
index 7fefe63c339..0f420dbca08 100644
--- a/plugins/woocommerce/src/Admin/Features/ProductBlockEditor/BlockRegistry.php
+++ b/plugins/woocommerce/src/Admin/Features/ProductBlockEditor/BlockRegistry.php
@@ -10,9 +10,16 @@ use Automattic\WooCommerce\Blocks\Utils\Utils;

 /**
  * Product block registration and style registration functionality.
+ *
+ * @deprecated 10.9.0 Product editor extension APIs will be removed in WooCommerce 11.0.
  */
 class BlockRegistry {

+	/**
+	 * Version that product editor APIs were deprecated in.
+	 */
+	const DEPRECATED_SINCE = '10.9.0';
+
 	/**
 	 * Generic blocks directory.
 	 */
@@ -255,7 +262,7 @@ class BlockRegistry {
 		$block_name      = $this->remove_block_prefix( $block_name );
 		$block_json_file = $this->get_file_path( $block_name . '/block.json', $block_dir );

-		return $this->register_block_type_from_metadata( $block_json_file );
+		return $this->register_block_type_from_metadata_without_deprecation_notice( $block_json_file );
 	}

 	/**
@@ -289,8 +296,27 @@ class BlockRegistry {
 	 * path to the folder where the `block.json` file is located.
 	 *
 	 * @return \WP_Block_Type|false The registered block type on success, or false on failure.
+	 *
+	 * @deprecated 10.9.0 Product editor extension APIs will be removed in WooCommerce 11.0.
 	 */
 	public function register_block_type_from_metadata( $file_or_folder ) {
+		wc_deprecated_function(
+			'Automattic\WooCommerce\Admin\Features\ProductBlockEditor\BlockRegistry::register_block_type_from_metadata, which will be removed in WooCommerce 11.0',
+			self::DEPRECATED_SINCE
+		);
+
+		return $this->register_block_type_from_metadata_without_deprecation_notice( $file_or_folder );
+	}
+
+	/**
+	 * Register a block type from metadata without emitting a deprecation notice for internal block registration.
+	 *
+	 * @param string $file_or_folder Path to the JSON file with metadata definition for the block or
+	 * path to the folder where the `block.json` file is located.
+	 *
+	 * @return \WP_Block_Type|false The registered block type on success, or false on failure.
+	 */
+	private function register_block_type_from_metadata_without_deprecation_notice( $file_or_folder ) {
 		$metadata_file = ( ! str_ends_with( $file_or_folder, 'block.json' ) )
 			? trailingslashit( $file_or_folder ) . 'block.json'
 			: $file_or_folder;
diff --git a/plugins/woocommerce/src/Admin/Features/ProductBlockEditor/BlockTemplateUtils.php b/plugins/woocommerce/src/Admin/Features/ProductBlockEditor/BlockTemplateUtils.php
index b892901e0f7..8c641e74f14 100644
--- a/plugins/woocommerce/src/Admin/Features/ProductBlockEditor/BlockTemplateUtils.php
+++ b/plugins/woocommerce/src/Admin/Features/ProductBlockEditor/BlockTemplateUtils.php
@@ -6,6 +6,8 @@ use Automattic\WooCommerce\LayoutTemplates\LayoutTemplateRegistry;

 /**
  * Utils for block templates.
+ *
+ * @deprecated 10.9.0 Product editor extension APIs will be removed in WooCommerce 11.0.
  */
 class BlockTemplateUtils {
 	/**
diff --git a/plugins/woocommerce/src/Admin/Features/ProductBlockEditor/Init.php b/plugins/woocommerce/src/Admin/Features/ProductBlockEditor/Init.php
index 7b10ca46402..98b1ea548e9 100644
--- a/plugins/woocommerce/src/Admin/Features/ProductBlockEditor/Init.php
+++ b/plugins/woocommerce/src/Admin/Features/ProductBlockEditor/Init.php
@@ -19,8 +19,15 @@ use WP_Block_Editor_Context;

 /**
  * Loads assets related to the product block editor.
+ *
+ * @deprecated 10.9.0 Product editor extension APIs will be removed in WooCommerce 11.0.
  */
 class Init {
+	/**
+	 * Version that product editor APIs were deprecated in.
+	 */
+	const DEPRECATED_SINCE = '10.9.0';
+
 	/**
 	 * The context name used to identify the editor.
 	 */
@@ -103,11 +110,21 @@ class Init {
 			return $response;
 		}
 		if ( ! $product->meta_exists( '_product_template_id' ) ) {
+			if ( has_filter( 'experimental_woocommerce_product_editor_product_template_id_for_product' ) ) {
+				wc_deprecated_hook(
+					'experimental_woocommerce_product_editor_product_template_id_for_product',
+					$this::DEPRECATED_SINCE,
+					null,
+					'This product editor extension filter will be removed in WooCommerce 11.0.'
+				);
+			}
+
 			/**
 			 * Experimental: Allows to determine a product template id based on the product data.
 			 *
 			 * @ignore
 			 * @since 9.1.0
+			 * @deprecated 10.9.0 Product editor extension APIs will be removed in WooCommerce 11.0.
 			 */
 			$product_template_id = apply_filters( 'experimental_woocommerce_product_editor_product_template_id_for_product', '', $product );
 			if ( $product_template_id ) {
@@ -401,10 +418,20 @@ class Init {
 	 * Register product templates.
 	 */
 	public function register_product_templates() {
+		if ( has_filter( 'woocommerce_product_editor_product_templates' ) ) {
+			wc_deprecated_hook(
+				'woocommerce_product_editor_product_templates',
+				self::DEPRECATED_SINCE,
+				null,
+				'This product editor extension filter will be removed in WooCommerce 11.0.'
+			);
+		}
+
 		/**
 		 * Allows for new product template registration.
 		 *
 		 * @since 8.5.0
+		 * @deprecated 10.9.0 Product editor extension APIs will be removed in WooCommerce 11.0.
 		 */
 		$this->product_templates = apply_filters( 'woocommerce_product_editor_product_templates', $this->get_default_product_templates() );
 		$this->product_templates = $this->create_default_product_template_by_custom_product_type( $this->product_templates );
diff --git a/plugins/woocommerce/src/Admin/Features/ProductBlockEditor/ProductFormsController.php b/plugins/woocommerce/src/Admin/Features/ProductBlockEditor/ProductFormsController.php
index f9fc30bc84e..3516ca858bf 100644
--- a/plugins/woocommerce/src/Admin/Features/ProductBlockEditor/ProductFormsController.php
+++ b/plugins/woocommerce/src/Admin/Features/ProductBlockEditor/ProductFormsController.php
@@ -7,9 +7,16 @@ namespace Automattic\WooCommerce\Admin\Features\ProductBlockEditor;

 /**
  * Handle retrieval of product forms.
+ *
+ * @deprecated 10.9.0 Product editor extension APIs will be removed in WooCommerce 11.0.
  */
 class ProductFormsController {

+	/**
+	 * Version that product editor APIs were deprecated in.
+	 */
+	const DEPRECATED_SINCE = '10.9.0';
+
 	/**
 	 * Product form templates.
 	 *
@@ -67,10 +74,20 @@ class ProductFormsController {
 	 * @return void
 	 */
 	public function migrate_product_form_posts( $action ) {
+		if ( has_filter( 'woocommerce_product_form_templates' ) ) {
+			wc_deprecated_hook(
+				'woocommerce_product_form_templates',
+				$this::DEPRECATED_SINCE,
+				null,
+				'This product editor extension filter will be removed in WooCommerce 11.0.'
+			);
+		}
+
 		/**
 		 * Allow extend the list of templates that should be auto-generated.
 		 *
 		 * @since 9.1.0
+		 * @deprecated 10.9.0 Product editor extension APIs will be removed in WooCommerce 11.0.
 		 * @param array $templates List of templates to auto-generate.
 		 */
 		$templates = apply_filters(
diff --git a/plugins/woocommerce/src/Admin/Features/ProductBlockEditor/ProductTemplate.php b/plugins/woocommerce/src/Admin/Features/ProductBlockEditor/ProductTemplate.php
index 49f88ad6b48..edb1d0fc480 100644
--- a/plugins/woocommerce/src/Admin/Features/ProductBlockEditor/ProductTemplate.php
+++ b/plugins/woocommerce/src/Admin/Features/ProductBlockEditor/ProductTemplate.php
@@ -10,6 +10,7 @@ namespace Automattic\WooCommerce\Admin\Features\ProductBlockEditor;
  * the LayoutTemplate (ProductFormTemplateInterface)
  *
  * @see ProductFormTemplateInterface
+ * @deprecated 10.9.0 Product editor extension APIs will be removed in WooCommerce 11.0.
  */
 class ProductTemplate {
 	/**
diff --git a/plugins/woocommerce/src/Admin/Features/ProductBlockEditor/ProductTemplates/GroupInterface.php b/plugins/woocommerce/src/Admin/Features/ProductBlockEditor/ProductTemplates/GroupInterface.php
index f8fd4bfc9d0..2185eddbb65 100644
--- a/plugins/woocommerce/src/Admin/Features/ProductBlockEditor/ProductTemplates/GroupInterface.php
+++ b/plugins/woocommerce/src/Admin/Features/ProductBlockEditor/ProductTemplates/GroupInterface.php
@@ -7,6 +7,8 @@ use Automattic\WooCommerce\Admin\BlockTemplates\BlockInterface;

 /**
  * Interface for group containers, which contain sections and blocks.
+ *
+ * @deprecated 10.9.0 Product editor extension APIs will be removed in WooCommerce 11.0.
  */
 interface GroupInterface extends BlockContainerInterface {

diff --git a/plugins/woocommerce/src/Admin/Features/ProductBlockEditor/ProductTemplates/ProductFormTemplateInterface.php b/plugins/woocommerce/src/Admin/Features/ProductBlockEditor/ProductTemplates/ProductFormTemplateInterface.php
index 5cddce4b55a..6e12b278211 100644
--- a/plugins/woocommerce/src/Admin/Features/ProductBlockEditor/ProductTemplates/ProductFormTemplateInterface.php
+++ b/plugins/woocommerce/src/Admin/Features/ProductBlockEditor/ProductTemplates/ProductFormTemplateInterface.php
@@ -7,6 +7,8 @@ use Automattic\WooCommerce\Admin\BlockTemplates\BlockTemplateInterface;

 /**
  * Interface for block containers.
+ *
+ * @deprecated 10.9.0 Product editor extension APIs will be removed in WooCommerce 11.0.
  */
 interface ProductFormTemplateInterface extends BlockTemplateInterface {

diff --git a/plugins/woocommerce/src/Admin/Features/ProductBlockEditor/ProductTemplates/SectionInterface.php b/plugins/woocommerce/src/Admin/Features/ProductBlockEditor/ProductTemplates/SectionInterface.php
index 396dbec3baa..e3cce8d3a8f 100644
--- a/plugins/woocommerce/src/Admin/Features/ProductBlockEditor/ProductTemplates/SectionInterface.php
+++ b/plugins/woocommerce/src/Admin/Features/ProductBlockEditor/ProductTemplates/SectionInterface.php
@@ -8,6 +8,8 @@ use Automattic\WooCommerce\Admin\BlockTemplates\BlockInterface;

 /**
  * Interface for section containers, which contain sub-sections and blocks.
+ *
+ * @deprecated 10.9.0 Product editor extension APIs will be removed in WooCommerce 11.0.
  */
 interface SectionInterface extends BlockContainerInterface {

diff --git a/plugins/woocommerce/src/Admin/Features/ProductBlockEditor/ProductTemplates/SubsectionInterface.php b/plugins/woocommerce/src/Admin/Features/ProductBlockEditor/ProductTemplates/SubsectionInterface.php
index 5df4991067d..7f6fa495426 100644
--- a/plugins/woocommerce/src/Admin/Features/ProductBlockEditor/ProductTemplates/SubsectionInterface.php
+++ b/plugins/woocommerce/src/Admin/Features/ProductBlockEditor/ProductTemplates/SubsectionInterface.php
@@ -7,6 +7,8 @@ use Automattic\WooCommerce\Admin\BlockTemplates\BlockInterface;

 /**
  * Interface for subsection containers, which contain sub-sections and blocks.
+ *
+ * @deprecated 10.9.0 Product editor extension APIs will be removed in WooCommerce 11.0.
  */
 interface SubsectionInterface extends BlockContainerInterface {
 	/**
diff --git a/plugins/woocommerce/src/Admin/Features/ProductBlockEditor/RedirectionController.php b/plugins/woocommerce/src/Admin/Features/ProductBlockEditor/RedirectionController.php
index 5a9bb32f511..24af1a389ad 100644
--- a/plugins/woocommerce/src/Admin/Features/ProductBlockEditor/RedirectionController.php
+++ b/plugins/woocommerce/src/Admin/Features/ProductBlockEditor/RedirectionController.php
@@ -11,6 +11,8 @@ use Automattic\WooCommerce\Internal\Admin\WCAdminAssets;

 /**
  * Handle redirecting to the old or new editor based on features and support.
+ *
+ * @deprecated 10.9.0 Product editor extension APIs will be removed in WooCommerce 11.0.
  */
 class RedirectionController {
 	/**
diff --git a/plugins/woocommerce/src/Admin/Features/ProductBlockEditor/Tracks.php b/plugins/woocommerce/src/Admin/Features/ProductBlockEditor/Tracks.php
index 1cf7b426401..f4d12fc41c8 100644
--- a/plugins/woocommerce/src/Admin/Features/ProductBlockEditor/Tracks.php
+++ b/plugins/woocommerce/src/Admin/Features/ProductBlockEditor/Tracks.php
@@ -7,6 +7,8 @@ namespace Automattic\WooCommerce\Admin\Features\ProductBlockEditor;

 /**
  * Add tracks for the product block editor.
+ *
+ * @deprecated 10.9.0 Product editor extension APIs will be removed in WooCommerce 11.0.
  */
 class Tracks {

diff --git a/plugins/woocommerce/src/Internal/Admin/BlockTemplates/AbstractBlock.php b/plugins/woocommerce/src/Internal/Admin/BlockTemplates/AbstractBlock.php
index 06ffd31671f..8e2dc8d1339 100644
--- a/plugins/woocommerce/src/Internal/Admin/BlockTemplates/AbstractBlock.php
+++ b/plugins/woocommerce/src/Internal/Admin/BlockTemplates/AbstractBlock.php
@@ -268,8 +268,15 @@ class AbstractBlock implements BlockInterface {
 		 * @param BlockInterface $block The block.
 		 *
 		 * @since 8.4.0
+		 * @deprecated 10.9.0 This hook will be removed in WooCommerce 11.0.
 		 */
-		do_action( 'woocommerce_block_template_after_add_hide_condition', $this );
+		wc_do_deprecated_action(
+			'woocommerce_block_template_after_add_hide_condition',
+			array( $this ),
+			'10.9.0',
+			null,
+			'This block template hook will be removed in WooCommerce 11.0.'
+		);

 		return $key;
 	}
@@ -288,8 +295,15 @@ class AbstractBlock implements BlockInterface {
 		 * @param BlockInterface $block The block.
 		 *
 		 * @since 8.4.0
+		 * @deprecated 10.9.0 This hook will be removed in WooCommerce 11.0.
 		 */
-		do_action( 'woocommerce_block_template_after_remove_hide_condition', $this );
+		wc_do_deprecated_action(
+			'woocommerce_block_template_after_remove_hide_condition',
+			array( $this ),
+			'10.9.0',
+			null,
+			'This block template hook will be removed in WooCommerce 11.0.'
+		);
 	}

 	/**
diff --git a/plugins/woocommerce/src/Internal/Admin/BlockTemplates/BlockContainerTrait.php b/plugins/woocommerce/src/Internal/Admin/BlockTemplates/BlockContainerTrait.php
index 6c183dd5613..99e9eadcb80 100644
--- a/plugins/woocommerce/src/Internal/Admin/BlockTemplates/BlockContainerTrait.php
+++ b/plugins/woocommerce/src/Internal/Admin/BlockTemplates/BlockContainerTrait.php
@@ -217,8 +217,15 @@ trait BlockContainerTrait {
 			 * @param BlockInterface $block The block.
 			 *
 			 * @since 8.2.0
+			 * @deprecated 10.9.0 This hook will be removed in WooCommerce 11.0.
 			 */
-			do_action( 'woocommerce_block_template_after_add_block', $block );
+			wc_do_deprecated_action(
+				'woocommerce_block_template_after_add_block',
+				array( $block ),
+				'10.9.0',
+				null,
+				'This block template hook will be removed in WooCommerce 11.0.'
+			);
 		} catch ( \Exception $e ) {
 			$this->do_after_add_block_error_action( $block, 'woocommerce_block_template_after_add_block', $e );
 		}
@@ -231,6 +238,8 @@ trait BlockContainerTrait {
 	 * @param BlockInterface $block The block.
 	 */
 	private function do_after_add_specific_block_action( BlockInterface $block ) {
+		$hook_name = "woocommerce_block_template_area_{$this->get_root_template()->get_area()}_after_add_block_{$block->get_id()}";
+
 		try {
 			/**
 			 * Action called after a specific block is added to a template with a specific area.
@@ -241,10 +250,17 @@ trait BlockContainerTrait {
 			 * @param BlockInterface $block The block.
 			 *
 			 * @since 8.2.0
+			 * @deprecated 10.9.0 This hook will be removed in WooCommerce 11.0.
 			 */
-			do_action( "woocommerce_block_template_area_{$this->get_root_template()->get_area()}_after_add_block_{$block->get_id()}", $block );
+			wc_do_deprecated_action(
+				$hook_name,
+				array( $block ),
+				'10.9.0',
+				null,
+				'This block template hook will be removed in WooCommerce 11.0.'
+			);
 		} catch ( \Exception $e ) {
-			$this->do_after_add_block_error_action( $block, "woocommerce_block_template_area_{$this->get_root_template()->get_area()}_after_add_block_{$block->get_id()}", $e );
+			$this->do_after_add_block_error_action( $block, $hook_name, $e );
 		}
 	}

@@ -264,12 +280,14 @@ trait BlockContainerTrait {
 		 * @param \Exception     $exception The exception.
 		 *
 		 * @since 8.4.0
+		 * @deprecated 10.9.0 This hook will be removed in WooCommerce 11.0.
 		 */
-		do_action(
+		wc_do_deprecated_action(
 			'woocommerce_block_template_after_add_block_error',
-			$block,
-			$action,
-			$e,
+			array( $block, $action, $e ),
+			'10.9.0',
+			null,
+			'This block template hook will be removed in WooCommerce 11.0.'
 		);
 	}

@@ -290,8 +308,15 @@ trait BlockContainerTrait {
 			 * @param BlockInterface $block The block.
 			 *
 			 * @since 8.2.0
+			 * @deprecated 10.9.0 This hook will be removed in WooCommerce 11.0.
 			 */
-			do_action( 'woocommerce_block_template_after_remove_block', $block );
+			wc_do_deprecated_action(
+				'woocommerce_block_template_after_remove_block',
+				array( $block ),
+				'10.9.0',
+				null,
+				'This block template hook will be removed in WooCommerce 11.0.'
+			);
 		} catch ( \Exception $e ) {
 			$this->do_after_remove_block_error_action( $block, 'woocommerce_block_template_after_remove_block', $e );
 		}
@@ -304,6 +329,8 @@ trait BlockContainerTrait {
 	 * @param BlockInterface $block The block.
 	 */
 	private function do_after_remove_specific_block_action( BlockInterface $block ) {
+		$hook_name = "woocommerce_block_template_area_{$this->get_root_template()->get_area()}_after_remove_block_{$block->get_id()}";
+
 		try {
 			/**
 			 * Action called after a specific block is removed from a template with a specific area.
@@ -314,10 +341,17 @@ trait BlockContainerTrait {
 			 * @param BlockInterface $block The block.
 			 *
 			 * @since 8.2.0
+			 * @deprecated 10.9.0 This hook will be removed in WooCommerce 11.0.
 			 */
-			do_action( "woocommerce_block_template_area_{$this->get_root_template()->get_area()}_after_remove_block_{$block->get_id()}", $block );
+			wc_do_deprecated_action(
+				$hook_name,
+				array( $block ),
+				'10.9.0',
+				null,
+				'This block template hook will be removed in WooCommerce 11.0.'
+			);
 		} catch ( \Exception $e ) {
-			$this->do_after_remove_block_error_action( $block, "woocommerce_block_template_area_{$this->get_root_template()->get_area()}_after_remove_block_{$block->get_id()}", $e );
+			$this->do_after_remove_block_error_action( $block, $hook_name, $e );
 		}
 	}

@@ -337,12 +371,14 @@ trait BlockContainerTrait {
 		 * @param \Exception     $exception The exception.
 		 *
 		 * @since 8.4.0
+		 * @deprecated 10.9.0 This hook will be removed in WooCommerce 11.0.
 		 */
-		do_action(
+		wc_do_deprecated_action(
 			'woocommerce_block_template_after_remove_block_error',
-			$block,
-			$action,
-			$e,
+			array( $block, $action, $e ),
+			'10.9.0',
+			null,
+			'This block template hook will be removed in WooCommerce 11.0.'
 		);
 	}
 }
diff --git a/plugins/woocommerce/tests/php/includes/rest-api/Controllers/Version3/class-wc-rest-layout-templates-controller-tests.php b/plugins/woocommerce/tests/php/includes/rest-api/Controllers/Version3/class-wc-rest-layout-templates-controller-tests.php
index e333df498a9..1d21586d223 100644
--- a/plugins/woocommerce/tests/php/includes/rest-api/Controllers/Version3/class-wc-rest-layout-templates-controller-tests.php
+++ b/plugins/woocommerce/tests/php/includes/rest-api/Controllers/Version3/class-wc-rest-layout-templates-controller-tests.php
@@ -31,6 +31,9 @@ class WC_REST_Layout_Templates_Controller_Tests extends WC_REST_Unit_Test_Case {
 	 * Test getting all layout templates.
 	 */
 	public function test_get_all_items() {
+		$this->setExpectedDeprecated( 'woocommerce_block_template_after_add_block' );
+		$this->setExpectedDeprecated( 'woocommerce_block_template_after_add_hide_condition' );
+
 		$response = $this->do_rest_get_request( 'layout-templates' );

 		$this->assertEquals( 200, $response->get_status() );
diff --git a/plugins/woocommerce/tests/php/src/Internal/Admin/BlockTemplates/BlockTemplateTest.php b/plugins/woocommerce/tests/php/src/Internal/Admin/BlockTemplates/BlockTemplateTest.php
index c761a169e0e..e34f73c3990 100644
--- a/plugins/woocommerce/tests/php/src/Internal/Admin/BlockTemplates/BlockTemplateTest.php
+++ b/plugins/woocommerce/tests/php/src/Internal/Admin/BlockTemplates/BlockTemplateTest.php
@@ -84,6 +84,9 @@ class BlockTemplateTest extends WC_Unit_Test_Case {

 			add_action( 'woocommerce_block_template_area_uncategorized_after_add_block_test-block-id', $specific_after_add_block_hook );

+			$this->setExpectedDeprecated( 'woocommerce_block_template_after_add_block' );
+			$this->setExpectedDeprecated( 'woocommerce_block_template_area_uncategorized_after_add_block_test-block-id' );
+
 			$template->add_block(
 				[
 					'id'        => 'test-block-id',
@@ -141,6 +144,9 @@ class BlockTemplateTest extends WC_Unit_Test_Case {
 			add_action( 'woocommerce_block_template_after_remove_block', $after_remove_block_hook );
 			add_action( 'woocommerce_block_template_area_uncategorized_after_remove_block_test-block-id', $specific_after_remove_block_hook );

+			$this->setExpectedDeprecated( 'woocommerce_block_template_after_remove_block' );
+			$this->setExpectedDeprecated( 'woocommerce_block_template_area_uncategorized_after_remove_block_test-block-id' );
+
 			$block = $template->add_block(
 				[
 					'id'        => 'test-block-id',