Commit 8b1bde085be for woocommerce
commit 8b1bde085be3d9156449c38b4e0c2eaf96369fee
Author: Luigi Teschio <gigitux@gmail.com>
Date: Tue Jun 2 10:05:28 2026 +0200
Remove async product editor category field (#65395)
* Remove async product editor category field
* Add changelog entries for async category field removal
* Deprecate async category tree AJAX callback
diff --git a/plugins/woocommerce-beta-tester/changelog/49120-remove-async-product-editor-category-field b/plugins/woocommerce-beta-tester/changelog/49120-remove-async-product-editor-category-field
new file mode 100644
index 00000000000..b2078449090
--- /dev/null
+++ b/plugins/woocommerce-beta-tester/changelog/49120-remove-async-product-editor-category-field
@@ -0,0 +1,4 @@
+Significance: patch
+Type: update
+
+Remove async product editor category field from live branch feature flags.
diff --git a/plugins/woocommerce-beta-tester/userscripts/wc-live-branches.user.js b/plugins/woocommerce-beta-tester/userscripts/wc-live-branches.user.js
index 6dbf992fc85..57a53a5824d 100644
--- a/plugins/woocommerce-beta-tester/userscripts/wc-live-branches.user.js
+++ b/plugins/woocommerce-beta-tester/userscripts/wc-live-branches.user.js
@@ -170,7 +170,6 @@
} else {
// TODO: Fetch the list of feature flags dynamically from the API or something.
const featureFlags = [
- 'async-product-editor-category-field',
'coming-soon-newsletter-template',
'launch-your-store',
'minified-js',
diff --git a/plugins/woocommerce/changelog/49120-remove-async-product-editor-category-field b/plugins/woocommerce/changelog/49120-remove-async-product-editor-category-field
new file mode 100644
index 00000000000..cb980ed6661
--- /dev/null
+++ b/plugins/woocommerce/changelog/49120-remove-async-product-editor-category-field
@@ -0,0 +1,3 @@
+Significance: patch
+Type: dev
+Comment: Remove unused async product editor category field feature flag and deprecate its AJAX callback.
diff --git a/plugins/woocommerce/client/admin/client/wp-admin-scripts/product-category-metabox/all-category-list.tsx b/plugins/woocommerce/client/admin/client/wp-admin-scripts/product-category-metabox/all-category-list.tsx
deleted file mode 100644
index d1a330b63b2..00000000000
--- a/plugins/woocommerce/client/admin/client/wp-admin-scripts/product-category-metabox/all-category-list.tsx
+++ /dev/null
@@ -1,212 +0,0 @@
-/**
- * External dependencies
- */
-import { __, sprintf } from '@wordpress/i18n';
-import {
- forwardRef,
- useCallback,
- useEffect,
- useImperativeHandle,
- useState,
-} from '@wordpress/element';
-import { addQueryArgs } from '@wordpress/url';
-import { useDebounce } from '@wordpress/compose';
-import { TreeSelectControl } from '@woocommerce/components';
-import { getSetting } from '@woocommerce/settings';
-import { recordEvent } from '@woocommerce/tracks';
-import apiFetch from '@wordpress/api-fetch';
-
-/**
- * Internal dependencies
- */
-import { CATEGORY_TERM_NAME } from './category-handlers';
-import { CategoryTerm } from './popular-category-list';
-
-declare const wc_product_category_metabox_params: {
- search_categories_nonce: string;
-};
-
-type CategoryTreeItem = CategoryTerm & {
- children?: CategoryTreeItem[];
-};
-
-type CategoryTreeItemLabelValue = {
- children: CategoryTreeItemLabelValue[];
- label: string;
- value: string;
-};
-
-export const DEFAULT_DEBOUNCE_TIME = 250;
-
-const categoryLibrary: Record< number, CategoryTreeItem > = {};
-function convertTreeToLabelValue(
- tree: CategoryTreeItem[],
- newTree: CategoryTreeItemLabelValue[] = []
-) {
- for ( const child of tree ) {
- const newItem = {
- label: child.name,
- value: child.term_id.toString(),
- children: [],
- };
- categoryLibrary[ child.term_id ] = child;
- newTree.push( newItem );
- if ( child.children?.length ) {
- convertTreeToLabelValue( child.children, newItem.children );
- }
- }
- newTree.sort(
- ( a: CategoryTreeItemLabelValue, b: CategoryTreeItemLabelValue ) => {
- const nameA = a.label.toUpperCase();
- const nameB = b.label.toUpperCase();
- if ( nameA < nameB ) {
- return -1;
- }
- if ( nameA > nameB ) {
- return 1;
- }
- return 0;
- }
- );
- return newTree;
-}
-
-async function getTreeItems( filter: string ) {
- const resp = await apiFetch< CategoryTreeItem[] >( {
- url: addQueryArgs(
- new URL( 'admin-ajax.php', getSetting( 'adminUrl' ) ).toString(),
- {
- term: filter,
- action: 'woocommerce_json_search_categories_tree',
- // eslint-disable-next-line no-undef, camelcase
- security:
- wc_product_category_metabox_params.search_categories_nonce,
- }
- ),
- method: 'GET',
- } );
- if ( resp ) {
- return convertTreeToLabelValue( Object.values( resp ) );
- }
- return [];
-}
-
-export const AllCategoryList = forwardRef<
- { resetInitialValues: () => void },
- {
- selectedCategoryTerms: CategoryTerm[];
- onChange: ( selected: CategoryTerm[] ) => void;
- }
->( ( { selectedCategoryTerms, onChange }, ref ) => {
- const [ filter, setFilter ] = useState( '' );
- const [ treeItems, setTreeItems ] = useState<
- CategoryTreeItemLabelValue[]
- >( [] );
-
- const searchCategories = useCallback(
- ( value: string ) => {
- if ( value && value.length > 0 ) {
- recordEvent( 'product_category_search', {
- page: 'product',
- async: true,
- search_string_length: value.length,
- } );
- }
- getTreeItems( value ).then( ( res ) => {
- setTreeItems( Object.values( res ) );
- } );
- },
- [ setTreeItems ]
- );
- const searchCategoriesDebounced = useDebounce(
- searchCategories,
- DEFAULT_DEBOUNCE_TIME
- );
-
- useEffect( () => {
- searchCategoriesDebounced( filter );
- }, [ filter ] );
-
- useImperativeHandle(
- ref,
- () => {
- return {
- resetInitialValues() {
- getTreeItems( '' ).then( ( res ) => {
- setTreeItems( Object.values( res ) );
- } );
- },
- };
- },
- []
- );
-
- return (
- <>
- <div className="product-add-category__tree-control">
- <TreeSelectControl
- alwaysShowPlaceholder={ true }
- options={ treeItems }
- value={ selectedCategoryTerms.map( ( category ) =>
- category.term_id.toString()
- ) }
- onChange={ ( selectedCategoryIds: number[] ) => {
- onChange(
- selectedCategoryIds.map(
- ( id ) => categoryLibrary[ id ]
- )
- );
- recordEvent( 'product_category_update', {
- page: 'product',
- async: true,
- selected: selectedCategoryIds.length,
- } );
- } }
- selectAllLabel={ false }
- onInputChange={ setFilter }
- placeholder={ __( 'Add category', 'woocommerce' ) }
- includeParent={ true }
- minFilterQueryLength={ 2 }
- clearOnSelect={ false }
- individuallySelectParent={ true }
- />
- </div>
- <ul
- // Adding tagchecklist class to make use of already existing styling for the selected categories.
- className="categorychecklist form-no-clear tagchecklist"
- id={ CATEGORY_TERM_NAME + 'checklist' }
- >
- { selectedCategoryTerms.map( ( selectedCategory ) => (
- <li key={ selectedCategory.term_id }>
- <button
- type="button"
- className="ntdelbutton"
- onClick={ () => {
- const newSelectedItems =
- selectedCategoryTerms.filter(
- ( category ) =>
- category.term_id !==
- selectedCategory.term_id
- );
- onChange( newSelectedItems );
- } }
- >
- <span
- className="remove-tag-icon"
- aria-hidden="true"
- ></span>
- <span className="screen-reader-text">
- { sprintf(
- /* translators: %s: category name */
- __( 'Remove term: %s', 'woocommerce' ),
- selectedCategory.name
- ) }
- </span>
- </button>
- { selectedCategory.name }
- </li>
- ) ) }
- </ul>
- </>
- );
-} );
diff --git a/plugins/woocommerce/client/admin/client/wp-admin-scripts/product-category-metabox/category-add-new.tsx b/plugins/woocommerce/client/admin/client/wp-admin-scripts/product-category-metabox/category-add-new.tsx
deleted file mode 100644
index 37bce4870fb..00000000000
--- a/plugins/woocommerce/client/admin/client/wp-admin-scripts/product-category-metabox/category-add-new.tsx
+++ /dev/null
@@ -1,197 +0,0 @@
-/**
- * External dependencies
- */
-import { __ } from '@wordpress/i18n';
-import { useCallback, useState } from '@wordpress/element';
-import { addQueryArgs } from '@wordpress/url';
-import { getSetting } from '@woocommerce/settings';
-import {
- useAsyncFilter,
- __experimentalSelectControl as SelectControl,
-} from '@woocommerce/components';
-import { useUser } from '@woocommerce/data';
-import { recordEvent } from '@woocommerce/tracks';
-import apiFetch from '@wordpress/api-fetch';
-
-/**
- * Internal dependencies
- */
-import { CATEGORY_TERM_NAME } from './category-handlers';
-import { CategoryTerm } from './popular-category-list';
-
-declare const wc_product_category_metabox_params: {
- search_categories_nonce: string;
-};
-
-function getCategoryTermLabel( item: CategoryTerm | null ): string {
- return item?.name || '';
-}
-
-function getCategoryTermKey( item: CategoryTerm | null ): string {
- return String( item?.term_id );
-}
-
-export const CategoryAddNew = ( {
- selectedCategoryTerms,
- onChange,
-}: {
- selectedCategoryTerms: CategoryTerm[];
- onChange: ( selected: CategoryTerm[] ) => void;
-} ) => {
- const [ showAddNew, setShowAddNew ] = useState( false );
- const [ newCategoryName, setNewCategoryName ] = useState( '' );
- const [ categoryCreateError, setCategoryCreateError ] = useState( '' );
- const [ categoryParent, setCategoryParent ] = useState< CategoryTerm >();
- const [ fetchedItems, setFetchedItems ] = useState< CategoryTerm[] >( [] );
- const { currentUserCan } = useUser();
-
- const canEditTerms = currentUserCan( 'edit_product_terms' );
-
- const onCreate = ( event: React.MouseEvent< HTMLInputElement > ) => {
- event.preventDefault();
- if ( ! newCategoryName ) {
- return;
- }
-
- const data = {
- name: newCategoryName,
- parent: categoryParent?.term_id ?? -1,
- };
- setCategoryCreateError( '' );
- apiFetch< {
- id: number;
- name: string;
- count: number;
- parent: number;
- } >( {
- path: '/wc/v3/products/categories',
- data,
- method: 'POST',
- } )
- .then( ( res ) => {
- if ( res ) {
- recordEvent( 'product_category_add', {
- category_id: res.id,
- parent_id: res.parent,
- parent_category: res.parent > 0 ? 'Other' : 'None',
- page: 'product',
- async: true,
- } );
- onChange( [
- ...selectedCategoryTerms,
- { term_id: res.id, name: res.name, count: res.count },
- ] );
- setNewCategoryName( '' );
- setCategoryParent( undefined );
- setShowAddNew( false );
- }
- } )
- .catch( ( error ) => {
- if ( error && error.message ) {
- setCategoryCreateError( error.message );
- }
- } );
- };
-
- const filter: ( value: string ) => Promise< CategoryTerm[] > = useCallback(
- async ( value = '' ) => {
- setFetchedItems( [] );
- return apiFetch< CategoryTerm[] >( {
- url: addQueryArgs(
- new URL(
- 'admin-ajax.php',
- getSetting( 'adminUrl' )
- ).toString(),
- {
- term: value,
- action: 'woocommerce_json_search_categories',
- // eslint-disable-next-line no-undef, camelcase
- security:
- wc_product_category_metabox_params.search_categories_nonce,
- }
- ),
- method: 'GET',
- } ).then( ( response ) => {
- if ( response ) {
- setFetchedItems( Object.values( response ) );
- }
- return [];
- } );
- },
- []
- );
-
- const { isFetching, ...selectProps } = useAsyncFilter< CategoryTerm >( {
- filter,
- } );
-
- if ( ! canEditTerms ) {
- return null;
- }
-
- return (
- <div id={ CATEGORY_TERM_NAME + '-adder' }>
- <a
- id="product_cat-add-toggle"
- href={ '#taxonomy-' + CATEGORY_TERM_NAME }
- className="taxonomy-add-new"
- onClick={ () => setShowAddNew( ! showAddNew ) }
- aria-label={ __( 'Add new category', 'woocommerce' ) }
- >
- { __( '+ Add new category', 'woocommerce' ) }
- </a>
- { showAddNew && (
- <div id="product_cat-add" className="category-add">
- <label
- className="screen-reader-text"
- htmlFor="newproduct_cat"
- >
- { __( 'Add new category', 'woocommerce' ) }
- </label>
- <input
- type="text"
- name="newproduct_cat"
- id="newproduct_cat"
- className="form-required"
- placeholder={ __( 'New category name', 'woocommerce' ) }
- value={ newCategoryName }
- onChange={ ( event ) =>
- setNewCategoryName( event.target.value )
- }
- aria-required="true"
- />
- <label
- className="screen-reader-text"
- htmlFor="newproduct_cat_parent"
- >
- { __( 'Parent category:', 'woocommerce' ) }
- </label>
- <SelectControl< CategoryTerm >
- { ...selectProps }
- label={ __( 'Parent category:', 'woocommerce' ) }
- items={ fetchedItems }
- selected={ categoryParent || null }
- placeholder={ __( 'Find category', 'woocommerce' ) }
- onSelect={ setCategoryParent }
- getItemLabel={ getCategoryTermLabel }
- getItemValue={ getCategoryTermKey }
- onRemove={ () => setCategoryParent( undefined ) }
- />
- { categoryCreateError && (
- <p className="category-add__error">
- { categoryCreateError }
- </p>
- ) }
- <input
- type="button"
- id="product_cat-add-submit"
- className="button category-add-submit"
- value={ __( 'Add new category', 'woocommerce' ) }
- disabled={ ! newCategoryName.length }
- onClick={ onCreate }
- />
- </div>
- ) }
- </div>
- );
-};
diff --git a/plugins/woocommerce/client/admin/client/wp-admin-scripts/product-category-metabox/category-handlers.js b/plugins/woocommerce/client/admin/client/wp-admin-scripts/product-category-metabox/category-handlers.js
deleted file mode 100644
index 831b455e64e..00000000000
--- a/plugins/woocommerce/client/admin/client/wp-admin-scripts/product-category-metabox/category-handlers.js
+++ /dev/null
@@ -1,25 +0,0 @@
-export const CATEGORY_TERM_NAME = 'product_cat';
-
-export function getCategoryDataFromElement( element ) {
- if ( element && element.dataset && element.dataset.name ) {
- return {
- term_id: parseInt( element.value, 10 ),
- name: element.dataset.name,
- };
- }
- return null;
-}
-
-export function getSelectedCategoryData( container ) {
- if ( container ) {
- const selectedCategories = Array.from(
- container.querySelectorAll( ':scope > input[type=hidden]' )
- ).map( ( categoryElement ) => {
- const id = getCategoryDataFromElement( categoryElement );
- categoryElement.remove();
- return id;
- } );
- return selectedCategories;
- }
- return [];
-}
diff --git a/plugins/woocommerce/client/admin/client/wp-admin-scripts/product-category-metabox/category-metabox.tsx b/plugins/woocommerce/client/admin/client/wp-admin-scripts/product-category-metabox/category-metabox.tsx
deleted file mode 100644
index 4e863bdac8b..00000000000
--- a/plugins/woocommerce/client/admin/client/wp-admin-scripts/product-category-metabox/category-metabox.tsx
+++ /dev/null
@@ -1,156 +0,0 @@
-/**
- * External dependencies
- */
-import { __ } from '@wordpress/i18n';
-import { useRef, useState } from '@wordpress/element';
-
-/**
- * Internal dependencies
- */
-import { CATEGORY_TERM_NAME } from './category-handlers';
-import { AllCategoryList } from './all-category-list';
-import { CategoryTerm, PopularCategoryList } from './popular-category-list';
-import { CategoryAddNew } from './category-add-new';
-
-let initialTab = '';
-if ( window.getUserSetting ) {
- initialTab = window.getUserSetting( CATEGORY_TERM_NAME + '_tab' ) || '';
-}
-
-const CATEGORY_POPULAR_TAB_ID = 'pop';
-const CATEGORY_ALL_TAB_ID = 'all';
-
-const CategoryMetabox = ( {
- initialSelected,
-}: {
- initialSelected: CategoryTerm[];
-} ) => {
- const [ selected, setSelected ] = useState( initialSelected );
- const allCategoryListRef = useRef< { resetInitialValues: () => void } >(
- null
- );
- const [ activeTab, setActiveTab ] = useState(
- initialTab === CATEGORY_POPULAR_TAB_ID
- ? initialTab
- : CATEGORY_ALL_TAB_ID
- );
- return (
- <div
- id={ 'taxonomy-' + CATEGORY_TERM_NAME }
- className="categorydiv category-async-metabox"
- >
- <ul className="category-tabs">
- <li
- className={
- activeTab === CATEGORY_ALL_TAB_ID ? 'tabs' : ''
- }
- >
- <a
- href={
- '#' + CATEGORY_TERM_NAME + '-' + CATEGORY_ALL_TAB_ID
- }
- onClick={ ( event ) => {
- event.preventDefault();
- setActiveTab( CATEGORY_ALL_TAB_ID );
- if ( window.deleteUserSetting ) {
- window.deleteUserSetting(
- CATEGORY_TERM_NAME + '_tab'
- );
- }
- } }
- >
- { __( 'All items', 'woocommerce' ) }
- </a>
- </li>
- <li
- className={
- activeTab === CATEGORY_POPULAR_TAB_ID ? 'tabs' : ''
- }
- >
- <a
- href={
- '#' +
- CATEGORY_TERM_NAME +
- '-' +
- CATEGORY_POPULAR_TAB_ID
- }
- onClick={ ( event ) => {
- event.preventDefault();
- setActiveTab( CATEGORY_POPULAR_TAB_ID );
- if ( window.setUserSetting ) {
- window.setUserSetting(
- CATEGORY_TERM_NAME + '_tab',
- CATEGORY_POPULAR_TAB_ID
- );
- }
- } }
- >
- { __( 'Most used', 'woocommerce' ) }
- </a>
- </li>
- </ul>
- <div
- className="tabs-panel"
- id={ CATEGORY_TERM_NAME + '-' + CATEGORY_POPULAR_TAB_ID }
- style={
- activeTab !== CATEGORY_POPULAR_TAB_ID
- ? { display: 'none' }
- : {}
- }
- >
- <ul
- id={
- CATEGORY_TERM_NAME +
- 'checklist-' +
- CATEGORY_POPULAR_TAB_ID
- }
- className="categorychecklist form-no-clear"
- >
- <PopularCategoryList
- selected={ selected }
- onChange={ setSelected }
- />
- </ul>
- </div>
- <div
- className="tabs-panel"
- id={ CATEGORY_TERM_NAME + '-' + CATEGORY_ALL_TAB_ID }
- style={
- activeTab !== CATEGORY_ALL_TAB_ID ? { display: 'none' } : {}
- }
- >
- <AllCategoryList
- selectedCategoryTerms={ selected }
- onChange={ setSelected }
- ref={ allCategoryListRef }
- />
- </div>
- { ( selected || [] ).map( ( sel ) => (
- <input
- key={ sel.term_id }
- type="hidden"
- value={ sel.term_id }
- name={ 'tax_input[' + CATEGORY_TERM_NAME + '][]' }
- />
- ) ) }
- { selected.length === 0 && (
- <input
- type="hidden"
- value=""
- name={ 'tax_input[' + CATEGORY_TERM_NAME + '][]' }
- />
- ) }
- <CategoryAddNew
- selectedCategoryTerms={ selected }
- onChange={ ( sel ) => {
- setSelected( sel );
- if ( allCategoryListRef.current ) {
- allCategoryListRef.current.resetInitialValues();
- }
- } }
- />
- </div>
- );
-};
-
-export default CategoryMetabox;
diff --git a/plugins/woocommerce/client/admin/client/wp-admin-scripts/product-category-metabox/index.js b/plugins/woocommerce/client/admin/client/wp-admin-scripts/product-category-metabox/index.js
deleted file mode 100644
index 463aa2eebee..00000000000
--- a/plugins/woocommerce/client/admin/client/wp-admin-scripts/product-category-metabox/index.js
+++ /dev/null
@@ -1,29 +0,0 @@
-/**
- * External dependencies
- */
-import { createRoot, Suspense, lazy } from '@wordpress/element';
-
-/**
- * Internal dependencies
- */
-import { getSelectedCategoryData } from './category-handlers';
-import './style.scss';
-
-const CategoryMetabox = lazy( () =>
- import( /* webpackChunkName: "category-metabox" */ './category-metabox' )
-);
-
-const metaboxContainer = document.querySelector(
- '#taxonomy-product_cat-metabox'
-);
-if ( metaboxContainer ) {
- const initialSelected = getSelectedCategoryData(
- metaboxContainer.parentElement
- );
- createRoot( metaboxContainer ).render(
- <Suspense fallback={ null }>
- <CategoryMetabox initialSelected={ initialSelected } />
- </Suspense>,
- metaboxContainer
- );
-}
diff --git a/plugins/woocommerce/client/admin/client/wp-admin-scripts/product-category-metabox/popular-category-list.tsx b/plugins/woocommerce/client/admin/client/wp-admin-scripts/product-category-metabox/popular-category-list.tsx
deleted file mode 100644
index d3d797e81bb..00000000000
--- a/plugins/woocommerce/client/admin/client/wp-admin-scripts/product-category-metabox/popular-category-list.tsx
+++ /dev/null
@@ -1,100 +0,0 @@
-/**
- * External dependencies
- */
-import { useEffect, useState } from '@wordpress/element';
-import { addQueryArgs } from '@wordpress/url';
-import { getSetting } from '@woocommerce/settings';
-import apiFetch from '@wordpress/api-fetch';
-
-/**
- * Internal dependencies
- */
-import { CATEGORY_TERM_NAME } from './category-handlers';
-
-declare const wc_product_category_metabox_params: {
- search_taxonomy_terms_nonce: string;
-};
-
-export type CategoryTerm = {
- name: string;
- term_id: number;
- count: number;
-};
-
-export const PopularCategoryList = ( {
- selected,
- onChange,
-}: {
- selected: CategoryTerm[];
- onChange: ( selected: CategoryTerm[] ) => void;
-} ) => {
- const [ popularCategories, setPopularCategories ] = useState<
- CategoryTerm[]
- >( [] );
-
- useEffect( () => {
- apiFetch< CategoryTerm[] >( {
- url: addQueryArgs(
- new URL(
- 'admin-ajax.php',
- getSetting( 'adminUrl' )
- ).toString(),
- {
- action: 'woocommerce_json_search_taxonomy_terms',
- taxonomy: CATEGORY_TERM_NAME,
- limit: 10,
- orderby: 'count',
- order: 'DESC',
- // eslint-disable-next-line no-undef, camelcase
- security:
- wc_product_category_metabox_params.search_taxonomy_terms_nonce,
- }
- ),
- method: 'GET',
- } ).then( ( res ) => {
- if ( res ) {
- setPopularCategories( res.filter( ( cat ) => cat.count > 0 ) );
- }
- } );
- }, [] );
-
- const selectedIds = selected.map( ( sel ) => sel.term_id );
-
- return (
- <ul
- className="categorychecklist form-no-clear"
- id={ CATEGORY_TERM_NAME + 'checklist-pop' }
- >
- { popularCategories.map( ( cat ) => {
- const categoryCheckboxId = `in-popular-${ CATEGORY_TERM_NAME }-${ cat.term_id }`;
- return (
- <li key={ cat.term_id } className="popular-category">
- <label
- className="selectit"
- htmlFor={ categoryCheckboxId }
- >
- <input
- type="checkbox"
- id={ categoryCheckboxId }
- checked={ selectedIds.includes( cat.term_id ) }
- onChange={ () => {
- if ( selectedIds.includes( cat.term_id ) ) {
- onChange(
- selected.filter(
- ( sel ) =>
- sel.term_id !== cat.term_id
- )
- );
- } else {
- onChange( [ ...selected, cat ] );
- }
- } }
- />
- { cat.name }
- </label>
- </li>
- );
- } ) }
- </ul>
- );
-};
diff --git a/plugins/woocommerce/client/admin/client/wp-admin-scripts/product-category-metabox/style.scss b/plugins/woocommerce/client/admin/client/wp-admin-scripts/product-category-metabox/style.scss
deleted file mode 100644
index bfc1564a2f4..00000000000
--- a/plugins/woocommerce/client/admin/client/wp-admin-scripts/product-category-metabox/style.scss
+++ /dev/null
@@ -1,64 +0,0 @@
-.product-add-category {
- &__tree-control {
- margin-top: $gap-smaller;
-
- .woocommerce-tree-select-control {
- .components-base-control,
- .woocommerce-tree-select-control__tree {
- padding: 0 5px;
- }
-
- .components-checkbox-control__label {
- min-height: $gap-larger;
- }
-
- &__tags {
- display: none;
- }
- .components-base-control .woocommerce-tree-select-control__control-input,
- .woocommerce-tree-select-control__option {
- font-size: 12px;
- }
- .components-checkbox-control__input {
- height: $gap;
- width: $gap;
- }
- .components-checkbox-control__checked {
- height: $gap + $gap-smallest;
- width: $gap + $gap-smallest;
- }
- }
- }
-}
-
-.categorydiv.category-async-metabox {
- #product_cat-all {
- overflow: visible;
-
- .categorychecklist {
- max-height: 140px;
- margin-left: 0;
- > li {
- display: flex;
- align-items: center;
- margin-right: $gap-small;
- }
- .ntdelbutton {
- position: relative;
- margin: 0;
- }
- }
- }
- .woocommerce-experimental-select-control__combo-box-wrapper {
- min-height: 30px;
- border-radius: $gap-smallest;
- }
- .woocommerce-experimental-select-control__menu-item {
- padding: 5px $gap-small;
- }
- .category-add {
- &__error {
- color: $error-red;
- }
- }
-}
diff --git a/plugins/woocommerce/client/admin/config/core.json b/plugins/woocommerce/client/admin/config/core.json
index 9a8247c4928..c33a84a26e6 100644
--- a/plugins/woocommerce/client/admin/config/core.json
+++ b/plugins/woocommerce/client/admin/config/core.json
@@ -37,7 +37,6 @@
"woo-mobile-welcome": true,
"wc-pay-promotion": true,
"wc-pay-welcome-page": true,
- "async-product-editor-category-field": false,
"launch-your-store": true,
"use-wp-horizon": false,
"rest-api-v4": false,
diff --git a/plugins/woocommerce/client/admin/config/development.json b/plugins/woocommerce/client/admin/config/development.json
index 89bdafe155f..94147a04818 100644
--- a/plugins/woocommerce/client/admin/config/development.json
+++ b/plugins/woocommerce/client/admin/config/development.json
@@ -37,7 +37,6 @@
"woo-mobile-welcome": true,
"wc-pay-promotion": true,
"wc-pay-welcome-page": true,
- "async-product-editor-category-field": true,
"launch-your-store": true,
"use-wp-horizon": false,
"rest-api-v4": false,
diff --git a/plugins/woocommerce/includes/class-wc-ajax.php b/plugins/woocommerce/includes/class-wc-ajax.php
index a30cfe596cf..7c01900c137 100644
--- a/plugins/woocommerce/includes/class-wc-ajax.php
+++ b/plugins/woocommerce/includes/class-wc-ajax.php
@@ -2054,9 +2054,13 @@ class WC_AJAX {
/**
* Search for categories and return json.
*
+ * @deprecated 10.9.0 This callback was used by the removed async product editor category field.
+ *
* @return void
*/
public static function json_search_categories_tree() {
+ wc_deprecated_function( __METHOD__, '10.9.0' );
+
ob_start();
check_ajax_referer( 'search-categories', 'security' );
diff --git a/plugins/woocommerce/phpstan-baseline.neon b/plugins/woocommerce/phpstan-baseline.neon
index 21152626014..d9197bf6882 100644
--- a/plugins/woocommerce/phpstan-baseline.neon
+++ b/plugins/woocommerce/phpstan-baseline.neon
@@ -45993,18 +45993,6 @@ parameters:
count: 1
path: src/Admin/FeaturePlugin.php
- -
- message: '#^Method Automattic\\WooCommerce\\Admin\\Features\\AsyncProductEditorCategoryField\\Init\:\:enqueue_scripts\(\) has no return type specified\.$#'
- identifier: missingType.return
- count: 1
- path: src/Admin/Features/AsyncProductEditorCategoryField/Init.php
-
- -
- message: '#^Method Automattic\\WooCommerce\\Admin\\Features\\AsyncProductEditorCategoryField\\Init\:\:enqueue_styles\(\) has no return type specified\.$#'
- identifier: missingType.return
- count: 1
- path: src/Admin/Features/AsyncProductEditorCategoryField/Init.php
-
-
message: '#^Access to an undefined property WooCommerce\:\:\$payment_gateways\.$#'
identifier: property.notFound
diff --git a/plugins/woocommerce/src/Admin/Features/AsyncProductEditorCategoryField/Init.php b/plugins/woocommerce/src/Admin/Features/AsyncProductEditorCategoryField/Init.php
deleted file mode 100644
index 89b53f0ac00..00000000000
--- a/plugins/woocommerce/src/Admin/Features/AsyncProductEditorCategoryField/Init.php
+++ /dev/null
@@ -1,86 +0,0 @@
-<?php
-/**
- * WooCommerce Async Product Editor Category Field.
- */
-
-namespace Automattic\WooCommerce\Admin\Features\AsyncProductEditorCategoryField;
-
-use Automattic\Jetpack\Constants;
-use Automattic\WooCommerce\Admin\Features\Features;
-use Automattic\WooCommerce\Internal\Admin\WCAdminAssets;
-use Automattic\WooCommerce\Admin\PageController;
-
-/**
- * Loads assets related to the async category field for the product editor.
- */
-class Init {
-
- const FEATURE_ID = 'async-product-editor-category-field';
-
- /**
- * Constructor
- */
- public function __construct() {
- if ( Features::is_enabled( self::FEATURE_ID ) ) {
- add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_styles' ) );
- add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
- add_filter( 'woocommerce_taxonomy_args_product_cat', array( $this, 'add_metabox_args' ) );
- }
- }
-
- /**
- * Adds meta_box_cb callback arguments for custom metabox.
- *
- * @param array $args Category taxonomy args.
- * @return array $args category taxonomy args.
- */
- public function add_metabox_args( $args ) {
- if ( ! isset( $args['meta_box_cb'] ) ) {
- $args['meta_box_cb'] = 'WC_Meta_Box_Product_Categories::output';
- $args['meta_box_sanitize_cb'] = 'taxonomy_meta_box_sanitize_cb_checkboxes';
- }
- return $args;
- }
-
- /**
- * Enqueue scripts needed for the product form block editor.
- */
- public function enqueue_scripts() {
- if ( ! PageController::is_embed_page() ) {
- return;
- }
-
- WCAdminAssets::register_script( 'wp-admin-scripts', 'product-category-metabox', true );
- wp_localize_script(
- 'wc-admin-product-category-metabox',
- 'wc_product_category_metabox_params',
- array(
- 'search_categories_nonce' => wp_create_nonce( 'search-categories' ),
- 'search_taxonomy_terms_nonce' => wp_create_nonce( 'search-taxonomy-terms' ),
- )
- );
- wp_enqueue_script( 'product-category-metabox' );
-
- }
-
- /**
- * Enqueue styles needed for the rich text editor.
- */
- public function enqueue_styles() {
- if ( ! PageController::is_embed_page() ) {
- return;
- }
- $version = Constants::get_constant( 'WC_VERSION' );
-
- wp_register_style(
- 'woocommerce_admin_product_category_metabox_styles',
- WCAdminAssets::get_url( 'product-category-metabox/style', 'css' ),
- array(),
- $version
- );
- wp_style_add_data( 'woocommerce_admin_product_category_metabox_styles', 'rtl', 'replace' );
-
- wp_enqueue_style( 'woocommerce_admin_product_category_metabox_styles' );
- }
-
-}