From 9d12459c445ef79c0dc47c8068d6c03e4abc789d Mon Sep 17 00:00:00 2001 From: Paul Sealock Date: Fri, 9 Aug 2024 14:18:39 +1200 Subject: [PATCH] [Navigation] Prepare to remove feature (#50190) --- .../50190-add-navigation-deprecation | 4 + .../changelog/add-navigation-deprecation | 4 + packages/js/navigation/src/index.js | 24 +- .../client/homescreen/layout.js | 4 - .../woocommerce-admin/client/layout/index.js | 10 - .../client/layout/navigation.js | 110 ---- .../client/layout/test/index.js | 4 - .../layout/transient-notices/style.scss | 2 - .../navigation/components/Item/index.js | 48 -- .../components/category-title/index.js | 26 - .../components/category-title/style.scss | 10 - .../components/category-title/test/index.js | 80 --- .../navigation/components/container/index.js | 129 ----- .../components/container/primary-menu.js | 89 --- .../components/container/secondary-menu.js | 39 -- .../components/container/style.scss | 118 ---- .../components/container/test/index.js | 253 --------- .../components/favorite-button/index.js | 68 --- .../components/favorite-button/style.scss | 9 - .../components/favorite-button/test/index.js | 109 ---- .../components/favorites-tooltip/index.js | 60 -- .../navigation/components/header/index.js | 133 ----- .../navigation/components/header/style.scss | 39 -- .../components/header/test/index.js | 95 ---- .../intro-modal/images/nav-intro-1.png | Bin 15645 -> 0 bytes .../intro-modal/images/nav-intro-2.png | Bin 10103 -> 0 bytes .../intro-modal/images/nav-intro-3.png | Bin 14417 -> 0 bytes .../components/intro-modal/index.js | 120 ---- .../components/intro-modal/style.scss | 76 --- .../components/intro-modal/test/index.js | 74 --- .../client/navigation/index.js | 16 - .../client/navigation/style.scss | 167 ------ .../navigation/stylesheets/_variables.scss | 22 - .../client/navigation/test/sample-test.js | 5 - .../client/navigation/test/utils.js | 521 ------------------ .../client/navigation/utils.ts | 259 --------- .../navigation-opt-out/container.js | 63 --- .../navigation-opt-out/index.js | 18 - .../navigation-opt-out/style.scss | 8 - .../add-navigation-items/js/index.js | 26 - ...rce-admin-add-navigation-items-example.php | 77 --- .../docs/features/navigation.md | 125 ----- plugins/woocommerce-admin/webpack.config.js | 1 - .../50190-add-navigation-deprecation | 4 + .../Admin/Features/Navigation/CoreMenu.php | 1 + .../Admin/Features/Navigation/Favorites.php | 1 + .../src/Admin/Features/Navigation/Init.php | 114 +--- .../src/Admin/Features/Navigation/Menu.php | 258 +-------- .../src/Admin/Features/Navigation/Screen.php | 20 +- .../woocommerce/src/Admin/PageController.php | 2 +- .../Internal/Features/FeaturesController.php | 12 - .../navigation/class-wc-favorites.php | 89 --- .../navigation/class-wc-menu.php | 293 ---------- .../navigation/class-wc-screen.php | 198 ------- 54 files changed, 54 insertions(+), 3983 deletions(-) create mode 100644 packages/js/navigation/changelog/50190-add-navigation-deprecation create mode 100644 packages/js/navigation/changelog/add-navigation-deprecation delete mode 100644 plugins/woocommerce-admin/client/layout/navigation.js delete mode 100644 plugins/woocommerce-admin/client/navigation/components/Item/index.js delete mode 100644 plugins/woocommerce-admin/client/navigation/components/category-title/index.js delete mode 100644 plugins/woocommerce-admin/client/navigation/components/category-title/style.scss delete mode 100644 plugins/woocommerce-admin/client/navigation/components/category-title/test/index.js delete mode 100644 plugins/woocommerce-admin/client/navigation/components/container/index.js delete mode 100644 plugins/woocommerce-admin/client/navigation/components/container/primary-menu.js delete mode 100644 plugins/woocommerce-admin/client/navigation/components/container/secondary-menu.js delete mode 100644 plugins/woocommerce-admin/client/navigation/components/container/style.scss delete mode 100644 plugins/woocommerce-admin/client/navigation/components/container/test/index.js delete mode 100644 plugins/woocommerce-admin/client/navigation/components/favorite-button/index.js delete mode 100644 plugins/woocommerce-admin/client/navigation/components/favorite-button/style.scss delete mode 100644 plugins/woocommerce-admin/client/navigation/components/favorite-button/test/index.js delete mode 100644 plugins/woocommerce-admin/client/navigation/components/favorites-tooltip/index.js delete mode 100644 plugins/woocommerce-admin/client/navigation/components/header/index.js delete mode 100644 plugins/woocommerce-admin/client/navigation/components/header/style.scss delete mode 100644 plugins/woocommerce-admin/client/navigation/components/header/test/index.js delete mode 100644 plugins/woocommerce-admin/client/navigation/components/intro-modal/images/nav-intro-1.png delete mode 100644 plugins/woocommerce-admin/client/navigation/components/intro-modal/images/nav-intro-2.png delete mode 100644 plugins/woocommerce-admin/client/navigation/components/intro-modal/images/nav-intro-3.png delete mode 100644 plugins/woocommerce-admin/client/navigation/components/intro-modal/index.js delete mode 100644 plugins/woocommerce-admin/client/navigation/components/intro-modal/style.scss delete mode 100644 plugins/woocommerce-admin/client/navigation/components/intro-modal/test/index.js delete mode 100644 plugins/woocommerce-admin/client/navigation/index.js delete mode 100644 plugins/woocommerce-admin/client/navigation/style.scss delete mode 100644 plugins/woocommerce-admin/client/navigation/stylesheets/_variables.scss delete mode 100644 plugins/woocommerce-admin/client/navigation/test/sample-test.js delete mode 100644 plugins/woocommerce-admin/client/navigation/test/utils.js delete mode 100644 plugins/woocommerce-admin/client/navigation/utils.ts delete mode 100644 plugins/woocommerce-admin/client/wp-admin-scripts/navigation-opt-out/container.js delete mode 100644 plugins/woocommerce-admin/client/wp-admin-scripts/navigation-opt-out/index.js delete mode 100644 plugins/woocommerce-admin/client/wp-admin-scripts/navigation-opt-out/style.scss delete mode 100644 plugins/woocommerce-admin/docs/examples/extensions/add-navigation-items/js/index.js delete mode 100644 plugins/woocommerce-admin/docs/examples/extensions/add-navigation-items/woocommerce-admin-add-navigation-items-example.php delete mode 100644 plugins/woocommerce-admin/docs/features/navigation.md create mode 100644 plugins/woocommerce/changelog/50190-add-navigation-deprecation delete mode 100644 plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/navigation/class-wc-favorites.php delete mode 100644 plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/navigation/class-wc-menu.php delete mode 100644 plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/navigation/class-wc-screen.php diff --git a/packages/js/navigation/changelog/50190-add-navigation-deprecation b/packages/js/navigation/changelog/50190-add-navigation-deprecation new file mode 100644 index 00000000000..1f80f12d42d --- /dev/null +++ b/packages/js/navigation/changelog/50190-add-navigation-deprecation @@ -0,0 +1,4 @@ +Significance: minor +Type: update + +Remove WooCommerce Navigation client side feature and deprecate PHP classes. \ No newline at end of file diff --git a/packages/js/navigation/changelog/add-navigation-deprecation b/packages/js/navigation/changelog/add-navigation-deprecation new file mode 100644 index 00000000000..478aeb0697e --- /dev/null +++ b/packages/js/navigation/changelog/add-navigation-deprecation @@ -0,0 +1,4 @@ +Significance: patch +Type: update + +Remove deprecated Navigation SlotFill diff --git a/packages/js/navigation/src/index.js b/packages/js/navigation/src/index.js index 9197c337b26..b22b51ad883 100644 --- a/packages/js/navigation/src/index.js +++ b/packages/js/navigation/src/index.js @@ -1,17 +1,11 @@ /** * External dependencies */ -import { - createElement, - useState, - useEffect, - useLayoutEffect, -} from '@wordpress/element'; +import { useState, useEffect, useLayoutEffect } from '@wordpress/element'; import { addQueryArgs } from '@wordpress/url'; import { parse } from 'qs'; import { pick } from 'lodash'; import { applyFilters } from '@wordpress/hooks'; -import { Slot, Fill } from '@wordpress/components'; import { getAdminLink } from '@woocommerce/settings'; /** @@ -343,19 +337,3 @@ export const navigateTo = ( { url } ) => { window.location.href = String( parsedUrl ); }; - -/** - * A Fill for extensions to add client facing custom Navigation Items. - * - * @slotFill WooNavigationItem - * @scope woocommerce-navigation - * @param {Object} props React props. - * @param {Array} props.children Node children. - * @param {string} props.item Navigation item slug. - */ -export const WooNavigationItem = ( { children, item } ) => { - return { children }; -}; -WooNavigationItem.Slot = ( { name } ) => ( - -); diff --git a/plugins/woocommerce-admin/client/homescreen/layout.js b/plugins/woocommerce-admin/client/homescreen/layout.js index 0f7e7b744ee..35ead10f211 100644 --- a/plugins/woocommerce-admin/client/homescreen/layout.js +++ b/plugins/woocommerce-admin/client/homescreen/layout.js @@ -27,7 +27,6 @@ import ActivityHeader from '~/activity-panel/activity-header'; import { ActivityPanel } from './activity-panel'; import { Column } from './column'; import InboxPanel from '../inbox-panel'; -import { IntroModal as NavigationIntroModal } from '../navigation/components/intro-modal'; import StatsOverview from './stats-overview'; import { StoreManagementLinks } from '../store-management-links'; import { @@ -162,9 +161,6 @@ export const Layout = ( { > { isDashboardShown ? renderColumns() : renderTaskList() } { shouldShowMobileAppModal && } - { window.wcAdminFeatures.navigation && ( - - ) } ); diff --git a/plugins/woocommerce-admin/client/layout/index.js b/plugins/woocommerce-admin/client/layout/index.js index 2cf1046a630..7b7986343bd 100644 --- a/plugins/woocommerce-admin/client/layout/index.js +++ b/plugins/woocommerce-admin/client/layout/index.js @@ -53,7 +53,6 @@ import { getAdminSetting } from '~/utils/admin-settings'; import { usePageClasses } from './hooks/use-page-classes'; import '~/activity-panel'; import '~/mobile-banner'; -import './navigation'; const StoreAlerts = lazy( () => import( /* webpackChunkName: "store-alerts" */ './store-alerts' ) @@ -125,15 +124,10 @@ function _Layout( { usePageClasses( page ); function recordPageViewTrack() { - const navigationFlag = { - has_navigation: !! window.wcNavigation, - }; - if ( isEmbedded ) { const path = document.location.pathname + document.location.search; recordPageView( path, { is_embedded: true, - ...navigationFlag, } ); return; } @@ -155,7 +149,6 @@ function _Layout( { jetpack_installed: installedPlugins.includes( 'jetpack' ), jetpack_active: activePlugins.includes( 'jetpack' ), jetpack_connected: isJetpackConnected, - ...navigationFlag, } ); } @@ -256,9 +249,6 @@ function _Layout( { { showPluginArea && ( <> - { window.wcAdminFeatures.navigation && ( - - ) } ) } diff --git a/plugins/woocommerce-admin/client/layout/navigation.js b/plugins/woocommerce-admin/client/layout/navigation.js deleted file mode 100644 index f95c801ee18..00000000000 --- a/plugins/woocommerce-admin/client/layout/navigation.js +++ /dev/null @@ -1,110 +0,0 @@ -/** - * External dependencies - */ -import { registerPlugin } from '@wordpress/plugins'; -import { WooHeaderNavigationItem } from '@woocommerce/admin-layout'; -import { - WooNavigationItem, - getNewPath, - pathIsExcluded, - isWCAdmin, -} from '@woocommerce/navigation'; -import { Link } from '@woocommerce/components'; -import { __ } from '@wordpress/i18n'; -import { useSelect } from '@wordpress/data'; -import { NAVIGATION_STORE_NAME } from '@woocommerce/data'; - -/** - * Internal dependencies - */ -import getReports from '../analytics/report/get-reports'; -import { getPages } from './controller'; -import Navigation from '~/navigation'; - -const NavigationPlugin = () => { - const { persistedQuery } = useSelect( ( select ) => { - return { - persistedQuery: select( NAVIGATION_STORE_NAME ).getPersistedQuery(), - }; - } ); - - if ( ! window.wcAdminFeatures.navigation ) { - return null; - } - - /** - * If the current page is embedded, stay with the default urls - * provided by Navigation because the router isn't present to - * respond to component's manipulation of the url. - */ - if ( ! isWCAdmin() ) { - return ( - - - - ); - } - - const reports = getReports().filter( ( item ) => item.navArgs ); - - const pages = getPages() - .filter( ( page ) => page.navArgs ) - .map( ( page ) => { - if ( page.path === '/analytics/settings' ) { - return { - ...page, - breadcrumbs: [ __( 'Analytics', 'woocommerce' ) ], - }; - } - return page; - } ); - - return ( - <> - - - - { pages.map( ( page ) => ( - - - { page.breadcrumbs[ page.breadcrumbs.length - 1 ] } - - - ) ) } - { reports.map( ( item ) => ( - - - { item.title } - - - ) ) } - - ); -}; - -registerPlugin( 'wc-admin-navigation', { - render: NavigationPlugin, - scope: 'woocommerce-navigation', -} ); diff --git a/plugins/woocommerce-admin/client/layout/test/index.js b/plugins/woocommerce-admin/client/layout/test/index.js index 3c83e190eec..92542320c0a 100644 --- a/plugins/woocommerce-admin/client/layout/test/index.js +++ b/plugins/woocommerce-admin/client/layout/test/index.js @@ -34,8 +34,6 @@ jest.mock( '@woocommerce/components', () => ( { jest.mock( '~/activity-panel', () => null ); -jest.mock( '../navigation', () => null ); - jest.mock( '~/utils/admin-settings', () => { const adminSetting = jest.requireActual( '~/utils/admin-settings' ); return { @@ -136,7 +134,6 @@ describe( 'EmbedLayout', () => { window.history.pushState( {}, 'Page Title', '/url?search' ); render( ); expect( recordPageView ).toHaveBeenCalledWith( '/url?search', { - has_navigation: true, is_embedded: true, } ); } ); @@ -168,7 +165,6 @@ describe( 'PageLayout', () => { mockPath( '/analytics/overview' ); render( ); expect( recordPageView ).toHaveBeenCalledWith( 'analytics_overview', { - has_navigation: true, jetpack_active: false, jetpack_connected: false, jetpack_installed: false, diff --git a/plugins/woocommerce-admin/client/layout/transient-notices/style.scss b/plugins/woocommerce-admin/client/layout/transient-notices/style.scss index cd9641556f9..6b3ada9ea13 100644 --- a/plugins/woocommerce-admin/client/layout/transient-notices/style.scss +++ b/plugins/woocommerce-admin/client/layout/transient-notices/style.scss @@ -1,5 +1,3 @@ -@import "../../navigation/stylesheets/variables.scss"; - .woocommerce-transient-notices { position: absolute; left: $gap; diff --git a/plugins/woocommerce-admin/client/navigation/components/Item/index.js b/plugins/woocommerce-admin/client/navigation/components/Item/index.js deleted file mode 100644 index c08888e8b72..00000000000 --- a/plugins/woocommerce-admin/client/navigation/components/Item/index.js +++ /dev/null @@ -1,48 +0,0 @@ -/** - * External dependencies - */ -import { NavigationItem, useSlot } from '@woocommerce/experimental'; -import { recordEvent } from '@woocommerce/tracks'; -import { WooNavigationItem } from '@woocommerce/navigation'; - -const Item = ( { item } ) => { - const slot = useSlot( 'woocommerce_navigation_' + item.id ); - const hasFills = Boolean( slot?.fills?.length ); - - const trackClick = ( id ) => { - recordEvent( 'navigation_click', { - menu_item: id, - } ); - }; - - // Disable reason: The div wrapping the slot item is used for tracking purposes - // and should not be a tabbable element. - /* eslint-disable jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events */ - - // Only render a slot if a corresponding Fill exists and the item is not a category - if ( hasFills && ! item.isCategory ) { - return ( - -
trackClick( item.id ) }> - -
-
- ); - } - - return ( - trackClick( item.id ) } - hideIfTargetMenuEmpty - /> - ); - /* eslint-enable jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events */ -}; - -export default Item; diff --git a/plugins/woocommerce-admin/client/navigation/components/category-title/index.js b/plugins/woocommerce-admin/client/navigation/components/category-title/index.js deleted file mode 100644 index 7342e90d771..00000000000 --- a/plugins/woocommerce-admin/client/navigation/components/category-title/index.js +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Internal dependencies - */ -import './style.scss'; -import { FavoriteButton } from '../favorite-button'; -import { FavoritesTooltip } from '../favorites-tooltip'; - -export const CategoryTitle = ( { category } ) => { - const { id, menuId, title } = category; - - const className = 'woocommerce-navigation-category-title'; - - if ( [ 'plugins', 'favorites' ].includes( menuId ) ) { - return ( - - { title } - - - - ); - } - - return { title }; -}; - -export default CategoryTitle; diff --git a/plugins/woocommerce-admin/client/navigation/components/category-title/style.scss b/plugins/woocommerce-admin/client/navigation/components/category-title/style.scss deleted file mode 100644 index 408d505b99a..00000000000 --- a/plugins/woocommerce-admin/client/navigation/components/category-title/style.scss +++ /dev/null @@ -1,10 +0,0 @@ -.woocommerce-navigation-category-title { - display: flex; - align-items: center; - font-size: 20px; - line-height: 28px; - - .woocommerce-navigation-favorite-button { - margin-left: auto; - } -} diff --git a/plugins/woocommerce-admin/client/navigation/components/category-title/test/index.js b/plugins/woocommerce-admin/client/navigation/components/category-title/test/index.js deleted file mode 100644 index 54a9b9d67c9..00000000000 --- a/plugins/woocommerce-admin/client/navigation/components/category-title/test/index.js +++ /dev/null @@ -1,80 +0,0 @@ -/** - * External dependencies - */ -import { render } from '@testing-library/react'; -import { createElement } from '@wordpress/element'; - -/** - * Internal dependencies - */ -import CategoryTitle from '../'; - -describe( 'CategoryTitle', () => { - test( 'should render the category title without the option to favorite for the primary menu', () => { - const { container, queryByText } = render( - - ); - - expect( - container.querySelector( '.woocommerce-navigation-favorite-button' ) - ).toBeNull(); - expect( queryByText( 'Category Title' ) ).not.toBeNull(); - } ); - - test( 'should render the category title without the option to favorite for any other menus', () => { - const { container, queryByText } = render( - - ); - - expect( - container.querySelector( '.woocommerce-navigation-favorite-button' ) - ).toBeNull(); - expect( queryByText( 'Category Title' ) ).not.toBeNull(); - } ); - - test( 'should render the category title and favorite button for plugins', () => { - const { container, queryByText } = render( - - ); - - expect( - container.querySelector( '.woocommerce-navigation-favorite-button' ) - ).not.toBeNull(); - expect( queryByText( 'Category Title' ) ).not.toBeNull(); - } ); - - test( 'should render the category title and unfavorite button for favorites', () => { - const { container, queryByText } = render( - - ); - - expect( - container.querySelector( '.woocommerce-navigation-favorite-button' ) - ).not.toBeNull(); - expect( queryByText( 'Category Title' ) ).not.toBeNull(); - } ); -} ); diff --git a/plugins/woocommerce-admin/client/navigation/components/container/index.js b/plugins/woocommerce-admin/client/navigation/components/container/index.js deleted file mode 100644 index 2be5d22d659..00000000000 --- a/plugins/woocommerce-admin/client/navigation/components/container/index.js +++ /dev/null @@ -1,129 +0,0 @@ -/** - * External dependencies - */ -import { useEffect, useMemo, useState, useRef } from '@wordpress/element'; -import clsx from 'clsx'; -import { Navigation } from '@woocommerce/experimental'; -import { NAVIGATION_STORE_NAME, useUser } from '@woocommerce/data'; -import { recordEvent } from '@woocommerce/tracks'; -import { useSelect } from '@wordpress/data'; -import { addHistoryListener } from '@woocommerce/navigation'; - -/** - * Internal dependencies - */ -import { getMappedItemsCategories, getMatchingItem } from '../../utils'; -import Header from '../header'; -import { PrimaryMenu } from './primary-menu'; -import { SecondaryMenu } from './secondary-menu'; - -const Container = () => { - const { menuItems } = useSelect( ( select ) => { - return { - menuItems: select( NAVIGATION_STORE_NAME ).getMenuItems(), - }; - } ); - - useEffect( () => { - // Collapse the original WP Menu. - document.documentElement.classList.remove( 'wp-toolbar' ); - document.body.classList.add( 'has-woocommerce-navigation' ); - const adminMenu = document.getElementById( 'adminmenumain' ); - - if ( ! adminMenu ) { - return; - } - - adminMenu.classList.add( 'folded' ); - }, [] ); - - const [ activeItem, setActiveItem ] = useState( 'woocommerce-home' ); - const [ activeLevel, setActiveLevel ] = useState( 'woocommerce' ); - - useEffect( () => { - const initialMatchedItem = getMatchingItem( menuItems ); - if ( initialMatchedItem && activeItem !== initialMatchedItem ) { - setActiveItem( initialMatchedItem ); - setActiveLevel( initialMatchedItem.parent ); - } - - const removeListener = addHistoryListener( () => { - setTimeout( () => { - const matchedItem = getMatchingItem( menuItems ); - if ( matchedItem ) { - setActiveItem( matchedItem ); - setActiveLevel( matchedItem.parent ); - } - }, 0 ); - } ); - - return removeListener; - }, [ menuItems ] ); - - const { currentUserCan } = useUser(); - - const { categories, items } = useMemo( - () => getMappedItemsCategories( menuItems, currentUserCan ), - [ menuItems, currentUserCan ] - ); - - const navDomRef = useRef( null ); - - const onBackClick = ( id ) => { - recordEvent( 'navigation_back_click', { - category: id, - } ); - }; - - const isRoot = activeLevel === 'woocommerce'; - - const classes = clsx( 'woocommerce-navigation', { - 'is-root': isRoot, - } ); - - return ( -
-
-
- { - if ( navDomRef && navDomRef.current ) { - navDomRef.current.scrollTop = 0; - } - - setActiveLevel( ...args ); - } } - > - { Object.values( categories ).map( ( category ) => { - const categoryItems = items[ category.id ]; - - return ( - !! categoryItems && [ - , - , - ] - ); - } ) } - -
-
- ); -}; - -export default Container; diff --git a/plugins/woocommerce-admin/client/navigation/components/container/primary-menu.js b/plugins/woocommerce-admin/client/navigation/components/container/primary-menu.js deleted file mode 100644 index bf3d0d6d612..00000000000 --- a/plugins/woocommerce-admin/client/navigation/components/container/primary-menu.js +++ /dev/null @@ -1,89 +0,0 @@ -/** - * External dependencies - */ -import { __ } from '@wordpress/i18n'; -import { NavigationMenu, NavigationGroup } from '@woocommerce/experimental'; -import { applyFilters } from '@wordpress/hooks'; - -/** - * Internal dependencies - */ -import CategoryTitle from '../category-title'; -import Item from '../../components/Item'; - -export const PrimaryMenu = ( { - category, - onBackClick, - pluginItems, - primaryItems, -} ) => { - if ( ! primaryItems.length && ! pluginItems.length ) { - return null; - } - - /** - * Navigation's exit button WooCommerce label. - * - * @filter woocommerce_navigation_root_back_label - * @param {string} label Back button label. - */ - const rootBackLabel = applyFilters( - 'woocommerce_navigation_root_back_label', - __( 'WordPress Dashboard', 'woocommerce' ) - ); - - /** - * Navigation's exit button url. - * - * @filter woocommerce_navigation_root_back_url - * @param {string} url Back button url. - */ - const rootBackUrl = applyFilters( - 'woocommerce_navigation_root_back_url', - window.wcNavigation.rootBackUrl - ); - - const isRootBackVisible = category.id === 'woocommerce' && rootBackUrl; - - return ( - } - menu={ category.id } - parentMenu={ category.parent } - backButtonLabel={ - isRootBackVisible - ? rootBackLabel - : category.backButtonLabel || null - } - onBackButtonClick={ - isRootBackVisible - ? () => { - onBackClick( 'woocommerce' ); - window.location = rootBackUrl; - } - : () => onBackClick( category.id ) - } - > - { !! primaryItems.length && ( - - { primaryItems.map( ( item ) => ( - - ) ) } - - ) } - { !! pluginItems.length && ( - - { pluginItems.map( ( item ) => ( - - ) ) } - - ) } - - ); -}; diff --git a/plugins/woocommerce-admin/client/navigation/components/container/secondary-menu.js b/plugins/woocommerce-admin/client/navigation/components/container/secondary-menu.js deleted file mode 100644 index aa159e373f8..00000000000 --- a/plugins/woocommerce-admin/client/navigation/components/container/secondary-menu.js +++ /dev/null @@ -1,39 +0,0 @@ -/** - * External dependencies - */ -import { NavigationMenu, NavigationGroup } from '@woocommerce/experimental'; - -/** - * Internal dependencies - */ -import CategoryTitle from '../category-title'; -import Item from '../../components/Item'; - -export const SecondaryMenu = ( { category, items, onBackClick } ) => { - if ( ! items.length ) { - return null; - } - - const isRoot = category.id === 'woocommerce'; - - return ( - } - menu={ category.id } - parentMenu={ category.parent } - backButtonLabel={ category.backButtonLabel || null } - onBackButtonClick={ - isRoot ? null : () => onBackClick( category.id ) - } - > - onBackClick( category.id ) } - > - { items.map( ( item ) => ( - - ) ) } - - - ); -}; diff --git a/plugins/woocommerce-admin/client/navigation/components/container/style.scss b/plugins/woocommerce-admin/client/navigation/components/container/style.scss deleted file mode 100644 index 4ddff7f38b2..00000000000 --- a/plugins/woocommerce-admin/client/navigation/components/container/style.scss +++ /dev/null @@ -1,118 +0,0 @@ -.woocommerce-navigation { - display: grid; - grid-template-rows: min-content 1fr; - height: 100%; -} - -.woocommerce-navigation .woocommerce-navigation__wrapper { - h2 > span { - width: 100%; - } - - .components-navigation__menu { - overflow-y: auto; - margin-bottom: 0; - padding-bottom: $gap-large; - } - - .components-navigation__group + .components-navigation__group { - margin-top: 24px; - } - - .components-navigation__item { - margin-bottom: 0; - - .components-button { - opacity: 1; - } - - &:not(:hover) { - .components-button { - color: $gray-400; - } - } - &:hover { - .components-button { - color: $white; - } - } - &.is-active { - .components-button { - color: #fff; - } - } - - /* - * <-------- Start Temporary Code --------> - * - * A change to Gutenberg base Navigation component in version 9.8.3 - * requires these overrides. As of this comment, the problematic code - * was published to .org but not shipped as part of WP 5.7. - * - * A fix in Gutenberg is https://github.com/WordPress/gutenberg/pull/28619 - * - * Criteria for removal - * 1. https://github.com/WordPress/gutenberg/pull/28619 is merged and deployed to .org - * 2. https://github.com/WordPress/gutenberg/pull/28619 is included in the Gutenberg version associated with WP 5.7 - * 3. If not part of WP 5.7, this code will be required until WP 6.0 is released and WC Admin no longer supports 5.7 - */ - a.components-button { - padding: 6px 16px; - } - &:not(:hover) { - a.components-button { - // ${ G2.lightGray.ui }; - color: $gray-400; - } - } - &.is-active { - a.components-button { - // ${ UI.textDark }; - color: #fff; - } - } - /* - * <-------- End Temporary Code --------> - */ - } - - .components-navigation { - height: 100%; - } - - .components-navigation > div { - height: 100%; - display: grid; - grid-template-rows: 1fr min-content; - } - - &.is-root { - .components-navigation__menu-secondary { - border-top: 1px solid $studio-gray-80; - margin: 0 -#{$gap-smaller}; - padding: $gap $gap-smaller $gap-small $gap-smaller; - } - } - - .components-navigation__menu-title, - .components-navigation__group-title { - color: #f0f0f0; - opacity: 1; - } - - .components-navigation__back-button { - color: $gray-400; - opacity: 1; - - &, - span { - font-size: 13px; - line-height: normal; - } - - &:hover, - &:hover:not(:disabled) { - color: #ddd; - } - } -} diff --git a/plugins/woocommerce-admin/client/navigation/components/container/test/index.js b/plugins/woocommerce-admin/client/navigation/components/container/test/index.js deleted file mode 100644 index a13535d618f..00000000000 --- a/plugins/woocommerce-admin/client/navigation/components/container/test/index.js +++ /dev/null @@ -1,253 +0,0 @@ -/** - * External dependencies - */ -import { act, render, waitFor } from '@testing-library/react'; -import { getAdminLink } from '@woocommerce/settings'; -import { getHistory } from '@woocommerce/navigation'; -import { useSelect } from '@wordpress/data'; -import userEvent from '@testing-library/user-event'; -import { createElement } from '@wordpress/element'; - -/** - * Internal dependencies - */ -import Container from '../'; - -jest.mock( '@wordpress/data', () => { - // Require the original module to not be mocked... - const originalModule = jest.requireActual( '@wordpress/data' ); - - return { - __esModule: true, // Use it when dealing with esModules - ...originalModule, - useSelect: jest.fn().mockReturnValue( {} ), - }; -} ); - -const originalLocation = window.location; -global.window = Object.create( window ); -window.wcNavigation = { - rootBackLabel: 'Root Back', - rootBackUrl: 'http://custombackbutton.com', -}; - -const menuItems = [ - { - id: 'woocommerce-home', - title: 'Home', - parent: 'woocommerce', - menuId: 'primary', - url: 'admin.php?page=wc-admin', - }, - { - id: 'primary-category', - title: 'Primary Category', - isCategory: true, - parent: 'woocommerce', - backButtonLabel: 'Custom Back Label', - menuId: 'primary', - }, - { - id: 'primary-child', - title: 'Primary Child', - parent: 'primary-category', - menuId: 'primary', - url: 'admin.php?page=wc-admin&path=/child', - }, - { - id: 'favorite-category', - title: 'Favorite Category', - isCategory: true, - parent: 'woocommerce', - menuId: 'favorites', - }, - { - id: 'favorite-child', - title: 'Favorite Child', - parent: 'favorite-category', - menuId: 'plugins', - }, - { - id: 'plugin-category', - title: 'Plugin Category', - isCategory: true, - parent: 'woocommerce', - menuId: 'plugins', - }, - { - id: 'plugin-child', - title: 'Plugin Child', - parent: 'plugin-category', - menuId: 'plugins', - url: 'admin.php?page=my-plugin', - }, - { - id: 'secondary-category', - title: 'Secondary Category', - isCategory: true, - parent: 'woocommerce', - menuId: 'secondary', - }, - { - id: 'secondary-child', - title: 'Secondary Child', - parent: 'secondary-category', - menuId: 'secondary', - }, -]; - -describe( 'Container', () => { - beforeEach( () => { - delete window.location; - window.location = new URL( getAdminLink( 'admin.php?page=wc-admin' ) ); - - useSelect.mockImplementation( () => ( { - menuItems, - favorites: [ 'favorite-category' ], - } ) ); - } ); - - afterAll( () => { - window.location = originalLocation; - } ); - - test( 'should show the woocommerce root items initially', () => { - const { container } = render( ); - - expect( - container.querySelectorAll( '.components-navigation__item' ).length - ).toBe( 5 ); - } ); - - test( 'should set the active item based on initial location', async () => { - const { queryByText } = render( ); - - expect( - queryByText( 'Home' ).parentElement.parentElement.classList - ).toContain( 'is-active' ); - } ); - - test( 'should set the initial active item based on current location', () => { - window.location = new URL( getAdminLink( 'admin.php?page=my-plugin' ) ); - - const { container, queryByText } = render( ); - - expect( - container.querySelector( '.woocommerce-navigation-category-title' ) - .textContent - ).toBe( 'Plugin Category' ); - expect( - queryByText( 'Plugin Child' ).parentElement.parentElement.classList - ).toContain( 'is-active' ); - } ); - - test( 'should update the active item and level when location changes', async () => { - window.location = new URL( getAdminLink( 'admin.php?page=wc-admin' ) ); - - const { container, queryByText } = render( ); - - expect( queryByText( 'Primary Child' ) ).toBeNull(); - - // Trigger and wait for history change. - await act( async () => { - delete window.location; - window.location = new URL( - getAdminLink( 'admin.php?page=wc-admin&path=/child' ) - ); - getHistory().push( new URL( getAdminLink( '/child' ) ) ); - } ); - - await waitFor( () => - expect( - container.querySelector( - '.woocommerce-navigation-category-title' - ).textContent - ).toBe( 'Primary Category' ) - ); - await waitFor( () => - expect( - queryByText( 'Primary Child' ).parentElement.parentElement - .classList - ).toContain( 'is-active' ) - ); - } ); - - test( 'should update the active level when a category is clicked', () => { - const { container, queryByText } = render( ); - - userEvent.click( queryByText( 'Secondary Category' ) ); - - expect( - container.querySelector( '.woocommerce-navigation-category-title' ) - .textContent - ).toBe( 'Secondary Category' ); - } ); - - test( 'should show the back button in each category', () => { - const { container, queryByText } = render( ); - - userEvent.click( queryByText( 'Primary Category' ) ); - - const backButton = container.querySelector( - '.components-navigation__back-button' - ); - - expect( backButton.textContent ).toBe( 'Custom Back Label' ); - } ); - - test( 'should go up a level on back button click', () => { - const { container, queryByText } = render( ); - - userEvent.click( queryByText( 'Primary Category' ) ); - - const backButton = container.querySelector( - '.components-navigation__back-button' - ); - - userEvent.click( backButton ); - - expect( - container.querySelector( '.woocommerce-navigation-category-title' ) - .textContent - ).toBe( 'WooCommerce' ); - } ); - - test( 'should show the favorite items after the primary items', () => { - const { container } = render( ); - - const navigationGroups = container.querySelectorAll( - '.components-navigation__group' - ); - - expect( - navigationGroups[ 0 ].querySelector( 'li:nth-child(1)' ).textContent - ).toBe( 'Home' ); - expect( - navigationGroups[ 0 ].querySelector( 'li:nth-child(2)' ).textContent - ).toBe( 'Primary Category' ); - expect( - navigationGroups[ 0 ].querySelector( 'li:nth-child(3)' ).textContent - ).toBe( 'Favorite Category' ); - expect( - navigationGroups[ 1 ].querySelector( 'li:nth-child(1)' ).textContent - ).toBe( 'Plugin Category' ); - } ); - - test( 'should not show multiple menus outside of the root category', () => { - const { container, queryByText } = render( ); - - const rootNavigationGroups = container.querySelectorAll( - '.components-navigation__group' - ); - - expect( rootNavigationGroups.length ).toBe( 3 ); - - userEvent.click( queryByText( 'Primary Category' ) ); - - const categoryNavigationGroups = container.querySelectorAll( - '.components-navigation__group' - ); - - expect( categoryNavigationGroups.length ).toBe( 1 ); - } ); -} ); diff --git a/plugins/woocommerce-admin/client/navigation/components/favorite-button/index.js b/plugins/woocommerce-admin/client/navigation/components/favorite-button/index.js deleted file mode 100644 index 167e17b104d..00000000000 --- a/plugins/woocommerce-admin/client/navigation/components/favorite-button/index.js +++ /dev/null @@ -1,68 +0,0 @@ -/** - * External dependencies - */ -import { __ } from '@wordpress/i18n'; -import { Button } from '@wordpress/components'; -import { NAVIGATION_STORE_NAME } from '@woocommerce/data'; -import { recordEvent } from '@woocommerce/tracks'; -import { useDispatch, useSelect } from '@wordpress/data'; -import { Icon, starEmpty, starFilled } from '@wordpress/icons'; - -/** - * Internal dependencies - */ -import './style.scss'; - -export const FavoriteButton = ( { id } ) => { - const { favorites, isResolving } = useSelect( ( select ) => { - return { - favorites: select( NAVIGATION_STORE_NAME ).getFavorites(), - isResolving: select( NAVIGATION_STORE_NAME ).isResolving( - 'getFavorites' - ), - }; - } ); - - const { addFavorite, removeFavorite } = useDispatch( - NAVIGATION_STORE_NAME - ); - - const isFavorited = favorites.includes( id ); - - const toggleFavorite = () => { - const toggle = isFavorited ? removeFavorite : addFavorite; - toggle( id ); - recordEvent( 'navigation_favorite', { - id, - action: isFavorited ? 'unfavorite' : 'favorite', - } ); - }; - - if ( isResolving ) { - return null; - } - - return ( - - ); -}; - -export default FavoriteButton; diff --git a/plugins/woocommerce-admin/client/navigation/components/favorite-button/style.scss b/plugins/woocommerce-admin/client/navigation/components/favorite-button/style.scss deleted file mode 100644 index 7cdb36fd7cd..00000000000 --- a/plugins/woocommerce-admin/client/navigation/components/favorite-button/style.scss +++ /dev/null @@ -1,9 +0,0 @@ -.woocommerce-navigation-favorite-button.components-button { - .star-empty-icon { - color: $gray-600; - } - - .star-filled-icon { - color: $alert-yellow; - } -} diff --git a/plugins/woocommerce-admin/client/navigation/components/favorite-button/test/index.js b/plugins/woocommerce-admin/client/navigation/components/favorite-button/test/index.js deleted file mode 100644 index b33c6ed85ac..00000000000 --- a/plugins/woocommerce-admin/client/navigation/components/favorite-button/test/index.js +++ /dev/null @@ -1,109 +0,0 @@ -/** - * External dependencies - */ -import { render } from '@testing-library/react'; -import { useDispatch, useSelect } from '@wordpress/data'; -import userEvent from '@testing-library/user-event'; -import { createElement } from '@wordpress/element'; - -/** - * Internal dependencies - */ -import FavoriteButton from '../'; - -jest.mock( '@wordpress/data', () => { - // Require the original module to not be mocked... - const originalModule = jest.requireActual( '@wordpress/data' ); - - return { - __esModule: true, // Use it when dealing with esModules - ...originalModule, - useDispatch: jest.fn().mockReturnValue( {} ), - useSelect: jest.fn().mockReturnValue( {} ), - }; -} ); - -describe( 'FavoriteButton', () => { - test( 'should not show when favorites are still resolving', () => { - useSelect.mockImplementation( () => ( { - favorites: [], - isResolving: true, - } ) ); - - const { container } = render( ); - - expect( - container.querySelector( '.woocommerce-navigation-favorite-button' ) - ).toBeNull(); - } ); - - test( 'should show the empty star when item is not favorited', () => { - useSelect.mockImplementation( () => ( { - favorites: [], - isResolving: false, - } ) ); - - const { container } = render( ); - - expect( container.querySelector( '.star-empty-icon' ) ).not.toBeNull(); - } ); - - test( 'should show the filled star when item is favorited', () => { - useSelect.mockImplementation( () => ( { - favorites: [ 'my-item' ], - isResolving: false, - } ) ); - - const { container } = render( ); - - expect( container.querySelector( '.star-filled-icon' ) ).not.toBeNull(); - } ); - - test( 'should remove the favorite when toggling a favorited item', () => { - useSelect.mockImplementation( () => ( { - favorites: [ 'my-item' ], - isResolving: false, - } ) ); - - const addFavorite = jest.fn(); - const removeFavorite = jest.fn(); - - useDispatch.mockReturnValue( { - addFavorite, - removeFavorite, - } ); - - const { container } = render( ); - - userEvent.click( - container.querySelector( '.woocommerce-navigation-favorite-button' ) - ); - - expect( addFavorite ).not.toHaveBeenCalled(); - expect( removeFavorite ).toHaveBeenCalled(); - } ); - - test( 'should add the favorite when toggling a unfavorited item', () => { - useSelect.mockImplementation( () => ( { - favorites: [], - isResolving: false, - } ) ); - - const addFavorite = jest.fn(); - const removeFavorite = jest.fn(); - - useDispatch.mockReturnValue( { - addFavorite, - removeFavorite, - } ); - - const { container } = render( ); - - userEvent.click( - container.querySelector( '.woocommerce-navigation-favorite-button' ) - ); - - expect( addFavorite ).toHaveBeenCalled(); - expect( removeFavorite ).not.toHaveBeenCalled(); - } ); -} ); diff --git a/plugins/woocommerce-admin/client/navigation/components/favorites-tooltip/index.js b/plugins/woocommerce-admin/client/navigation/components/favorites-tooltip/index.js deleted file mode 100644 index 4a9f5456d72..00000000000 --- a/plugins/woocommerce-admin/client/navigation/components/favorites-tooltip/index.js +++ /dev/null @@ -1,60 +0,0 @@ -/** - * External dependencies - */ -import { __ } from '@wordpress/i18n'; -import { NAVIGATION_STORE_NAME, OPTIONS_STORE_NAME } from '@woocommerce/data'; -import { useDispatch, useSelect } from '@wordpress/data'; - -/** - * Internal dependencies - */ -import { HighlightTooltip } from '~/activity-panel/highlight-tooltip'; - -const tooltipHiddenOption = 'woocommerce_navigation_favorites_tooltip_hidden'; - -export const FavoritesTooltip = () => { - const { isFavoritesResolving, isOptionResolving, isTooltipHidden } = - useSelect( ( select ) => { - const { getOption, isResolving } = select( OPTIONS_STORE_NAME ); - return { - isFavoritesResolving: select( - NAVIGATION_STORE_NAME - ).isResolving( 'getFavorites' ), - isOptionResolving: isResolving( 'getOption', [ - tooltipHiddenOption, - ] ), - isTooltipHidden: getOption( tooltipHiddenOption ) === 'yes', - }; - } ); - - const { updateOptions } = useDispatch( OPTIONS_STORE_NAME ); - - if ( isFavoritesResolving || isTooltipHidden || isOptionResolving ) { - return null; - } - - if ( document.body.classList.contains( 'is-wc-nav-folded' ) ) { - return null; - } - - return ( - - updateOptions( { - [ tooltipHiddenOption ]: 'yes', - } ) - } - useAnchor - /> - ); -}; - -export default FavoritesTooltip; diff --git a/plugins/woocommerce-admin/client/navigation/components/header/index.js b/plugins/woocommerce-admin/client/navigation/components/header/index.js deleted file mode 100644 index 43335d22b58..00000000000 --- a/plugins/woocommerce-admin/client/navigation/components/header/index.js +++ /dev/null @@ -1,133 +0,0 @@ -/** - * External dependencies - */ -import { __ } from '@wordpress/i18n'; -import { Button } from '@wordpress/components'; -import { decodeEntities } from '@wordpress/html-entities'; -import { Icon, wordpress } from '@wordpress/icons'; -import { getSetting } from '@woocommerce/settings'; -import { useSelect } from '@wordpress/data'; -import { useEffect, useState } from '@wordpress/element'; -import clsx from 'clsx'; -import { debounce } from 'lodash'; -import { addHistoryListener } from '@woocommerce/navigation'; - -/** - * Internal dependencies - */ -import useIsScrolled from '../../../hooks/useIsScrolled'; - -const Header = () => { - const siteTitle = getSetting( 'siteTitle', '' ); - const homeUrl = getSetting( 'homeUrl', '' ); - const { isScrolled } = useIsScrolled(); - const [ isFolded, setIsFolded ] = useState( - document.body.classList.contains( false ) - ); - const navClasses = { - folded: 'is-wc-nav-folded', - expanded: 'is-wc-nav-expanded', - }; - - const foldNav = () => { - document.body.classList.add( navClasses.folded ); - document.body.classList.remove( navClasses.expanded ); - setIsFolded( true ); - }; - - const expandNav = () => { - document.body.classList.remove( navClasses.folded ); - document.body.classList.add( navClasses.expanded ); - setIsFolded( false ); - }; - - const toggleFolded = () => { - if ( document.body.classList.contains( navClasses.folded ) ) { - expandNav(); - } else { - foldNav(); - } - }; - - const foldOnMobile = ( screenWidth = document.body.clientWidth ) => { - if ( screenWidth <= 960 ) { - foldNav(); - } else { - expandNav(); - } - }; - - useEffect( () => { - foldOnMobile(); - const foldEvents = [ - { - eventName: 'orientationchange', - handler: ( e ) => foldOnMobile( e.target.screen.availWidth ), - }, - { - eventName: 'resize', - handler: debounce( () => foldOnMobile(), 200 ), - }, - ]; - - for ( const { eventName, handler } of foldEvents ) { - window.addEventListener( eventName, handler, false ); - } - - addHistoryListener( () => foldOnMobile() ); - }, [] ); - - let buttonIcon = ; - - const { isRequestingSiteIcon, siteIconUrl } = useSelect( ( select ) => { - const { isResolving } = select( 'core/data' ); - const { getEntityRecord } = select( 'core' ); - const siteData = - getEntityRecord( 'root', '__unstableBase', undefined ) || {}; - - return { - isRequestingSiteIcon: isResolving( 'core', 'getEntityRecord', [ - 'root', - '__unstableBase', - undefined, - ] ), - siteIconUrl: siteData.siteIconUrl, - }; - } ); - - if ( siteIconUrl ) { - buttonIcon = ( - { - ); - } else if ( isRequestingSiteIcon ) { - buttonIcon = null; - } - - const className = clsx( 'woocommerce-navigation-header', { - 'is-scrolled': isScrolled, - } ); - - return ( -
- - -
- ); -}; - -export default Header; diff --git a/plugins/woocommerce-admin/client/navigation/components/header/style.scss b/plugins/woocommerce-admin/client/navigation/components/header/style.scss deleted file mode 100644 index fa835f9c737..00000000000 --- a/plugins/woocommerce-admin/client/navigation/components/header/style.scss +++ /dev/null @@ -1,39 +0,0 @@ -.woocommerce-navigation-header { - display: flex; - align-items: center; - border: none; - border-radius: 0; - height: auto; - - .woocommerce-navigation-header__site-icon.components-button { - padding: 12px; - height: 60px; - color: #fff; - - &:hover, - &:focus, - &:not([aria-disabled="true"]):active { - color: #fff; - } - } - - .woocommerce-navigation-header__site-title.components-button { - padding-left: 0; - color: $gray-400; - font-weight: 600; - - &:hover, - &:focus, - &:active { - color: $gray-200; - } - } - - .woocommerce-navigation-header__site-title { - padding-top: 0; - display: -webkit-box; - -webkit-line-clamp: 2; - -webkit-box-orient: vertical; - overflow: hidden; - } -} diff --git a/plugins/woocommerce-admin/client/navigation/components/header/test/index.js b/plugins/woocommerce-admin/client/navigation/components/header/test/index.js deleted file mode 100644 index 0225d0c2273..00000000000 --- a/plugins/woocommerce-admin/client/navigation/components/header/test/index.js +++ /dev/null @@ -1,95 +0,0 @@ -/** - * External dependencies - */ -import { render } from '@testing-library/react'; -import { useSelect } from '@wordpress/data'; - -/** - * Internal dependencies - */ -import Header from '../'; - -global.window.wcNavigation = {}; - -jest.mock( '@woocommerce/settings', () => ( { - ...jest.requireActual( '@woocommerce/settings' ), - getSetting: jest.fn( ( setting ) => { - const settings = { - homeUrl: 'https://fake-site-url.com', - siteTitle: 'Fake & Title <3', - }; - return settings[ setting ]; - } ), -} ) ); - -jest.mock( '@wordpress/data', () => { - // Require the original module to not be mocked... - const originalModule = jest.requireActual( '@wordpress/data' ); - - return { - __esModule: true, // Use it when dealing with esModules - ...originalModule, - useDispatch: jest.fn().mockReturnValue( {} ), - useSelect: jest.fn().mockReturnValue( {} ), - }; -} ); - -describe( 'Header', () => { - test( 'should not show the button when the site icon is requesting', () => { - useSelect.mockImplementation( () => ( { - isRequestingSiteIcon: true, - siteIconUrl: null, - } ) ); - - const { container } = render(
); - - expect( container.querySelector( 'img' ) ).toBeNull(); - } ); - - test( 'should show the button when the site icon has resolved', () => { - useSelect.mockImplementation( () => ( { - isRequestingSiteIcon: false, - siteIconUrl: '#', - } ) ); - - const { container } = render(
); - - expect( container.querySelector( 'img' ) ).not.toBeNull(); - } ); - - test( 'should start with the nav expanded in larger viewports', () => { - Object.defineProperty( window.HTMLElement.prototype, 'clientWidth', { - configurable: true, - value: 2000, - } ); - - render(
); - - expect( Object.values( document.body.classList ) ).toContain( - 'is-wc-nav-expanded' - ); - } ); - - test( 'should start with the nav folded when the viewport is smaller', () => { - Object.defineProperty( window.HTMLElement.prototype, 'clientWidth', { - configurable: true, - value: 480, - } ); - - render(
); - - expect( Object.values( document.body.classList ) ).toContain( - 'is-wc-nav-folded' - ); - } ); - - test( 'should decode site titles', () => { - const { container } = render(
); - - expect( - container.querySelector( - '.woocommerce-navigation-header__site-title' - ).textContent - ).toBe( 'Fake & Title <3' ); - } ); -} ); diff --git a/plugins/woocommerce-admin/client/navigation/components/intro-modal/images/nav-intro-1.png b/plugins/woocommerce-admin/client/navigation/components/intro-modal/images/nav-intro-1.png deleted file mode 100644 index 3beff125f777f40659c57c6216816e43fba8d3ed..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15645 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%0D_?}gp!u&56V{6xl&_YT-5&5-sL-b!TLw% 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

vkbn?k6*3f9} z5>t=U*}9VYHt)0(fJpqM{Q=pS;M#TWQqv?^w@$2X~MRxDmSyVG8Ku& zWpFrT#+5wNnOAgzto<$TQ4DN1Sz_+}I)&zz=qQ?kb`RxfNjS7;Fpm!AwEV6cEWp;U zq7Nrp(Aw7v=V_~o!|8RoOIjh5rbGP%6nTXsu=1yt3vIU3?_LE|DgKOu#ND23No1!5v70T2^YW7y>kk?)h2HJ7&rmwoqd<_GRK6|A;5b9 zVLC=%-iQyxBQy8PP8g?|q6d)>Kz`&YiG2c}0rRXwy+W{JvUk4B&YFwkNVEO^T3v(o z;{rPk?Ml_4vuR(+ds!}yPt{D`@-+Yb!e(IOaCY+K{@|;PpPgx%qv>j$G3CFa6t zM!87SEQ{z>bpRgFpOl59Z>xZhfUrg8yhA3&iI2E6ZCLpHe`&e@f4D6n-B~Xi2|%K8 zI_mrX9$Nom*JmRUTQW<$Noi)SumvZ?{1dddM^*}w9^4KOyM#VbZd+FbqdO-nRsJ*D z+_CY(1Q>&C17^XQ7A^nDF+eEX{UIE>lt+ts%EHEJJ0f9gH7nahNYy$kh;e7xeAd#% z*@1S@vrkZ-rCzPHKgRf7jj3115iE19gb82N*!p&y+lqzZS5;}x#_xo)yud$)UPM&I zSaX0!;e;v0JT8y6Iy_7eDYL1XB)jhGz2ffTR2_d9QzL%!e7zl91&nxkTG0>Fe>hz6 z#D=utM|IdNYEv>s+c*SR3uDl(l~wkx%ER2OVpv{j^P{f~&P$BKkmCFtzA z(Fj$rdYDf`Pt3Eb)@{Ubx@~{xBib8&^p|E@ITv;7DEc>{?PQhGq}!isZjDWctPtPvup)vI zMk+ID7({pVH!W2EYIHgkOhTJgV(mSyPiu2K50Cg)esy^J>UbW}y0yK(vUPiG&qL>Y zxh#NcxbX%atS@O4o3LT%ctN{Tjo(MO==9|3T2gmWoT|=l_|hqm<(E0ZAQvQuQ^ZwUy8C|POtsQIE&lD>cNy7NwAXH-4QQO(dBJ= z(5Evo1@!5YyN2?i<_9$Kv$8+Uk7JcHS1$|~0JuptZnHoWIFKw0#=oHQdR%$PA)%l0 zbm79$^hca^rdBtpeyJ_HGat%gL_$k^9$S`+=JoC^qgbJ5O~kg|GK$JwCg6yC;e-ybaGgEKqy>+^>fhuO58nlJ4L}>uVI=x#h0#^y2K#I*(apPj(&a0 z2817Rf|*GCWeh-v-(|2He)7pA0AV&B&{y1PP)^)AIL@X+zZfuVZKN_^M1L}rX!z8O4TBLKxyNOk_+tdR0jE*ENo-!Dueu&Q7|z2qnEEpk#IL;=9k*N3oX z=85wHjX()N$2+4(h1{0u5V*nR?fv$73G$_T0}U|$@Snp80J-Ll7VcGiO`df4P|e#% zM*-BdXt{bwl2G%b`W?Zt#lM@ci{HoGndW|l_2-d_dh$y$JHG!o z`mpO~SucGt*C{R^iO|josho(j-niCG=2IGsR5iL(GyY6V>~_w*4yIdg+$)JSju$%N z$<@T~XKlu>cB2QcN)9}}ugu8;7ZDoVhh19Scyah#&lMI;*Dw0}Yty4X`;S4^F7LVT zXe20(nv1Rp)>Mn)cQY<=pU&Q z4dIRqVypPKu>QgS#Z$GhC_pwgTqqObhMyMpK_peU$Q4_pSxe?xwf5(hOWMd=7S9lT$vV`^(im%bO0enMEG6*fHgRfO~c8N+6Y+x%zzHeKd zgR|Y0--$8Yoxguu9eh1+dL@$kgtL%@b91*SOAZa7`H#02x={<*`fgucU)ft<`?@7O z-LLR37lIapEIUZnG}<;PWwII&Vjm6OblgjwzK}iGylqC%!U{$xp-D?V6ILGQ7C%#o z4Pe0R%{OTt!+)`&PC=InWkT^l`wiZBXBO*J*KWdYexlW#fN0j#Y9B#zJww~YgU_jz zGg#7jk%HTZiZJ&`5EJ@mK5{hrp^E^DcoDImHRWL!{cR4XsINfMrQ`~JR5G1i5Oav< zSF>5J4GDXIEW@JcV#xfrO18W3gpO`jciTA4N*+jt&#*|<5#X&kE>?qToaac6pr=KY zMyhuRMA=2jwcq0gtxr9Ud0G&4f8dj|$uv~(2mvi!%Q zpq-ly;}&fVje}E{9!I;ppM5WQbW%}w@!($7#ykXW0 z#@4@jkeMWc;p0b}E1OmqwDatG`=|W6X3xHW+{*y-6nXB@bo7>~aq>S<`or9{?g zJZX`oRab0J1d-fXCzqdmv%t%ms1}o68fyGeLzyJK@Yr%+)q#88c|Oa)JIhGc?mA^M;byTVyE& z|Bp+H2hRF)w6X)=6jvNSFZ_D!E>Ut-^@QuYDIn3JbSD15l9L!cYxjOC&IRHjc+aj& z>jqA6T0~XF{7stpz{jqDlG5(~Jm}u_Qk7(>MPmE)H+7|8wF{ypNNx2u@&_SFh0Vu5 z;_RVV9VeuKA53cAj~P-^RdRIdMb%5t?ZI$E=kEj1@sSe{`z1@ZBd@!6_<22f98Daw zJN_=T=GYuVAk?u@URJ%>ft$vEx7|}Exq;#1pZpwL?v(+!9rhz+`15S4UOvxdWiuZE N7(TdLssHrN{{V5RpbG#1 diff --git a/plugins/woocommerce-admin/client/navigation/components/intro-modal/images/nav-intro-2.png b/plugins/woocommerce-admin/client/navigation/components/intro-modal/images/nav-intro-2.png deleted file mode 100644 index fe69a4be83723acc32f16cb4cbc33b965d7a51a4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10103 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 diff --git a/plugins/woocommerce-admin/client/navigation/components/intro-modal/index.js b/plugins/woocommerce-admin/client/navigation/components/intro-modal/index.js deleted file mode 100644 index 6925ac3f288..00000000000 --- a/plugins/woocommerce-admin/client/navigation/components/intro-modal/index.js +++ /dev/null @@ -1,120 +0,0 @@ -/** - * External dependencies - */ -import { __ } from '@wordpress/i18n'; -import { Guide } from '@wordpress/components'; -import { OPTIONS_STORE_NAME } from '@woocommerce/data'; -import { recordEvent } from '@woocommerce/tracks'; -import { Text } from '@woocommerce/experimental'; -import { useState } from '@wordpress/element'; -import { useSelect, useDispatch } from '@wordpress/data'; - -/** - * Internal dependencies - */ -import './style.scss'; -import NavInto1 from './images/nav-intro-1.png'; -import NavInto2 from './images/nav-intro-2.png'; -import NavInto3 from './images/nav-intro-3.png'; - -export const INTRO_MODAL_DISMISSED_OPTION_NAME = - 'woocommerce_navigation_intro_modal_dismissed'; - -export const IntroModal = () => { - const [ isOpen, setOpen ] = useState( true ); - - const { updateOptions } = useDispatch( OPTIONS_STORE_NAME ); - - const { isDismissed, isResolving } = useSelect( ( select ) => { - const { getOption, isResolving: isOptionResolving } = - select( OPTIONS_STORE_NAME ); - const dismissedOption = getOption( INTRO_MODAL_DISMISSED_OPTION_NAME ); - - return { - isDismissed: dismissedOption === 'yes', - isResolving: - typeof dismissedOption === 'undefined' || - isOptionResolving( 'getOption', [ - INTRO_MODAL_DISMISSED_OPTION_NAME, - ] ), - }; - } ); - - const dismissModal = () => { - updateOptions( { - [ INTRO_MODAL_DISMISSED_OPTION_NAME ]: 'yes', - } ); - recordEvent( 'navigation_intro_modal_close', {} ); - setOpen( false ); - }; - - if ( ! isOpen || isDismissed || isResolving ) { - return null; - } - - const getPage = ( title, description, imageUrl ) => { - return { - content: ( -

-
- - { title } - - - { description } - -
-
- { -
-
- ), - }; - }; - - return ( - - ); -}; diff --git a/plugins/woocommerce-admin/client/navigation/components/intro-modal/style.scss b/plugins/woocommerce-admin/client/navigation/components/intro-modal/style.scss deleted file mode 100644 index 0b7f00c33cb..00000000000 --- a/plugins/woocommerce-admin/client/navigation/components/intro-modal/style.scss +++ /dev/null @@ -1,76 +0,0 @@ -.woocommerce-navigation-intro-modal { - width: 670px; - - @include breakpoint( "<782px" ) { - width: 350px; - } - - .components-guide__page-control { - order: 3; - margin: $gap 0; - - li { - margin: 0; - } - } - - .components-modal__header { - display: none; - } - - .components-guide__container { - margin-top: 0; - } - - .components-guide__footer { - box-sizing: border-box; - margin: 0; - height: 0; - overflow: visible; - - .components-button { - position: absolute; - bottom: 100%; - margin-bottom: $gap; - } - - .components-guide__back-button { - display: none; - } - } - - &.components-modal__frame.components-guide { - height: auto; - } - - .woocommerce-navigation-intro-modal__page-wrapper { - display: grid; - grid-template-columns: 1fr 1fr; - - img { - max-width: 100%; - } - - @include breakpoint( "<782px" ) { - grid-template-columns: 1fr; - - .woocommerce-navigation-intro-modal__image-wrapper { - grid-row: 1; - max-height: 328px; - overflow: hidden; - } - } - } - - .woocommerce-navigation-intro-modal__page-text { - padding: $gap-large; - display: flex; - flex-direction: column; - justify-content: center; - - h2 { - font-weight: bold; - margin-bottom: $gap-smaller; - } - } -} diff --git a/plugins/woocommerce-admin/client/navigation/components/intro-modal/test/index.js b/plugins/woocommerce-admin/client/navigation/components/intro-modal/test/index.js deleted file mode 100644 index f81a797472b..00000000000 --- a/plugins/woocommerce-admin/client/navigation/components/intro-modal/test/index.js +++ /dev/null @@ -1,74 +0,0 @@ -/** - * External dependencies - */ -import { fireEvent, render, screen } from '@testing-library/react'; -import { useDispatch, useSelect } from '@wordpress/data'; - -/** - * Internal dependencies - */ -import { IntroModal, INTRO_MODAL_DISMISSED_OPTION_NAME } from '../'; - -global.window.wcNavigation = {}; - -jest.mock( '@wordpress/data', () => { - // Require the original module to not be mocked... - const originalModule = jest.requireActual( '@wordpress/data' ); - - return { - __esModule: true, // Use it when dealing with esModules - ...originalModule, - useDispatch: jest.fn().mockReturnValue( {} ), - useSelect: jest.fn().mockReturnValue( {} ), - }; -} ); - -describe( 'IntroModal', () => { - test( 'should not show when modal options are resolving', () => { - useSelect.mockImplementation( () => ( { - isResolving: true, - } ) ); - - const { container } = render( ); - - expect( container ).toBeEmptyDOMElement(); - } ); - - test( 'should not dismiss when the modal has already been dismissed', () => { - const updateOptions = jest.fn(); - useSelect.mockImplementation( () => ( { - isDismissed: true, - isResolving: false, - } ) ); - useDispatch.mockImplementation( () => ( { - updateOptions, - } ) ); - - const { container } = render( ); - - expect( container ).toBeEmptyDOMElement(); - expect( updateOptions ).not.toHaveBeenCalled(); - } ); - - test( 'should hide and update the dismissal option when closing the modal', () => { - const updateOptions = jest.fn(); - useSelect.mockImplementation( () => ( { - isResolving: false, - isDismissed: false, - } ) ); - useDispatch.mockImplementation( () => ( { - updateOptions, - } ) ); - - render( ); - - fireEvent.click( screen.queryByLabelText( 'Close dialog' ) ); - - expect( - screen.queryByText( 'A new navigation for WooCommerce' ) - ).toBeNull(); - expect( updateOptions ).toHaveBeenCalledWith( { - [ INTRO_MODAL_DISMISSED_OPTION_NAME ]: 'yes', - } ); - } ); -} ); diff --git a/plugins/woocommerce-admin/client/navigation/index.js b/plugins/woocommerce-admin/client/navigation/index.js deleted file mode 100644 index 9f0898b4317..00000000000 --- a/plugins/woocommerce-admin/client/navigation/index.js +++ /dev/null @@ -1,16 +0,0 @@ -/** - * External dependencies - */ -import { withNavigationHydration } from '@woocommerce/data'; - -/** - * Internal dependencies - */ -import './style.scss'; -import Container from './components/container'; - -const HydratedNavigation = withNavigationHydration( window.wcNavigation )( - Container -); - -export default HydratedNavigation; diff --git a/plugins/woocommerce-admin/client/navigation/style.scss b/plugins/woocommerce-admin/client/navigation/style.scss deleted file mode 100644 index 3d4098ebeb3..00000000000 --- a/plugins/woocommerce-admin/client/navigation/style.scss +++ /dev/null @@ -1,167 +0,0 @@ -@import "./stylesheets/variables.scss"; -@import "./components/container/style.scss"; -@import "./components/header/style.scss"; - -.woocommerce-navigation { - position: relative; - width: $navigation-width; - box-sizing: border-box; - background-color: $gray-900; - z-index: 1100; //Must be greater than z-index on .woocommerce-layout__header - - @media ( max-width: 960px ) { - width: $header-height; - height: $header-height; - } - - .components-navigation { - box-sizing: border-box; - } - - .components-navigation__menu-title { - overflow: visible; - } - - .components-navigation__menu { - scrollbar-color: $gray-700 $gray-900; - scrollbar-width: thin; - - &::-webkit-scrollbar-thumb { - border-radius: 10px; - background-color: $gray-700; - } - - - &::-webkit-scrollbar-thumb:hover { - background-color: $gray-700; - width: 8px; - height: 8px; - } - - - &::-webkit-scrollbar { - width: 8px; - height: 8px; - } - } -} - -.woocommerce-navigation__wrapper { - background-color: $gray-900; - position: absolute; - top: $header-height; - width: 100%; - height: calc(100vh - #{$header-height + $adminbar-height}); - overflow-y: auto; -} - -.is-wp-toolbar-disabled .woocommerce-navigation__wrapper { - height: calc(100vh - #{$header-height}); -} - -body.is-wc-nav-expanded { - .woocommerce-navigation { - width: $navigation-width; - height: 100%; - } - - font > .xdebug-error { - margin-left: calc(#{$navigation-width} + #{$gap}); - } -} - -body.is-wc-nav-folded { - .woocommerce-navigation { - width: $header-height; - height: $header-height; - overflow: hidden; - - .woocommerce-navigation-header { - > * { - display: none; - } - } - - .woocommerce-navigation-header__site-icon { - display: block; - } - - .components-navigation { - display: none; - } - } - - .woocommerce-transient-notices { - left: $gap; - } - - #wpbody { - padding-left: 0; - } -} - -.has-woocommerce-navigation { - #adminmenuwrap, - #adminmenuback { - display: none !important; - } - - &.woocommerce_page_wc-reports, - &.woocommerce_page_wc-settings, - &.woocommerce_page_wc-status { - .woo-nav-tab-wrapper { - display: none; - } - - .woocommerce .subsubsub { - font-size: 14px; - margin: 5px 0; - } - } - - #wpcontent, - #wpfooter { - margin-left: 0; - - @media ( max-width: 960px ) { - margin-left: 0; - } - } - - #wpbody { - padding-left: $navigation-width; - - @media ( max-width: 960px ) { - padding-left: 0; - } - } - - .woocommerce-layout__header.is-embed-loading { - &::before { - content: ""; - position: fixed; - width: $navigation-width; - height: 100%; - background: $gray-900; - - @include breakpoint( "<960px" ) { - width: $header-height; - height: $header-height; - } - } - } - - #woocommerce-embedded-root.is-embed-loading { - margin-bottom: -$adminbar-height; - } - - &:not(.is-wp-toolbar-disabled) { - #wpbody-content { - margin-top: $adminbar-height; - } - } - - font > .xdebug-error { - margin-top: $header-height; - } -} diff --git a/plugins/woocommerce-admin/client/navigation/stylesheets/_variables.scss b/plugins/woocommerce-admin/client/navigation/stylesheets/_variables.scss deleted file mode 100644 index ba6cc601576..00000000000 --- a/plugins/woocommerce-admin/client/navigation/stylesheets/_variables.scss +++ /dev/null @@ -1,22 +0,0 @@ -// WooCommerce Navigation -$navigation-width: 240px; -$navigation-x-padding: 30px; - -// WordPress defaults. -$admin-menu-width: 160px; -$admin-bar-height: 32px; -$admin-bar-height-mobile: 46px; - -// Gaps and gutters. -$fallback-gutter: 24px; -$fallback-gutter-large: 40px; -$gutter: var(--main-gap); -$gutter-large: var(--large-gap); - -$gap-largest: 40px; -$gap-larger: 36px; -$gap-large: 24px; -$gap: 16px; -$gap-small: 12px; -$gap-smaller: 8px; -$gap-smallest: 4px; diff --git a/plugins/woocommerce-admin/client/navigation/test/sample-test.js b/plugins/woocommerce-admin/client/navigation/test/sample-test.js deleted file mode 100644 index b68cb362003..00000000000 --- a/plugins/woocommerce-admin/client/navigation/test/sample-test.js +++ /dev/null @@ -1,5 +0,0 @@ -describe( 'Sample test', () => { - it( 'should pass', () => { - expect( true ).not.toBeNull(); - } ); -} ); diff --git a/plugins/woocommerce-admin/client/navigation/test/utils.js b/plugins/woocommerce-admin/client/navigation/test/utils.js deleted file mode 100644 index 477f635b6a1..00000000000 --- a/plugins/woocommerce-admin/client/navigation/test/utils.js +++ /dev/null @@ -1,521 +0,0 @@ -/** - * External dependencies - */ -import { getAdminLink } from '@woocommerce/settings'; - -/** - * Internal dependencies - */ -import { - getDefaultMatchExpression, - getFullUrl, - getMappedItemsCategories, - getMatchingItem, - getMatchScore, - sortMenuItems, -} from '../utils'; - -const originalLocation = window.location; -global.window = Object.create( window ); -global.window.wcNavigation = {}; - -const sampleMenuItems = [ - { - id: 'main', - title: 'Main page', - url: 'admin.php?page=wc-admin', - }, - { - id: 'path', - title: 'Page with Path', - url: 'admin.php?page=wc-admin&path=/test-path', - }, - { - id: 'hash', - title: 'Page with Hash', - url: 'admin.php?page=wc-admin&path=/test-path#anchor', - }, - { - id: 'multiple-args', - title: 'Page with multiple arguments', - url: 'admin.php?page=wc-admin&path=/test-path§ion=section-name', - }, - { - id: 'multiple-args-plus-one', - title: 'Page with same multiple arguments plus an additional one', - url: 'admin.php?page=wc-admin&path=/test-path§ion=section-name&version=22', - }, - { - id: 'hash-and-multiple-args', - title: 'Page with multiple arguments and a hash', - url: 'admin.php?page=wc-admin&path=/test-path§ion=section-name#anchor', - }, -]; - -const runGetMatchingItemTests = ( items ) => { - it( 'should get the closest matched item', () => { - window.location = new URL( getAdminLink( 'admin.php?page=wc-admin' ) ); - const matchingItem = getMatchingItem( items ); - expect( matchingItem.id ).toBe( 'main' ); - } ); - - it( 'should match the item without hash if a better match does not exist', () => { - window.location = new URL( - getAdminLink( 'admin.php?page=wc-admin#hash' ) - ); - const matchingItem = getMatchingItem( items ); - expect( matchingItem.id ).toBe( 'main' ); - } ); - - it( 'should exactly match the item with a hash if it exists', () => { - window.location = new URL( - getAdminLink( 'admin.php?page=wc-admin&path=/test-path#anchor' ) - ); - const matchingItem = getMatchingItem( items ); - expect( matchingItem.id ).toBe( 'hash' ); - } ); - - it( 'should roughly match the item if all menu item arguments exist', () => { - window.location = new URL( - getAdminLink( - 'admin.php?page=wc-admin&path=/test-path§ion=section-name' - ) - ); - const matchingItem = getMatchingItem( items ); - expect( matchingItem.id ).toBe( 'multiple-args' ); - } ); - - it( 'should match an item with irrelevant query parameters', () => { - window.location = new URL( - getAdminLink( - 'admin.php?page=wc-admin&path=/test-path§ion=section-name&foo=bar' - ) - ); - const matchingItem = getMatchingItem( items ); - expect( matchingItem.id ).toBe( 'multiple-args' ); - } ); - - it( 'should match an item with similar query args plus one additional arg', () => { - window.location = new URL( - getAdminLink( - 'admin.php?page=wc-admin&path=/test-path§ion=section-name&version=22' - ) - ); - const matchingItem = getMatchingItem( items ); - expect( matchingItem.id ).toBe( 'multiple-args-plus-one' ); - } ); - - it( 'should match an item with query parameters in mixed order', () => { - window.location = new URL( - getAdminLink( - 'admin.php?foo=bar&page=wc-admin&path=/test-path§ion=section-name' - ) - ); - const matchingItem = getMatchingItem( items ); - expect( matchingItem.id ).toBe( 'multiple-args' ); - } ); - - it( 'should match an item with query parameters and a hash', () => { - window.location = new URL( - getAdminLink( - 'admin.php?foo=bar&page=wc-admin&path=/test-path§ion=section-name#anchor' - ) - ); - const matchingItem = getMatchingItem( items ); - expect( matchingItem.id ).toBe( 'hash-and-multiple-args' ); - } ); -}; - -describe( 'getMatchingItem', () => { - beforeAll( () => { - delete window.location; - } ); - - afterAll( () => { - window.location = originalLocation; - } ); - - runGetMatchingItemTests( sampleMenuItems ); - // re-run the tests with sampleMenuItems in reverse order. - runGetMatchingItemTests( sampleMenuItems.reverse() ); -} ); - -describe( 'getDefaultMatchExpression', () => { - it( 'should return the regex for the path without query args', () => { - expect( getDefaultMatchExpression( 'http://wordpress.org' ) ).toBe( - '^http:\\/\\/wordpress\\.org' - ); - } ); - - it( 'should return the regex for the path and query args', () => { - expect( - getDefaultMatchExpression( - 'http://wordpress.org?param1=a¶m2=b' - ) - ).toBe( - '^http:\\/\\/wordpress\\.org(?=.*[?|&]param1=a(&|$|#))(?=.*[?|&]param2=b(&|$|#))' - ); - } ); - - it( 'should return the regex with hash if present', () => { - expect( - getDefaultMatchExpression( - 'http://wordpress.org?param1=a¶m2=b#hash' - ) - ).toBe( - '^http:\\/\\/wordpress\\.org(?=.*[?|&]param1=a(&|$|#))(?=.*[?|&]param2=b(&|$|#))(.*#hash$)' - ); - } ); -} ); - -describe( 'getMatchScore', () => { - beforeAll( () => { - delete window.location; - window.location = new URL( getAdminLink( '/' ) ); - } ); - - afterAll( () => { - window.location = originalLocation; - } ); - - it( 'should return max safe integer if the url is an exact match', () => { - expect( - getMatchScore( - new URL( getAdminLink( 'admin.php?page=testpage' ) ), - getAdminLink( 'admin.php?page=testpage' ) - ) - ).toBe( Number.MAX_SAFE_INTEGER ); - } ); - - it( 'should return matching path and parameter count', () => { - expect( - getMatchScore( - new URL( - getFullUrl( - '/wp-admin/admin.php?page=testpage&extra_param=a' - ) - ), - '/wp-admin/admin.php?page=testpage' - ) - ).toBe( 2 ); - } ); - - it( 'should return 0 if the URL does not meet match criteria', () => { - expect( - getMatchScore( - new URL( getAdminLink( 'admin.php?page=different-page' ) ), - getAdminLink( 'admin.php?page=testpage' ) - ) - ).toBe( 0 ); - } ); - - it( 'should return match count for a custom match expression', () => { - expect( - getMatchScore( - new URL( - getAdminLink( 'admin.php?page=different-page¶m1=a' ) - ), - getAdminLink( 'admin.php?page=testpage' ), - 'param1=a' - ) - ).toBe( 1 ); - } ); - - it( 'should return 0 for custom match expression that does not match', () => { - expect( - getMatchScore( - new URL( - getAdminLink( 'admin.php?page=different-page¶m1=b' ) - ), - getAdminLink( 'admin.php?page=testpage' ), - 'param1=a' - ) - ).toBe( 0 ); - } ); - - it( 'should return match count if params match but are out of order', () => { - expect( - getMatchScore( - new URL( getAdminLink( 'admin.php?param1=a&page=testpage' ) ), - getAdminLink( 'admin.php?page=testpage' ) - ) - ).toBe( 2 ); - } ); - - it( 'should return match count if multiple params match but are out of order', () => { - expect( - getMatchScore( - new URL( - getAdminLink( 'admin.php?param1=a&page=testpage¶m2=b' ) - ), - getAdminLink( 'admin.php?page=testpage¶m1=a' ) - ) - ).toBe( 3 ); - } ); -} ); - -describe( 'getFullUrl', () => { - beforeAll( () => { - delete window.location; - window.location = new URL( getAdminLink( '/' ) ); - } ); - - afterAll( () => { - window.location = originalLocation; - } ); - - it( 'should get the full admin URL from a path', () => { - expect( getFullUrl( 'admin.php?page=testpage' ) ).toBe( - getAdminLink( 'admin.php?page=testpage' ) - ); - } ); - - it( 'should return the same URL from an already complete URL', () => { - expect( getFullUrl( getAdminLink( 'admin.php?page=testpage' ) ) ).toBe( - getAdminLink( 'admin.php?page=testpage' ) - ); - } ); -} ); - -describe( 'sortMenuItems', () => { - it( 'should return an array of items sorted by the order property', () => { - const menuItems = [ - { id: 'second', title: 'second', order: 2 }, - { id: 'first', title: 'three', order: 1 }, - { id: 'third', title: 'four', order: 3 }, - ]; - - const sortedItems = sortMenuItems( menuItems ); - - expect( sortedItems[ 0 ].id ).toBe( 'first' ); - expect( sortedItems[ 1 ].id ).toBe( 'second' ); - expect( sortedItems[ 2 ].id ).toBe( 'third' ); - } ); - - it( 'should sort items alphabetically if order is the same', () => { - const menuItems = [ - { id: 'third', title: 'z', order: 2 }, - { id: 'first', title: 'first', order: 1 }, - { id: 'second', title: 'a', order: 2 }, - ]; - - const sortedItems = sortMenuItems( menuItems ); - - expect( sortedItems[ 0 ].id ).toBe( 'first' ); - expect( sortedItems[ 1 ].id ).toBe( 'second' ); - expect( sortedItems[ 2 ].id ).toBe( 'third' ); - } ); -} ); - -describe( 'getMappedItemsCategories', () => { - it( 'should get the default category when none are provided', () => { - const menuItems = [ - { - id: 'child-one', - title: 'child-one', - isCategory: false, - parent: 'woocommerce', - menuId: 'plugins', - }, - ]; - const { categories, items } = getMappedItemsCategories( menuItems ); - - expect( items.woocommerce ).toBeDefined(); - expect( items.woocommerce.plugins ).toBeDefined(); - expect( items.woocommerce.plugins.length ).toBe( 1 ); - - expect( Object.keys( categories ).length ).toBe( 1 ); - expect( categories.woocommerce ).toBeDefined(); - } ); - - it( 'should get a map of all items and categories', () => { - const menuItems = [ - { - id: 'child-one', - title: 'child-one', - isCategory: false, - parent: 'parent', - menuId: 'plugins', - }, - { - id: 'child-two', - title: 'child-two', - isCategory: false, - parent: 'parent', - menuId: 'plugins', - }, - { - id: 'parent', - title: 'parent', - isCategory: true, - parent: 'woocommerce', - menuId: 'plugins', - }, - ]; - const { categories, items } = getMappedItemsCategories( menuItems ); - - expect( items.woocommerce ).toBeDefined(); - expect( items.woocommerce.plugins ).toBeDefined(); - expect( items.woocommerce.plugins.length ).toBe( 1 ); - - expect( items.parent ).toBeDefined(); - expect( items.parent.plugins ).toBeDefined(); - expect( items.parent.plugins.length ).toBe( 2 ); - - expect( Object.keys( categories ).length ).toBe( 2 ); - expect( categories.parent ).toBeDefined(); - expect( categories.woocommerce ).toBeDefined(); - } ); - - it( 'should handle multiple depths', () => { - const menuItems = [ - { - id: 'grand-child', - title: 'grand-child', - isCategory: false, - parent: 'child', - menuId: 'plugins', - }, - { - id: 'child', - title: 'child', - isCategory: true, - parent: 'grand-parent', - menuId: 'plugins', - }, - { - id: 'grand-parent', - title: 'grand-parent', - isCategory: true, - parent: 'woocommerce', - menuId: 'plugins', - }, - ]; - const { categories, items } = getMappedItemsCategories( menuItems ); - - expect( items[ 'grand-parent' ] ).toBeDefined(); - expect( items[ 'grand-parent' ] ).toBeDefined(); - expect( items[ 'grand-parent' ].plugins.length ).toBe( 1 ); - - expect( items.child ).toBeDefined(); - expect( items.child.plugins.length ).toBe( 1 ); - - expect( items[ 'grand-child' ] ).not.toBeDefined(); - - expect( Object.keys( categories ).length ).toBe( 3 ); - } ); - - it( 'should group by menuId', () => { - const menuItems = [ - { - id: 'parent', - title: 'parent', - isCategory: true, - parent: 'woocommerce', - menuId: 'primary', - }, - { - id: 'primary-one', - title: 'primary-one', - isCategory: false, - parent: 'parent', - menuId: 'primary', - }, - { - id: 'primary-two', - title: 'primary-two', - isCategory: false, - parent: 'parent', - menuId: 'primary', - }, - ]; - const { items } = getMappedItemsCategories( menuItems ); - - expect( items.parent ).toBeDefined(); - expect( items.parent.primary ).toBeDefined(); - expect( items.parent.primary.length ).toBe( 2 ); - } ); - - it( 'should group children only if their menuId matches parent', () => { - const menuItems = [ - { - id: 'plugin-one', - title: 'plugin-one', - isCategory: false, - parent: 'parent', - menuId: 'plugins', - }, - { - id: 'plugin-two', - title: 'plugin-two', - isCategory: false, - parent: 'parent', - menuId: 'plugins', - }, - { - id: 'parent', - title: 'parent', - isCategory: true, - parent: 'woocommerce', - menuId: 'plugins', - }, - { - id: 'primary-one', - title: 'primary-one', - isCategory: false, - parent: 'parent', - menuId: 'primary', - }, - { - id: 'primary-two', - title: 'primary-two', - isCategory: false, - parent: 'parent', - menuId: 'primary', - }, - ]; - const { items } = getMappedItemsCategories( menuItems ); - - expect( items.parent ).toBeDefined(); - expect( items.parent.plugins ).toBeDefined(); - expect( items.parent.plugins.length ).toBe( 2 ); - - expect( items.primary ).not.toBeDefined(); - } ); - - it( 'should ignore bad menu IDs', () => { - const menuItems = [ - { - id: 'parent', - title: 'parent', - isCategory: false, - parent: 'woocommerce', - menuId: 'badId', - }, - { - id: 'primary-one', - title: 'primary-one', - isCategory: false, - parent: 'woocommerce', - menuId: 'primary', - }, - { - id: 'primary-two', - title: 'primary-two', - isCategory: false, - parent: 'woocommerce', - menuId: 'primary', - }, - ]; - const { categories, items } = getMappedItemsCategories( menuItems ); - - expect( items.woocommerce ).toBeDefined(); - expect( items.woocommerce.primary ).toBeDefined(); - expect( items.woocommerce.primary.length ).toBe( 2 ); - - expect( items.woocommerce ).toBeDefined(); - expect( items.woocommerce.badId ).not.toBeDefined(); - - expect( Object.keys( categories ).length ).toBe( 1 ); - } ); -} ); diff --git a/plugins/woocommerce-admin/client/navigation/utils.ts b/plugins/woocommerce-admin/client/navigation/utils.ts deleted file mode 100644 index 04c1bc4b1ac..00000000000 --- a/plugins/woocommerce-admin/client/navigation/utils.ts +++ /dev/null @@ -1,259 +0,0 @@ -/** - * External dependencies - */ -import { getAdminLink } from '@woocommerce/settings'; - -type MenuId = 'primary' | 'favorites' | 'plugins' | 'secondary'; - -interface Item { - id: string; - matchExpression: string; - url: string; - order: number; - title: string; - parent: string; - menuId: MenuId; - capability: string; - isCategory: boolean; -} - -interface Category { - id: string; - isCategory: boolean; - menuId: MenuId; - migrate: boolean; - order: number; - parent: string; - title: string; - primary?: Item[]; - favorites?: Item[]; - plugins?: Item[]; - secondary?: Item[]; -} - -/** - * Get the full URL if a relative path is passed. - */ -export const getFullUrl = ( url: string ): string => { - if ( url.indexOf( 'http' ) === 0 ) { - return url; - } - - return getAdminLink( url ); -}; - -/** - * Get a default regex expression to match the path and provided params. - */ -export const getDefaultMatchExpression = ( url: string ): string => { - const escapedUrl = url.replace( /[-\/\\^$*+?.()|[\]{}]/gi, '\\$&' ); - const [ path, args, hash ] = escapedUrl.split( /\\\?|#/ ); - const hashExpression = hash ? `(.*#${ hash }$)` : ''; - const argsExpression = args - ? args.split( '&' ).reduce( ( acc, param ) => { - return `${ acc }(?=.*[?|&]${ param }(&|$|#))`; - }, '' ) - : ''; - return '^' + path + argsExpression + hashExpression; -}; - -/** - * Get a match score for a menu item given a location. - */ -export const getMatchScore = ( - location: Location, - itemUrl: string, - itemExpression: string | null = null -): number => { - if ( ! itemUrl ) { - return 0; - } - - const fullUrl = getFullUrl( itemUrl ); - const { href } = location; - - // Return highest possible score for exact match. - if ( fullUrl === href ) { - return Number.MAX_SAFE_INTEGER; - } - - const defaultExpression = getDefaultMatchExpression( fullUrl ); - const regexp = new RegExp( itemExpression || defaultExpression, 'i' ); - return ( decodeURIComponent( href ).match( regexp ) || [] ).length; -}; - -interface wcNavigation { - menuItems: Item[]; - rootBackLabel: string; - rootBackUrl: string; - historyPatched: boolean; -} - -declare global { - interface Window { - wcNavigation: wcNavigation; - } -} - -interface wcNavigation { - menuItems: Item[]; - rootBackLabel: string; - rootBackUrl: string; - historyPatched: boolean; -} - -declare global { - interface Window { - wcNavigation: wcNavigation; - } -} - -/** - * Get the closest matching item. - * - * @param {Array} items An array of items to match against. - */ -export const getMatchingItem = ( items: Item[] ): Item | null => { - let matchedItem = null; - let highestMatchScore = 0; - - items.forEach( ( item ) => { - const score = getMatchScore( - window.location, - item.url, - item.matchExpression - ); - if ( score > 0 && score >= highestMatchScore ) { - highestMatchScore = score; - matchedItem = item; - } - } ); - - return matchedItem || null; -}; - -/** - * Available menu IDs. - */ -export const menuIds: MenuId[] = [ - 'primary', - 'favorites', - 'plugins', - 'secondary', -]; - -interface Category { - id: string; - isCategory: boolean; - menuId: MenuId; - migrate: boolean; - order: number; - parent: string; - title: string; - primary?: Item[]; - favorites?: Item[]; - plugins?: Item[]; - secondary?: Item[]; -} - -/** - * Default categories for the menu. - */ -export const defaultCategories: { - [ key: string ]: Category; -} = { - woocommerce: { - id: 'woocommerce', - isCategory: true, - menuId: 'primary', - migrate: true, - order: 10, - parent: '', - title: 'WooCommerce', - }, -}; - -/** - * Sort an array of menu items by their order property. - * - * @param {Array} menuItems Array of menu items. - * @return {Array} Sorted menu items. - */ -export const sortMenuItems = ( menuItems: Item[] ): Item[] => { - return menuItems.sort( ( a, b ) => { - if ( a.order === b.order ) { - return a.title.localeCompare( b.title ); - } - - return a.order - b.order; - } ); -}; - -/** - * Get a flat tree structure of all Categories and their children grouped by menuId - * - * @param {Array} menuItems Array of menu items. - * @param {Function} currentUserCan Callback method passed the capability to determine if a menu item is visible. - * @return {Object} Mapped menu items and categories. - */ -export const getMappedItemsCategories = ( - menuItems: Item[], - currentUserCan: ( capability: string ) => boolean -): { - items: Record< string, Category | Record< string, Item[] > >; - categories: Record< string, Category | Item >; -} => { - const categories: { - [ key: string ]: Category | Item; - } = { ...defaultCategories }; - - const items = sortMenuItems( menuItems ).reduce( - ( - acc: { - [ key: string ]: Category | { [ key: string ]: Item[] }; - }, - item: Item - ) => { - // Set up the category if it doesn't yet exist. - if ( ! acc[ item.parent ] ) { - acc[ item.parent ] = {}; - menuIds.forEach( ( menuId ) => { - acc[ item.parent ][ menuId ] = []; - } ); - } - - // Incorrect menu ID. - if ( ! acc[ item.parent ][ item.menuId ] ) { - return acc; - } - - // User does not have permission to view this item. - if ( - currentUserCan && - item.capability && - ! currentUserCan( item.capability ) - ) { - return acc; - } - - // Add categories. - if ( item.isCategory ) { - categories[ item.id ] = item; - } - - const menuIdArray = acc[ item.parent ][ item.menuId ]; - - if ( menuIdArray ) { - menuIdArray.push( item ); - } - - return acc; - }, - {} - ); - - return { - items, - categories, - }; -}; diff --git a/plugins/woocommerce-admin/client/wp-admin-scripts/navigation-opt-out/container.js b/plugins/woocommerce-admin/client/wp-admin-scripts/navigation-opt-out/container.js deleted file mode 100644 index 14b429f0354..00000000000 --- a/plugins/woocommerce-admin/client/wp-admin-scripts/navigation-opt-out/container.js +++ /dev/null @@ -1,63 +0,0 @@ -/** - * External dependencies - */ -import { __ } from '@wordpress/i18n'; -import { Component } from '@wordpress/element'; -import { Button, Modal } from '@wordpress/components'; - -export class NavigationOptOutContainer extends Component { - constructor( props ) { - super( props ); - this.state = { - isModalOpen: true, - }; - } - - render() { - const { isModalOpen } = this.state; - if ( ! isModalOpen ) { - return null; - } - - if ( ! window.surveyData || ! window.surveyData.url ) { - return null; - } - - return ( - this.setState( { isModalOpen: false } ) } - className="woocommerce-navigation-opt-out-modal" - > -

- { __( - "Take this 2-minute survey to share why you're opting out of the new navigation", - 'woocommerce' - ) } -

- -
- - - -
-
- ); - } -} diff --git a/plugins/woocommerce-admin/client/wp-admin-scripts/navigation-opt-out/index.js b/plugins/woocommerce-admin/client/wp-admin-scripts/navigation-opt-out/index.js deleted file mode 100644 index 9f52860e34a..00000000000 --- a/plugins/woocommerce-admin/client/wp-admin-scripts/navigation-opt-out/index.js +++ /dev/null @@ -1,18 +0,0 @@ -/** - * External dependencies - */ -import { render } from '@wordpress/element'; - -/** - * Internal dependencies - */ -import { NavigationOptOutContainer } from './container'; -import './style.scss'; - -const navigationOptOutRoot = document.createElement( 'div' ); -navigationOptOutRoot.setAttribute( 'id', 'navigation-opt-out-root' ); - -render( - , - document.body.appendChild( navigationOptOutRoot ) -); diff --git a/plugins/woocommerce-admin/client/wp-admin-scripts/navigation-opt-out/style.scss b/plugins/woocommerce-admin/client/wp-admin-scripts/navigation-opt-out/style.scss deleted file mode 100644 index 5797952fab1..00000000000 --- a/plugins/woocommerce-admin/client/wp-admin-scripts/navigation-opt-out/style.scss +++ /dev/null @@ -1,8 +0,0 @@ -.woocommerce-navigation-opt-out-modal__actions { - text-align: right; - margin-top: $gap-large; - - .components-button.is-primary { - margin-left: $gap; - } -} diff --git a/plugins/woocommerce-admin/docs/examples/extensions/add-navigation-items/js/index.js b/plugins/woocommerce-admin/docs/examples/extensions/add-navigation-items/js/index.js deleted file mode 100644 index 561e2ab7379..00000000000 --- a/plugins/woocommerce-admin/docs/examples/extensions/add-navigation-items/js/index.js +++ /dev/null @@ -1,26 +0,0 @@ -/** - * External dependencies - */ -import { __ } from '@wordpress/i18n'; -import { Button } from '@wordpress/components'; -import { registerPlugin } from '@wordpress/plugins'; -import { WooNavigationItem } from '@woocommerce/navigation'; - -const MyPlugin = () => { - const handleClick = () => { - alert( 'Menu item clicked!' ); - }; - - return ( - - - - ); -}; - -registerPlugin( 'my-plugin', { - render: MyPlugin, - scope: 'woocommerce-navigation', -} ); diff --git a/plugins/woocommerce-admin/docs/examples/extensions/add-navigation-items/woocommerce-admin-add-navigation-items-example.php b/plugins/woocommerce-admin/docs/examples/extensions/add-navigation-items/woocommerce-admin-add-navigation-items-example.php deleted file mode 100644 index 4b43e00f21d..00000000000 --- a/plugins/woocommerce-admin/docs/examples/extensions/add-navigation-items/woocommerce-admin-add-navigation-items-example.php +++ /dev/null @@ -1,77 +0,0 @@ - 'example-plugin', - 'title' => 'Example Plugin', - 'capability' => 'view_woocommerce_reports', - 'url' => 'https://www.google.com', - ) - ); - - \Automattic\WooCommerce\Admin\Features\Navigation\Menu::add_plugin_category( - array( - 'id' => 'example-category', - 'title' => 'Example Category', - 'capability' => 'view_woocommerce_reports', - ) - ); - - \Automattic\WooCommerce\Admin\Features\Navigation\Menu::add_plugin_item( - array( - 'id' => 'example-category-child-1', - 'parent' => 'example-category', - 'title' => 'Sub Menu Child 1', - 'capability' => 'view_woocommerce_reports', - 'url' => 'https://www.google.com', - ) - ); - - \Automattic\WooCommerce\Admin\Features\Navigation\Menu::add_plugin_item( - array( - 'id' => 'example-category-child-2', - 'parent' => 'example-category', - 'title' => 'Sub Menu Child 2', - 'capability' => 'view_woocommerce_reports', - 'url' => 'https://www.google.com', - ) - ); -} -add_filter( 'admin_menu', 'add_navigation_items_register_items' ); diff --git a/plugins/woocommerce-admin/docs/features/navigation.md b/plugins/woocommerce-admin/docs/features/navigation.md deleted file mode 100644 index 26592cd2442..00000000000 --- a/plugins/woocommerce-admin/docs/features/navigation.md +++ /dev/null @@ -1,125 +0,0 @@ -# WooCommerce Navigation - -The WooCommerce Navigation feature is a navigational project designed to create a more intuitive and functional WooCommerce specific navigation. - -This API will allow you to add in your own items to the navigation and register pages with the new navigation screens. - -### Getting started - -This feature is hidden behind a feature flag and can be turned on or off by visiting WooCommerce -> Settngs -> Advanced -> Features and checking the box next to the `Navigation` option. It can also by controlled programmatically by setting the option `woocommerce_navigation_enable` to `yes` or `no`. - -The fastest way to get started is by creating an example plugin from WooCommerce Admin. Enter the following command: - -`WC_EXT=add-navigation-items pnpm example --filter=@woocommerce/admin-library` - -This will create a new plugin that covers various features of the navigation and helps to register some initial items and categories within the new navigation menu. After running the command above, you can make edits directly to the files at `docs/examples/extensions/add-navigation-items` and they will be built and copied to your `wp-content/add-navigation-items` folder on save. - -If you need to enable the WP Toolbar for debugging purposes in the new navigation, you can add the following filter to do so: - -`add_filter( 'woocommerce_navigation_wp_toolbar_disabled', '__return_false' );` - -### Adding a menu category - -Categories in the new navigation are menu items that house child menu items. - -Clicking on a category will not navigate to a new page, but instead open the child menu. Note that categories without menu items will not be shown in the menu. - -* `id` - (string) The unique ID of the menu item. Required. -* `title` - (string) Title of the menu item. Required. -* `parent` - (string) Parent menu item ID. -* `capability` - (string) Capability to view this menu item. - -```php -\Automattic\WooCommerce\Admin\Features\Navigation\Menu::add_plugin_category( - array( - 'id' => 'example-category', - 'title' => 'Example Category', - ) -); -``` - -Categories can also contain more categories by specifying the `parent` property for the child category. There is no limit on the level of nesting. - -```php -\Automattic\WooCommerce\Admin\Features\Navigation\Menu::add_plugin_category( - array( - 'id' => 'example-nested-category', - 'parent' => 'example-category', - 'title' => 'Example Nested Category', - ) -); -``` - -### Adding a menu item - -Adding an item, much like a category, can be added directly to the menu or to an existing category. Typically this will create a link to the specified URL or callback unless overridden by JavaScript using the slot/fill approach described below. - -* `id` - (string) The unique ID of the menu item. Required. -* `title` - (string) Title of the menu item. Required. -* `parent` - (string) Parent menu item ID. -* `capability` - (string) Capability to view this menu item. -* `url` - (string) URL or callback to be used. Required. -* `migrate` - (bool) Whether or not to hide the item in the wp admin menu. -* `matchExpression` - (string) An optional regex string to compare against the current location and mark the item active. - -```php -\Automattic\WooCommerce\Admin\Features\Navigation\Menu::add_plugin_item( - array( - 'id' => 'example-plugin', - 'title' => 'Example Plugin', - 'capability' => 'view_woocommerce_reports', - 'url' => 'https://www.google.com', - ) -); -``` - -### Registering plugin screens - -In order to show the new navigation in place of the traditional WordPress menu on a given page, the screen ID must be registered to identify a page as supporting the new WooCommerce navigation. - -When adding items, the navigation will automatically add support for the screen via the URL or callback provided with an item. However, custom post types and taxonomies need to be registered with the navigation to work on the custom post type page. - - -```php -\Automattic\WooCommerce\Admin\Features\Navigation\Screen::register_post_type( 'my-custom-post-type' ); -\Automattic\WooCommerce\Admin\Features\Navigation\Screen::register_taxonomy( 'my-custom-taxonomy' ); -``` - -You can also manually add a screen without registering an item. - -```php -\Automattic\WooCommerce\Admin\Features\Navigation\Screen::add_screen( 'my-plugin-page' ); -``` - -### Slot/fill items - -Using slot fill we can update items on the front-end of the site using JavaScript. This is useful for modern JavaScript routing, more intricate interactions with menu items, or updating URLs and hyperlink text without reloading the page. - -In order to use slot fill, you can import the `WooNavigationItem` component from `@woocommerce/navigation` and match the `item` prop with the ID of the item you'd like to modify the behavior of. - - -```js -import { __ } from '@wordpress/i18n'; -import { Button } from '@wordpress/components'; -import { registerPlugin } from "@wordpress/plugins"; -import { useHistory } from "react-router-dom"; -import { WooNavigationItem } from "@woocommerce/navigation"; - -const MyPlugin = () => { - const history = useHistory(); - - const handleClick = () => { - history.push( '/my-plugin-path' ); - } - - return ( - - - - ); -}; - -registerPlugin( 'my-plugin', { render: MyPlugin, scope: 'woocommerce-navigation' } ); -``` diff --git a/plugins/woocommerce-admin/webpack.config.js b/plugins/woocommerce-admin/webpack.config.js index 7f3fa90597e..cadd1251831 100644 --- a/plugins/woocommerce-admin/webpack.config.js +++ b/plugins/woocommerce-admin/webpack.config.js @@ -48,7 +48,6 @@ const wcAdminPackages = [ // See ./client/wp-admin-scripts/README.md for more details const wpAdminScripts = [ 'marketing-coupons', - 'navigation-opt-out', 'onboarding-homepage-notice', 'onboarding-product-notice', 'onboarding-product-import-notice', diff --git a/plugins/woocommerce/changelog/50190-add-navigation-deprecation b/plugins/woocommerce/changelog/50190-add-navigation-deprecation new file mode 100644 index 00000000000..1f80f12d42d --- /dev/null +++ b/plugins/woocommerce/changelog/50190-add-navigation-deprecation @@ -0,0 +1,4 @@ +Significance: minor +Type: update + +Remove WooCommerce Navigation client side feature and deprecate PHP classes. \ No newline at end of file diff --git a/plugins/woocommerce/src/Admin/Features/Navigation/CoreMenu.php b/plugins/woocommerce/src/Admin/Features/Navigation/CoreMenu.php index 5f18b2355a0..23df1306948 100644 --- a/plugins/woocommerce/src/Admin/Features/Navigation/CoreMenu.php +++ b/plugins/woocommerce/src/Admin/Features/Navigation/CoreMenu.php @@ -2,6 +2,7 @@ /** * WooCommerce Navigation Core Menu * + * @deprecated 9.3.0 Navigation is no longer a feature and its classes will be removed in WooCommerce 9.4. * @package Woocommerce Admin */ diff --git a/plugins/woocommerce/src/Admin/Features/Navigation/Favorites.php b/plugins/woocommerce/src/Admin/Features/Navigation/Favorites.php index 8c25424d302..e842bb713e2 100644 --- a/plugins/woocommerce/src/Admin/Features/Navigation/Favorites.php +++ b/plugins/woocommerce/src/Admin/Features/Navigation/Favorites.php @@ -2,6 +2,7 @@ /** * WooCommerce Navigation Favorite * + * @deprecated 9.3.0 Navigation is no longer a feature and its classes will be removed in WooCommerce 9.4. * @package Woocommerce Navigation */ diff --git a/plugins/woocommerce/src/Admin/Features/Navigation/Init.php b/plugins/woocommerce/src/Admin/Features/Navigation/Init.php index 2d0cd85142e..4ce972e6fe7 100644 --- a/plugins/woocommerce/src/Admin/Features/Navigation/Init.php +++ b/plugins/woocommerce/src/Admin/Features/Navigation/Init.php @@ -2,17 +2,17 @@ /** * Navigation Experience * + * @deprecated 9.3.0 Navigation is no longer a feature and its classes will be removed in WooCommerce 9.4. * @package Woocommerce Admin */ namespace Automattic\WooCommerce\Admin\Features\Navigation; -use Automattic\WooCommerce\Internal\Admin\Survey; use Automattic\WooCommerce\Admin\Features\Features; use Automattic\WooCommerce\Admin\Features\Navigation\Screen; use Automattic\WooCommerce\Admin\Features\Navigation\Menu; use Automattic\WooCommerce\Admin\Features\Navigation\CoreMenu; -use Automattic\WooCommerce\Internal\Admin\WCAdminAssets; +use WC_Tracks; /** * Contains logic for the Navigation @@ -23,115 +23,27 @@ class Init { */ const TOGGLE_OPTION_NAME = 'woocommerce_navigation_enabled'; - /** - * Determines if the feature has been toggled on or off. - * - * @var boolean - */ - protected static $is_updated = false; - /** * Hook into WooCommerce. */ public function __construct() { - add_action( 'update_option_' . self::TOGGLE_OPTION_NAME, array( $this, 'reload_page_on_toggle' ), 10, 2 ); - add_action( 'woocommerce_settings_saved', array( $this, 'maybe_reload_page' ) ); - add_action( 'admin_enqueue_scripts', array( $this, 'maybe_enqueue_opt_out_scripts' ) ); - if ( Features::is_enabled( 'navigation' ) ) { - Menu::instance()->init(); - CoreMenu::instance()->init(); - Screen::instance()->init(); + // Disable the option to turn off the feature. + update_option( self::TOGGLE_OPTION_NAME, 'no' ); + + if ( class_exists( 'WC_Tracks' ) ) { + WC_Tracks::record_event( 'deprecated_navigation_in_use' ); + } } } /** - * Add the feature toggle to the features settings. + * Create a deprecation notice. * - * @deprecated 7.0 The WooCommerce Admin features are now handled by the WooCommerce features engine (see the FeaturesController class). - * - * @param array $features Feature sections. - * @return array + * @param string $fcn The function that is deprecated. */ - public static function add_feature_toggle( $features ) { - return $features; - } - - /** - * Determine if sufficient versions are present to support Navigation feature - */ - public function is_nav_compatible() { - include_once ABSPATH . 'wp-admin/includes/plugin.php'; - - $gutenberg_minimum_version = '9.0.0'; // https://github.com/WordPress/gutenberg/releases/tag/v9.0.0. - $wp_minimum_version = '5.6'; - $has_gutenberg = is_plugin_active( 'gutenberg/gutenberg.php' ); - $gutenberg_version = $has_gutenberg ? get_plugin_data( WP_PLUGIN_DIR . '/gutenberg/gutenberg.php' )['Version'] : false; - - if ( $gutenberg_version && version_compare( $gutenberg_version, $gutenberg_minimum_version, '>=' ) ) { - return true; - } - - // Get unmodified $wp_version. - include ABSPATH . WPINC . '/version.php'; - - // Strip '-src' from the version string. Messes up version_compare(). - $wp_version = str_replace( '-src', '', $wp_version ); - - if ( version_compare( $wp_version, $wp_minimum_version, '>=' ) ) { - return true; - } - - return false; - } - - /** - * Reloads the page when the option is toggled to make sure all nav features are loaded. - * - * @param string $old_value Old value. - * @param string $value New value. - */ - public static function reload_page_on_toggle( $old_value, $value ) { - if ( $old_value === $value ) { - return; - } - - if ( 'yes' !== $value ) { - update_option( 'woocommerce_navigation_show_opt_out', 'yes' ); - } - - self::$is_updated = true; - } - - /** - * Reload the page if the setting has been updated. - */ - public static function maybe_reload_page() { - if ( ! isset( $_SERVER['REQUEST_URI'] ) || ! self::$is_updated ) { - return; - } - - wp_safe_redirect( wp_unslash( $_SERVER['REQUEST_URI'] ) ); - exit(); - } - - /** - * Enqueue the opt out scripts. - */ - public function maybe_enqueue_opt_out_scripts() { - if ( get_option( 'woocommerce_navigation_show_opt_out', 'no' ) !== 'yes' ) { - return; - } - - WCAdminAssets::register_style( 'navigation-opt-out', 'style', array( 'wp-components' ) ); - WCAdminAssets::register_script( 'wp-admin-scripts', 'navigation-opt-out', true ); - wp_localize_script( - 'wc-admin-navigation-opt-out', - 'surveyData', - array( - 'url' => Survey::get_url( '/new-navigation-opt-out' ), - ) - ); - delete_option( 'woocommerce_navigation_show_opt_out' ); + public static function deprecation_notice( $fcn ) { + // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log + error_log( 'Automattic\WooCommerce\Admin\Features\Navigation\\' . $fcn . ' is deprecated since 9.3 with no alternative. Navigation classes will be removed in WooCommerce 9.4' ); } } diff --git a/plugins/woocommerce/src/Admin/Features/Navigation/Menu.php b/plugins/woocommerce/src/Admin/Features/Navigation/Menu.php index 486b34c35e2..42afe8892c5 100644 --- a/plugins/woocommerce/src/Admin/Features/Navigation/Menu.php +++ b/plugins/woocommerce/src/Admin/Features/Navigation/Menu.php @@ -2,6 +2,7 @@ /** * WooCommerce Navigation Menu * + * @deprecated 9.3.0 Navigation is no longer a feature and its classes will be removed in WooCommerce 9.4. * @package Woocommerce Navigation */ @@ -10,6 +11,7 @@ namespace Automattic\WooCommerce\Admin\Features\Navigation; use Automattic\WooCommerce\Admin\Features\Navigation\Favorites; use Automattic\WooCommerce\Admin\Features\Navigation\Screen; use Automattic\WooCommerce\Admin\Features\Navigation\CoreMenu; +use Automattic\WooCommerce\Admin\Features\Navigation\Init; /** * Contains logic for the WooCommerce Navigation menu. @@ -95,172 +97,33 @@ class Menu { /** * Init. + * + * @internal */ - public function init() { - add_action( 'admin_menu', array( $this, 'add_core_items' ), 100 ); - add_filter( 'admin_enqueue_scripts', array( $this, 'enqueue_data' ), 20 ); - - add_filter( 'admin_menu', array( $this, 'migrate_core_child_items' ), PHP_INT_MAX - 1 ); - add_filter( 'admin_menu', array( $this, 'migrate_menu_items' ), PHP_INT_MAX - 2 ); - } + final public function init() {} /** * Convert a WordPress menu callback to a URL. - * - * @param string $callback Menu callback. - * @return string */ - public static function get_callback_url( $callback ) { - // Return the full URL. - if ( strpos( $callback, 'http' ) === 0 ) { - return $callback; - } - - $pos = strpos( $callback, '?' ); - $file = $pos > 0 ? substr( $callback, 0, $pos ) : $callback; - if ( file_exists( ABSPATH . "/wp-admin/$file" ) ) { - return $callback; - } - return 'admin.php?page=' . $callback; - } + public static function get_callback_url() {} /** * Get the parent key if one exists. - * - * @param string $callback Callback or URL. - * @return string|null */ - public static function get_parent_key( $callback ) { - global $submenu; - - if ( ! $submenu ) { - return null; - } - - // This is already a parent item. - if ( isset( $submenu[ $callback ] ) ) { - return null; - } - - foreach ( $submenu as $key => $menu ) { - foreach ( $menu as $item ) { - if ( $item[ self::CALLBACK ] === $callback ) { - return $key; - } - } - } - - return null; - } + public static function get_parent_key() {} /** * Adds a top level menu item to the navigation. - * - * @param array $args Array containing the necessary arguments. - * $args = array( - * 'id' => (string) The unique ID of the menu item. Required. - * 'title' => (string) Title of the menu item. Required. - * 'url' => (string) URL or callback to be used. Required. - * 'order' => (int) Menu item order. - * 'migrate' => (bool) Whether or not to hide the item in the wp admin menu. - * 'menuId' => (string) The ID of the menu to add the category to. - * ). */ - private static function add_category( $args ) { - if ( ! isset( $args['id'] ) || isset( self::$menu_items[ $args['id'] ] ) ) { - return; - } - - $defaults = array( - 'id' => '', - 'title' => '', - 'order' => 100, - 'migrate' => true, - 'menuId' => 'primary', - 'isCategory' => true, - ); - $menu_item = wp_parse_args( $args, $defaults ); - $menu_item['title'] = wp_strip_all_tags( wp_specialchars_decode( $menu_item['title'] ) ); - unset( $menu_item['url'] ); - unset( $menu_item['capability'] ); - - if ( ! isset( $menu_item['parent'] ) ) { - $menu_item['parent'] = 'woocommerce'; - $menu_item['backButtonLabel'] = __( - 'WooCommerce Home', - 'woocommerce' - ); - } - - self::$menu_items[ $menu_item['id'] ] = $menu_item; - self::$categories[ $menu_item['id'] ] = array(); - self::$categories[ $menu_item['parent'] ][] = $menu_item['id']; - - if ( isset( $args['url'] ) ) { - self::$callbacks[ $args['url'] ] = $menu_item['migrate']; - } + private static function add_category() { + Init::deprecation_notice( 'Menu::add_category' ); } /** * Adds a child menu item to the navigation. - * - * @param array $args Array containing the necessary arguments. - * $args = array( - * 'id' => (string) The unique ID of the menu item. Required. - * 'title' => (string) Title of the menu item. Required. - * 'parent' => (string) Parent menu item ID. - * 'capability' => (string) Capability to view this menu item. - * 'url' => (string) URL or callback to be used. Required. - * 'order' => (int) Menu item order. - * 'migrate' => (bool) Whether or not to hide the item in the wp admin menu. - * 'menuId' => (string) The ID of the menu to add the item to. - * 'matchExpression' => (string) A regular expression used to identify if the menu item is active. - * ). */ - private static function add_item( $args ) { - if ( ! isset( $args['id'] ) ) { - return; - } - - if ( isset( self::$menu_items[ $args['id'] ] ) ) { - wc_doing_it_wrong( - __METHOD__, - sprintf( - /* translators: 1: Duplicate menu item path. */ - esc_html__( 'You have attempted to register a duplicate item with WooCommerce Navigation: %1$s', 'woocommerce' ), - '`' . $args['id'] . '`' - ), - '6.5.0' - ); - - return; - } - - $defaults = array( - 'id' => '', - 'title' => '', - 'capability' => 'manage_woocommerce', - 'url' => '', - 'order' => 100, - 'migrate' => true, - 'menuId' => 'primary', - ); - $menu_item = wp_parse_args( $args, $defaults ); - $menu_item['title'] = wp_strip_all_tags( wp_specialchars_decode( $menu_item['title'] ) ); - $menu_item['url'] = self::get_callback_url( $menu_item['url'] ); - - if ( ! isset( $menu_item['parent'] ) ) { - $menu_item['parent'] = 'woocommerce'; - } - - $menu_item['menuId'] = self::get_item_menu_id( $menu_item ); - - self::$menu_items[ $menu_item['id'] ] = $menu_item; - self::$categories[ $menu_item['parent'] ][] = $menu_item['id']; - - if ( isset( $args['url'] ) ) { - self::$callbacks[ $args['url'] ] = $menu_item['migrate']; - } + private static function add_item() { + Init::deprecation_notice( 'Menu::add_item' ); } /** @@ -287,112 +150,25 @@ class Menu { /** * Adds a plugin category. - * - * @param array $args Array containing the necessary arguments. - * $args = array( - * 'id' => (string) The unique ID of the menu item. Required. - * 'title' => (string) Title of the menu item. Required. - * 'url' => (string) URL or callback to be used. Required. - * 'migrate' => (bool) Whether or not to hide the item in the wp admin menu. - * 'order' => (int) Menu item order. - * ). */ - public static function add_plugin_category( $args ) { - $category_args = array_merge( - $args, - array( - 'menuId' => 'plugins', - ) - ); - - if ( ! isset( $category_args['parent'] ) ) { - unset( $category_args['order'] ); - } - - $menu_id = self::get_item_menu_id( $category_args ); - if ( ! in_array( $menu_id, array( 'plugins', 'favorites' ), true ) ) { - return; - } - - $category_args['menuId'] = $menu_id; - - self::add_category( $category_args ); + public static function add_plugin_category() { + Init::deprecation_notice( 'Menu::add_plugin_category' ); } /** * Adds a plugin item. - * - * @param array $args Array containing the necessary arguments. - * $args = array( - * 'id' => (string) The unique ID of the menu item. Required. - * 'title' => (string) Title of the menu item. Required. - * 'parent' => (string) Parent menu item ID. - * 'capability' => (string) Capability to view this menu item. - * 'url' => (string) URL or callback to be used. Required. - * 'migrate' => (bool) Whether or not to hide the item in the wp admin menu. - * 'order' => (int) Menu item order. - * 'matchExpression' => (string) A regular expression used to identify if the menu item is active. - * ). */ - public static function add_plugin_item( $args ) { - if ( ! isset( $args['parent'] ) ) { - unset( $args['order'] ); - } - - $item_args = array_merge( - $args, - array( - 'menuId' => 'plugins', - ) - ); - - $menu_id = self::get_item_menu_id( $item_args ); - - if ( 'plugins' !== $menu_id ) { - return; - } - - self::add_item( $item_args ); + public static function add_plugin_item() { + Init::deprecation_notice( 'Menu::add_plugin_item' ); } /** * Adds a plugin setting item. - * - * @param array $args Array containing the necessary arguments. - * $args = array( - * 'id' => (string) The unique ID of the menu item. Required. - * 'title' => (string) Title of the menu item. Required. - * 'capability' => (string) Capability to view this menu item. - * 'url' => (string) URL or callback to be used. Required. - * 'migrate' => (bool) Whether or not to hide the item in the wp admin menu. - * ). */ - public static function add_setting_item( $args ) { - unset( $args['order'] ); - - if ( isset( $args['parent'] ) || isset( $args['menuId'] ) ) { - error_log( // phpcs:ignore - sprintf( - /* translators: 1: Duplicate menu item path. */ - esc_html__( 'The item ID %1$s attempted to register using an invalid option. The arguments `menuId` and `parent` are not allowed for add_setting_item()', 'woocommerce' ), - '`' . $args['id'] . '`' - ) - ); - } - - $item_args = array_merge( - $args, - array( - 'menuId' => 'secondary', - 'parent' => 'woocommerce-settings', - ) - ); - - self::add_item( $item_args ); + public static function add_setting_item() { + Init::deprecation_notice( 'Menu::add_setting_item' ); } - - /** * Get menu item templates for a given post type. * diff --git a/plugins/woocommerce/src/Admin/Features/Navigation/Screen.php b/plugins/woocommerce/src/Admin/Features/Navigation/Screen.php index 7f54d110bd4..dfe6e60e12e 100644 --- a/plugins/woocommerce/src/Admin/Features/Navigation/Screen.php +++ b/plugins/woocommerce/src/Admin/Features/Navigation/Screen.php @@ -2,12 +2,14 @@ /** * WooCommerce Navigation Screen * + * @deprecated 9.3.0 Navigation is no longer a feature and its classes will be removed in WooCommerce 9.4. * @package Woocommerce Navigation */ namespace Automattic\WooCommerce\Admin\Features\Navigation; use Automattic\WooCommerce\Admin\Features\Navigation\Menu; +use Automattic\WooCommerce\Admin\Features\Navigation\Init; /** * Contains logic for the WooCommerce Navigation menu. @@ -85,6 +87,8 @@ class Screen { * @return bool */ public static function is_woocommerce_page() { + Init::deprecation_notice( 'Screen::is_woocommerce_page' ); + global $pagenow; // Get taxonomy if on a taxonomy screen. @@ -218,23 +222,15 @@ class Screen { /** * Register post type for use in WooCommerce Navigation screens. - * - * @param string $post_type Post type to add. */ - public static function register_post_type( $post_type ) { - if ( ! in_array( $post_type, self::$post_types, true ) ) { - self::$post_types[] = $post_type; - } + public static function register_post_type() { + Init::deprecation_notice( 'Screen::register_post_type' ); } /** * Register taxonomy for use in WooCommerce Navigation screens. - * - * @param string $taxonomy Taxonomy to add. */ - public static function register_taxonomy( $taxonomy ) { - if ( ! in_array( $taxonomy, self::$taxonomies, true ) ) { - self::$taxonomies[] = $taxonomy; - } + public static function register_taxonomy() { + Init::deprecation_notice( 'Screen::register_taxonomy' ); } } diff --git a/plugins/woocommerce/src/Admin/PageController.php b/plugins/woocommerce/src/Admin/PageController.php index c44525cef5c..16d8b7125a2 100644 --- a/plugins/woocommerce/src/Admin/PageController.php +++ b/plugins/woocommerce/src/Admin/PageController.php @@ -574,6 +574,6 @@ class PageController { * TODO: See usage in `admin.php`. This needs refactored and implemented properly in core. */ public static function is_embed_page() { - return wc_admin_is_connected_page() || ( ! self::is_admin_page() && class_exists( 'Automattic\WooCommerce\Admin\Features\Navigation\Screen' ) && Screen::is_woocommerce_page() ); + return wc_admin_is_connected_page(); } } diff --git a/plugins/woocommerce/src/Internal/Features/FeaturesController.php b/plugins/woocommerce/src/Internal/Features/FeaturesController.php index 9aec6dcaa11..e777fc63fb8 100644 --- a/plugins/woocommerce/src/Internal/Features/FeaturesController.php +++ b/plugins/woocommerce/src/Internal/Features/FeaturesController.php @@ -6,7 +6,6 @@ namespace Automattic\WooCommerce\Internal\Features; use Automattic\WooCommerce\Internal\Admin\Analytics; -use Automattic\WooCommerce\Admin\Features\Navigation\Init; use Automattic\WooCommerce\Internal\DataStores\Orders\CustomOrdersTableController; use Automattic\WooCommerce\Internal\Traits\AccessiblePrivateMethods; use Automattic\WooCommerce\Proxies\LegacyProxy; @@ -174,17 +173,6 @@ class FeaturesController { 'disable_ui' => false, 'is_legacy' => true, ), - 'new_navigation' => array( - 'name' => __( 'Navigation', 'woocommerce' ), - 'description' => __( - 'Add the new WooCommerce navigation experience to the dashboard', - 'woocommerce' - ), - 'option_key' => Init::TOGGLE_OPTION_NAME, - 'is_experimental' => false, - 'disable_ui' => false, - 'is_legacy' => true, - ), 'product_block_editor' => array( 'name' => __( 'New product editor', 'woocommerce' ), 'description' => __( 'Try the new product editor (Beta)', 'woocommerce' ), diff --git a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/navigation/class-wc-favorites.php b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/navigation/class-wc-favorites.php deleted file mode 100644 index b33427b814e..00000000000 --- a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/navigation/class-wc-favorites.php +++ /dev/null @@ -1,89 +0,0 @@ -instance = new Favorites(); - $this->user = $this->factory->user->create( - array( - 'role' => 'administrator', - ) - ); - } - - /** - * Test that favorites can be added. - */ - public function test_add_favorites() { - wp_set_current_user( $this->user ); - - $result = $this->instance->add_item( 'menu-item', get_current_user_id() ); - $this->assertTrue( $result ); - $result = $this->instance->add_item( 'menu-item2', get_current_user_id() ); - $this->assertTrue( $result ); - - $favorites = $this->instance->get_all( get_current_user_id() ); - $this->assertContains( 'menu-item', $favorites ); - $this->assertContains( 'menu-item2', $favorites ); - } - - /** - * Test that favorites can be removed. - */ - public function test_remove_favorites() { - wp_set_current_user( $this->user ); - - $result = $this->instance->add_item( 'item-to-remove', get_current_user_id() ); - $this->assertTrue( $result ); - - $favorites = $this->instance->get_all( get_current_user_id() ); - $this->assertContains( 'item-to-remove', $favorites ); - - $result = $this->instance->remove_item( 'item-to-remove', get_current_user_id() ); - $favorites = $this->instance->get_all( get_current_user_id() ); - $this->assertNotContains( 'item-to-remove', $favorites ); - } - - /** - * Test that existing favorites can not be added again. - */ - public function test_add_previously_added_favorite() { - wp_set_current_user( $this->user ); - - $result = $this->instance->add_item( 'duplicate-item', get_current_user_id() ); - $this->assertTrue( $result ); - - $result = $this->instance->add_item( 'duplicate-item', get_current_user_id() ); - $this->assertInstanceOf( 'WP_Error', $result ); - } - - /** - * Test removing a favorite that does not exist. - */ - public function test_remove_invalid_favorite() { - wp_set_current_user( $this->user ); - - $result = $this->instance->remove_item( 'does-not-exist', get_current_user_id() ); - $this->assertInstanceOf( 'WP_Error', $result ); - } -} diff --git a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/navigation/class-wc-menu.php b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/navigation/class-wc-menu.php deleted file mode 100644 index 7f19b62346a..00000000000 --- a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/navigation/class-wc-menu.php +++ /dev/null @@ -1,293 +0,0 @@ -instance = new Menu(); - - $this->user = $this->factory->user->create( - array( - 'role' => 'administrator', - ) - ); - wp_set_current_user( $this->user ); - } - - /** - * Test that the correct callback is returned given a string. - */ - public function test_get_callback_url() { - // Full URLs should return the same full URL. - $full_url = 'http://mycustomurl.com'; - $callback = $this->instance->get_callback_url( $full_url ); - $this->assertEquals( $full_url, $callback ); - - // Files that exist should return the same callback. - $callback = $this->instance->get_callback_url( 'edit.php' ); - $this->assertEquals( 'edit.php', $callback ); - $callback = $this->instance->get_callback_url( 'edit.php?custom_arg=1' ); - $this->assertEquals( 'edit.php?custom_arg=1', $callback ); - - // Custom callbacks should return the callback as an admin page. - $callback = $this->instance->get_callback_url( 'my-page' ); - $this->assertEquals( 'admin.php?page=my-page', $callback ); - } - - /** - * Test the ability to retrieve a parent key. - */ - public function test_get_parent_key() { - global $submenu; - $submenu['my-parent-page'] = array( // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited - array( - 'my-child-item', - 'manage_woocommerce', - 'my-child-item', - ), - ); - - // Items that are already parents should not return parent keys. - $parent_key = $this->instance->get_parent_key( 'my-parent-page' ); - $this->assertNull( $parent_key ); - - // Fake items should not return parent keys. - $parent_key = $this->instance->get_parent_key( 'not-a-page' ); - $this->assertNull( $parent_key ); - - // Children should return their parent's key. - $parent_key = $this->instance->get_parent_key( 'my-child-item' ); - $this->assertEquals( 'my-parent-page', $parent_key ); - } - - /** - * Test adding a menu item. - */ - public function test_add_plugin_items() { - $item = array( - 'id' => 'test-plugin-item', - 'title' => 'Test Plugin Item', - 'capability' => 'manage_woocommerce', - 'url' => 'my-test-page', - ); - $this->instance->add_plugin_item( $item ); - - $items = $this->instance->get_items(); - $this->assertEquals( $item['id'], $items['test-plugin-item']['id'] ); - $this->assertEquals( 'Test Plugin Item', $items['test-plugin-item']['title'] ); - } - - /** - * Test adding an existing menu ID. - */ - public function test_add_duplicate_plugin_items() { - $this->setExpectedIncorrectUsage( 'Automattic\WooCommerce\Admin\Features\Navigation\Menu::add_item' ); - - $item = array( - 'id' => 'test-duplicate-item', - 'title' => 'Test Duplicate Item', - 'capability' => 'manage_woocommerce', - 'url' => 'my-duplicate-page', - ); - $this->instance->add_plugin_item( $item ); - - // Test that the duplicate ID does not replace the item. - $item['title'] = 'Test Updated Title'; - $this->instance->add_plugin_item( $item ); - $items = $this->instance->get_items(); - $this->assertEquals( 'Test Duplicate Item', $items['test-duplicate-item']['title'] ); - } - - /** - * Test adding a plugin category. - */ - public function test_add_plugin_category() { - $this->instance->add_plugin_category( - array( - 'id' => 'test-plugin-category', - 'title' => 'Test Plugin Category', - 'capability' => 'manage_woocommerce', - ) - ); - - $this->instance->add_plugin_item( - array( - 'id' => 'test-plugin-child', - 'title' => 'Test Plugin Child', - 'parent' => 'test-plugin-category', - 'capability' => 'manage_woocommerce', - 'url' => 'my-test-child', - ) - ); - - $items = $this->instance->get_items(); - $this->assertEquals( 'test-plugin-category', $items['test-plugin-category']['id'] ); - $this->assertEquals( 'test-plugin-child', $items['test-plugin-child']['id'] ); - } - - /** - * Test that a plugin item's menu ID gets properly set. - */ - public function test_plugin_menus() { - $this->instance->add_plugin_item( - array( - 'id' => 'test-plugin-menu', - 'title' => 'Test Plugin Category', - 'capability' => 'manage_woocommerce', - ) - ); - - $items = $this->instance->get_items(); - $this->assertEquals( 'plugins', $items['test-plugin-menu']['menuId'] ); - - $this->instance->add_plugin_item( - array( - 'id' => 'test-plugin-bad-menu', - 'title' => 'Test Plugin Category', - 'capability' => 'manage_woocommerce', - 'menuId' => 'primary', - ) - ); - - $items = $this->instance->get_items(); - $this->assertEquals( 'plugins', $items['test-plugin-bad-menu']['menuId'] ); - } - - /** - * Test that menu mapping by category works as expected. - */ - public function test_get_mapped_menu_items() { - $this->instance->add_plugin_category( - array( - 'id' => 'test-mapped-category', - 'title' => 'Test Mapped Category', - 'capability' => 'manage_woocommerce', - ) - ); - - $this->instance->add_plugin_item( - array( - 'id' => 'test-mapped-item-c', - 'title' => 'Test Mapped Item C', - 'parent' => 'test-mapped-category', - 'capability' => 'manage_woocommerce', - 'order' => 2, - ) - ); - - $this->instance->add_plugin_item( - array( - 'id' => 'test-mapped-item-b', - 'title' => 'Test Mapped Item B', - 'parent' => 'test-mapped-category', - 'capability' => 'manage_woocommerce', - 'order' => 1, - ) - ); - - $this->instance->add_plugin_item( - array( - 'id' => 'test-mapped-item-a', - 'title' => 'Test Mapped Item A', - 'parent' => 'test-mapped-category', - 'capability' => 'manage_woocommerce', - 'order' => 1, - ) - ); - - $this->instance->add_plugin_item( - array( - 'id' => 'test-mapped-permission', - 'title' => 'Should not be included', - 'parent' => 'test-mapped-category', - 'capability' => 'no_permission', - ) - ); - - $map = $this->instance->get_mapped_menu_items(); - - $this->assertCount( count( $this->instance::MENU_IDS ), $map['test-mapped-category'] ); - foreach ( $this->instance::MENU_IDS as $menu_id ) { - $this->assertArrayHasKey( $menu_id, $map['test-mapped-category'] ); - } - $this->assertEquals( 'test-mapped-item-a', $map['test-mapped-category']['plugins'][0]['id'] ); - $this->assertEquals( 'test-mapped-item-b', $map['test-mapped-category']['plugins'][1]['id'] ); - $this->assertEquals( 'test-mapped-item-c', $map['test-mapped-category']['plugins'][2]['id'] ); - } - - /** - * Test adding a setting item. - */ - public function add_setting_item() { - $this->instance->add_setting_item( - array( - 'id' => 'test-setting-item', - 'title' => 'Test Setting Item', - ) - ); - - $this->instance->add_setting_item( - array( - 'id' => 'test-setting-item-bad-parent', - 'title' => 'Test Bad Parent', - 'parent' => 'woocommerce', - ) - ); - - $this->instance->add_setting_item( - array( - 'id' => 'test-setting-item-bad-menu', - 'title' => 'Test Bad Menu', - 'menuId' => 'primary', - ) - ); - - $items = $this->instance->get_items(); - $this->assertArrayHasKey( $menu_id, $map['test-setting-item'] ); - $this->assertArrayNotHasKey( $menu_id, $map['test-setting-item-bad-parent'] ); - $this->assertArrayNotHasKey( $menu_id, $map['test-setting-item-bad-menu'] ); - } - - /** - * Test if adding a menu item can be checked via the callback. - */ - public function test_has_callback() { - $item = array( - 'test-callback-item', - 'manage_woocommerce', - 'test-callback-item', - ); - - $this->assertFalse( $this->instance->has_callback( $item ) ); - - $this->instance->add_plugin_item( - array( - 'id' => 'test-callback-item', - 'title' => 'Test Callback Item', - 'capability' => 'manage_woocommerce', - 'url' => 'test-callback-item', - ) - ); - - $this->assertTrue( $this->instance->has_callback( $item ) ); - } -} diff --git a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/navigation/class-wc-screen.php b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/navigation/class-wc-screen.php deleted file mode 100644 index f4aca88f352..00000000000 --- a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/navigation/class-wc-screen.php +++ /dev/null @@ -1,198 +0,0 @@ -instance = new Screen(); - - // Store globals for reset. - global $pagenow, $current_screen; - $this->_current_screen = $current_screen; - $this->_pagenow = $pagenow; - /* phpcs:disable WordPress.Security.NonceVerification, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash */ - $this->_post = isset( $_GET['post'] ) ? $_GET['post'] : null; - $this->_post_type = isset( $_GET['post_type'] ) ? $_GET['post_type'] : null; - $this->_taxonomy = isset( $_GET['taxonomy'] ) ? $_GET['taxonomy'] : null; - /* phpcs:enable WordPress.Security.NonceVerification, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash */ - - // Register a post type. - register_post_type( 'my-post-type' ); - } - - /** - * Reset globals. - */ - public function reset_globals() { - global $pagenow, $current_screen; - - $current_screen = $this->_current_screen; - $pagenow = $this->_pagenow; - $_GET['post'] = $this->_post; - $_GET['post_type'] = $this->_post_type; - $_GET['taxonomy'] = $this->_taxonomy; - } - - /** - * Test that screen IDs are correctly registered. - */ - public function test_add_screen() { - $this->instance->add_screen( 'my-screen' ); - // Test adding a duplicate screen ID. - $this->instance->add_screen( 'my-screen' ); - $this->instance->add_screen( 'plugins.php' ); - - $screen_ids = $this->instance->get_screen_ids(); - - $this->assertCount( 2, $screen_ids ); - $this->assertContains( 'admin_page_my-screen', $screen_ids ); - $this->assertContains( 'admin_page_plugins', $screen_ids ); - } - - /** - * Test that taxonomies are correctly registered. - */ - public function test_register_taxonomy() { - $this->instance->register_taxonomy( 'my-taxonomy' ); - // Test adding a duplicate taxonomy. - $this->instance->register_taxonomy( 'my-taxonomy' ); - - $taxonomies = $this->instance->get_taxonomies(); - - $this->assertCount( 1, $taxonomies ); - $this->assertContains( 'my-taxonomy', $taxonomies ); - } - - /** - * Test that post types are correctly registered. - */ - public function test_register_post_type() { - $this->instance->register_post_type( 'my-post-type' ); - // Test adding a duplicate post type. - $this->instance->register_post_type( 'my-post-type' ); - - $post_types = $this->instance->get_post_types(); - - $this->assertCount( 1, $post_types ); - $this->assertContains( 'my-post-type', $post_types ); - } - - /** - * Test that screens can be detected. - */ - public function test_is_woocommerce_page_screens() { - $this->instance->add_screen( 'my-screen' ); - - global $pagenow, $current_screen; - - $this->assertFalse( $this->instance->is_woocommerce_page() ); - $current_screen = (object) array( 'id' => 'admin_page_my-screen' ); - $this->assertTrue( $this->instance->is_woocommerce_page() ); - $current_screen = (object) array( 'id' => 'admin_page_different-screen' ); - $this->assertFalse( $this->instance->is_woocommerce_page() ); - - $this->reset_globals(); - } - - /** - * Test that taxonomies can be detected. - */ - public function test_is_woocommerce_page_taxonomies() { - global $pagenow, $current_screen; - - $this->instance->register_taxonomy( 'my-taxonomy' ); - - $pagenow = 'edit-tags.php'; - $_GET['taxonomy'] = 'my-taxonomy'; - $this->assertTrue( $this->instance->is_woocommerce_page() ); - $pagenow = 'term.php'; - $this->assertTrue( $this->instance->is_woocommerce_page() ); - $_GET['taxonomy'] = 'different-taxonomy'; - $this->assertFalse( $this->instance->is_woocommerce_page() ); - $pagenow = 'edit.php'; - $_GET['taxonomy'] = 'my-taxonomy'; - $this->assertFalse( $this->instance->is_woocommerce_page() ); - - // Core taxonomies. - $pagenow = 'edit-tags.php'; - $_GET['taxonomy'] = 'product_cat'; - $this->assertTrue( $this->instance->is_woocommerce_page() ); - $pagenow = 'edit-tags.php'; - $_GET['taxonomy'] = 'product_tag'; - $this->assertTrue( $this->instance->is_woocommerce_page() ); - - $this->reset_globals(); - } - - /** - * Test that post types can be detected. - */ - public function test_is_woocommerce_page_post_types() { - global $pagenow, $current_screen; - - $this->instance->register_post_type( 'my-post-type' ); - - $pagenow = 'edit.php'; - $_GET['taxonomy'] = null; - $_GET['post_type'] = 'my-post-type'; - $this->assertTrue( $this->instance->is_woocommerce_page() ); - $pagenow = 'post.php'; - $this->assertTrue( $this->instance->is_woocommerce_page() ); - $pagenow = 'post-new.php'; - $this->assertTrue( $this->instance->is_woocommerce_page() ); - $_GET['post_type'] = 'different-post-type'; - $this->assertFalse( $this->instance->is_woocommerce_page() ); - $pagenow = 'edit-tags.php'; - $_GET['post_type'] = 'my-post-type'; - $this->assertFalse( $this->instance->is_woocommerce_page() ); - - $my_post_id = wp_insert_post( - array( - 'post_title' => 'Test post type', - 'post_type' => 'my-post-type', - ) - ); - - $different_post_id = wp_insert_post( - array( - 'post_title' => 'Different post type', - 'post_type' => 'post', - ) - ); - - $_GET['post'] = $my_post_id; - $pagenow = 'edit.php'; - $this->assertTrue( $this->instance->is_woocommerce_page() ); - - $_GET['post'] = $different_post_id; - $pagenow = 'edit.php'; - $this->assertFalse( $this->instance->is_woocommerce_page() ); - - $this->reset_globals(); - } -} - -/* phpcs:enable WordPress.WP.GlobalVariablesOverride.Prohibited */