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',