Navigation: extend with WC Admin router links (https://github.com/woocommerce/woocommerce-admin/pull/5445)
* add test case * save * pages * comments * use id * bail on no wcAdmin pages * prefix
This commit is contained in:
parent
29f6bcc126
commit
7e351c18a3
|
@ -57,58 +57,63 @@ export default () => {
|
||||||
report: 'revenue',
|
report: 'revenue',
|
||||||
title: __( 'Revenue', 'woocommerce-admin' ),
|
title: __( 'Revenue', 'woocommerce-admin' ),
|
||||||
component: RevenueReport,
|
component: RevenueReport,
|
||||||
|
id: 'woocommerce-analytics-revenue',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
report: 'products',
|
report: 'products',
|
||||||
title: __( 'Products', 'woocommerce-admin' ),
|
title: __( 'Products', 'woocommerce-admin' ),
|
||||||
component: ProductsReport,
|
component: ProductsReport,
|
||||||
|
id: 'woocommerce-analytics-products',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
report: 'variations',
|
report: 'variations',
|
||||||
title: __( 'Variations', 'woocommerce-admin' ),
|
title: __( 'Variations', 'woocommerce-admin' ),
|
||||||
component: VariationsReport,
|
component: VariationsReport,
|
||||||
|
id: 'woocommerce-analytics-variations',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
report: 'orders',
|
report: 'orders',
|
||||||
title: __( 'Orders', 'woocommerce-admin' ),
|
title: __( 'Orders', 'woocommerce-admin' ),
|
||||||
component: OrdersReport,
|
component: OrdersReport,
|
||||||
|
id: 'woocommerce-analytics-orders',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
report: 'categories',
|
report: 'categories',
|
||||||
title: __( 'Categories', 'woocommerce-admin' ),
|
title: __( 'Categories', 'woocommerce-admin' ),
|
||||||
component: CategoriesReport,
|
component: CategoriesReport,
|
||||||
|
id: 'woocommerce-analytics-categories',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
report: 'coupons',
|
report: 'coupons',
|
||||||
title: __( 'Coupons', 'woocommerce-admin' ),
|
title: __( 'Coupons', 'woocommerce-admin' ),
|
||||||
component: CouponsReport,
|
component: CouponsReport,
|
||||||
|
id: 'woocommerce-analytics-coupons',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
report: 'taxes',
|
report: 'taxes',
|
||||||
title: __( 'Taxes', 'woocommerce-admin' ),
|
title: __( 'Taxes', 'woocommerce-admin' ),
|
||||||
component: TaxesReport,
|
component: TaxesReport,
|
||||||
},
|
id: 'woocommerce-analytics-taxes',
|
||||||
{
|
|
||||||
report: 'downloads',
|
|
||||||
title: __( 'Downloads', 'woocommerce-admin' ),
|
|
||||||
component: DownloadsReport,
|
|
||||||
},
|
},
|
||||||
manageStock === 'yes'
|
manageStock === 'yes'
|
||||||
? {
|
? {
|
||||||
report: 'stock',
|
report: 'stock',
|
||||||
title: __( 'Stock', 'woocommerce-admin' ),
|
title: __( 'Stock', 'woocommerce-admin' ),
|
||||||
component: StockReport,
|
component: StockReport,
|
||||||
|
id: 'woocommerce-analytics-stock',
|
||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
{
|
{
|
||||||
report: 'customers',
|
report: 'customers',
|
||||||
title: __( 'Customers', 'woocommerce-admin' ),
|
title: __( 'Customers', 'woocommerce-admin' ),
|
||||||
component: CustomersReport,
|
component: CustomersReport,
|
||||||
|
id: 'woocommerce-analytics-customers',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
report: 'downloads',
|
report: 'downloads',
|
||||||
title: __( 'Downloads', 'woocommerce-admin' ),
|
title: __( 'Downloads', 'woocommerce-admin' ),
|
||||||
component: DownloadsReport,
|
component: DownloadsReport,
|
||||||
|
id: 'woocommerce-analytics-downloads',
|
||||||
},
|
},
|
||||||
].filter( Boolean );
|
].filter( Boolean );
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,7 @@ export const getPages = () => {
|
||||||
__( 'Home', 'woocommerce-admin' ),
|
__( 'Home', 'woocommerce-admin' ),
|
||||||
],
|
],
|
||||||
wpOpenMenu: 'toplevel_page_woocommerce',
|
wpOpenMenu: 'toplevel_page_woocommerce',
|
||||||
|
id: 'woocommerce-home',
|
||||||
} );
|
} );
|
||||||
|
|
||||||
if ( window.wcAdminFeatures.analytics ) {
|
if ( window.wcAdminFeatures.analytics ) {
|
||||||
|
@ -74,6 +75,7 @@ export const getPages = () => {
|
||||||
__( 'Overview', 'woocommerce-admin' ),
|
__( 'Overview', 'woocommerce-admin' ),
|
||||||
],
|
],
|
||||||
wpOpenMenu: 'toplevel_page_wc-admin-path--analytics-overview',
|
wpOpenMenu: 'toplevel_page_wc-admin-path--analytics-overview',
|
||||||
|
id: 'woocommerce-analytics-overview',
|
||||||
} );
|
} );
|
||||||
pages.push( {
|
pages.push( {
|
||||||
container: AnalyticsSettings,
|
container: AnalyticsSettings,
|
||||||
|
@ -87,6 +89,7 @@ export const getPages = () => {
|
||||||
__( 'Settings', 'woocommerce-admin' ),
|
__( 'Settings', 'woocommerce-admin' ),
|
||||||
],
|
],
|
||||||
wpOpenMenu: 'toplevel_page_wc-admin-path--analytics-overview',
|
wpOpenMenu: 'toplevel_page_wc-admin-path--analytics-overview',
|
||||||
|
id: 'woocommerce-analytics-settings',
|
||||||
} );
|
} );
|
||||||
pages.push( {
|
pages.push( {
|
||||||
container: AnalyticsReport,
|
container: AnalyticsReport,
|
||||||
|
@ -96,6 +99,7 @@ export const getPages = () => {
|
||||||
__( 'Customers', 'woocommerce-admin' ),
|
__( 'Customers', 'woocommerce-admin' ),
|
||||||
],
|
],
|
||||||
wpOpenMenu: 'toplevel_page_woocommerce',
|
wpOpenMenu: 'toplevel_page_woocommerce',
|
||||||
|
id: 'woocommerce-analytics-customers',
|
||||||
} );
|
} );
|
||||||
pages.push( {
|
pages.push( {
|
||||||
container: AnalyticsReport,
|
container: AnalyticsReport,
|
||||||
|
@ -130,6 +134,7 @@ export const getPages = () => {
|
||||||
__( 'Overview', 'woocommerce-admin' ),
|
__( 'Overview', 'woocommerce-admin' ),
|
||||||
],
|
],
|
||||||
wpOpenMenu: 'toplevel_page_woocommerce-marketing',
|
wpOpenMenu: 'toplevel_page_woocommerce-marketing',
|
||||||
|
id: 'woocommerce-marketing',
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@ import { Controller, getPages } from './controller';
|
||||||
import { Header } from '../header';
|
import { Header } from '../header';
|
||||||
import Notices from './notices';
|
import Notices from './notices';
|
||||||
import TransientNotices from './transient-notices';
|
import TransientNotices from './transient-notices';
|
||||||
|
import './navigation';
|
||||||
|
|
||||||
const StoreAlerts = lazy( () =>
|
const StoreAlerts = lazy( () =>
|
||||||
import( /* webpackChunkName: "store-alerts" */ './store-alerts' )
|
import( /* webpackChunkName: "store-alerts" */ './store-alerts' )
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { registerPlugin } from '@wordpress/plugins';
|
||||||
|
import {
|
||||||
|
WooNavigationItem,
|
||||||
|
getNewPath,
|
||||||
|
getPersistedQuery,
|
||||||
|
} from '@woocommerce/navigation';
|
||||||
|
import { Link } from '@woocommerce/components';
|
||||||
|
import { __ } from '@wordpress/i18n';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import getReports from '../analytics/report/get-reports';
|
||||||
|
import { getPages } from './controller';
|
||||||
|
import { isWCAdmin } from '../dashboard/utils';
|
||||||
|
|
||||||
|
const NavigationPlugin = () => {
|
||||||
|
/**
|
||||||
|
* If the current page is embedded, stay with the default urls
|
||||||
|
* provided by Navigation because the router isn't present to
|
||||||
|
* respond to <Link /> component's manipulation of the url.
|
||||||
|
*/
|
||||||
|
if ( ! isWCAdmin( window.location.href ) ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const reports = getReports();
|
||||||
|
const pages = getPages()
|
||||||
|
.filter( ( page ) => page.id )
|
||||||
|
.map( ( page ) => {
|
||||||
|
if ( page.id === 'woocommerce-analytics-settings' ) {
|
||||||
|
return {
|
||||||
|
...page,
|
||||||
|
breadcrumbs: [ __( 'Analytics', 'woocommerce-admin' ) ],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return page;
|
||||||
|
} );
|
||||||
|
const persistedQuery = getPersistedQuery( {} );
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{ pages.map( ( page ) => (
|
||||||
|
<WooNavigationItem item={ page.id } key={ page.id }>
|
||||||
|
<Link
|
||||||
|
className="components-button"
|
||||||
|
href={ getNewPath( persistedQuery, page.path, {} ) }
|
||||||
|
type="wc-admin"
|
||||||
|
>
|
||||||
|
{ page.breadcrumbs[ page.breadcrumbs.length - 1 ] }
|
||||||
|
</Link>
|
||||||
|
</WooNavigationItem>
|
||||||
|
) ) }
|
||||||
|
{ reports.map( ( item ) => (
|
||||||
|
<WooNavigationItem item={ item.id } key={ item.report }>
|
||||||
|
<Link
|
||||||
|
className="components-button"
|
||||||
|
href={ getNewPath(
|
||||||
|
persistedQuery,
|
||||||
|
`/analytics/${ item.report }`,
|
||||||
|
{}
|
||||||
|
) }
|
||||||
|
type="wc-admin"
|
||||||
|
>
|
||||||
|
{ item.title }
|
||||||
|
</Link>
|
||||||
|
</WooNavigationItem>
|
||||||
|
) ) }
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
registerPlugin( 'wc-admin-navigation', { render: NavigationPlugin } );
|
|
@ -1,20 +1,22 @@
|
||||||
/**
|
/**
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
import {
|
import { __experimentalNavigationItem as NavigationItem } from '@wordpress/components';
|
||||||
__experimentalNavigationItem as NavigationItem,
|
import { WooNavigationItem, useNavSlot } from '@woocommerce/navigation';
|
||||||
__experimentalUseSlot as useSlot,
|
|
||||||
} from '@wordpress/components';
|
|
||||||
import { WooNavigationItem } from '@woocommerce/navigation';
|
|
||||||
|
|
||||||
const Item = ( { item } ) => {
|
const Item = ( { item } ) => {
|
||||||
const slot = useSlot( item.id );
|
const slot = useNavSlot( 'woocommerce_navigation_' + item.id );
|
||||||
const hasFills = Boolean( slot.fills && slot.fills.length );
|
const hasFills = Boolean( slot.fills && slot.fills.length );
|
||||||
|
|
||||||
// Only render a slot if a coresponding Fill exists and the item is not a category
|
// Only render a slot if a coresponding Fill exists and the item is not a category
|
||||||
if ( hasFills && ! item.isCategory ) {
|
if ( hasFills && ! item.isCategory ) {
|
||||||
return <WooNavigationItem.Slot name={ item.id } />;
|
return (
|
||||||
|
<NavigationItem key={ item.id } item={ item.id }>
|
||||||
|
<WooNavigationItem.Slot name={ item.id } />
|
||||||
|
</NavigationItem>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NavigationItem
|
<NavigationItem
|
||||||
key={ item.id }
|
key={ item.id }
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
/**
|
/**
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
import { SlotFillProvider } from '@wordpress/components';
|
|
||||||
import { PluginArea } from '@wordpress/plugins';
|
import { PluginArea } from '@wordpress/plugins';
|
||||||
|
import { NavSlotFillProvider } from '@woocommerce/navigation';
|
||||||
import { withNavigationHydration } from '@woocommerce/data';
|
import { withNavigationHydration } from '@woocommerce/data';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -12,10 +12,10 @@ import './stylesheets/index.scss';
|
||||||
import Container from './components/container';
|
import Container from './components/container';
|
||||||
|
|
||||||
const Navigation = () => (
|
const Navigation = () => (
|
||||||
<SlotFillProvider>
|
<NavSlotFillProvider>
|
||||||
<Container />
|
<Container />
|
||||||
<PluginArea />
|
<PluginArea />
|
||||||
</SlotFillProvider>
|
</NavSlotFillProvider>
|
||||||
);
|
);
|
||||||
|
|
||||||
const HydratedNavigation = withNavigationHydration( window.wcNavigation )(
|
const HydratedNavigation = withNavigationHydration( window.wcNavigation )(
|
||||||
|
|
|
@ -6,9 +6,10 @@ import { parse } from 'qs';
|
||||||
import { pick, uniq } from 'lodash';
|
import { pick, uniq } from 'lodash';
|
||||||
import { applyFilters } from '@wordpress/hooks';
|
import { applyFilters } from '@wordpress/hooks';
|
||||||
import {
|
import {
|
||||||
__experimentalNavigationItem as NavigationItem,
|
|
||||||
Slot,
|
Slot,
|
||||||
Fill,
|
Fill,
|
||||||
|
SlotFillProvider,
|
||||||
|
__experimentalUseSlot as useSlot,
|
||||||
} from '@wordpress/components';
|
} from '@wordpress/components';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -170,13 +171,42 @@ export function updateQueryString(
|
||||||
getHistory().push( newPath );
|
getHistory().push( newPath );
|
||||||
}
|
}
|
||||||
|
|
||||||
export const WooNavigationItem = ( { children, item, ...passProps } ) => {
|
/**
|
||||||
return (
|
* Create a Fill for extensions to add client facing custom Navigation Items.
|
||||||
<Fill name={ item }>
|
*
|
||||||
<NavigationItem item={ item } { ...passProps }>
|
* @param {Object} param0
|
||||||
{ children }
|
* @param {Array} param0.children - Node children.
|
||||||
</NavigationItem>
|
* @param {string} param0.item - Navigation item slug.
|
||||||
</Fill>
|
*/
|
||||||
);
|
export const WooNavigationItem = ( { children, item } ) => {
|
||||||
|
return <Fill name={ 'woocommerce_navigation_' + item }>{ children }</Fill>;
|
||||||
};
|
};
|
||||||
WooNavigationItem.Slot = ( { name } ) => <Slot name={ name } />;
|
WooNavigationItem.Slot = ( { name } ) => (
|
||||||
|
<Slot name={ 'woocommerce_navigation_' + name } />
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export @wordpress/components SlotFillProvider so that Slots, Fills, and useSlot
|
||||||
|
* have access to the same context.
|
||||||
|
*
|
||||||
|
* This is a workaround because components exported from this package do not have
|
||||||
|
* the same `context` as those created in the /client folder. This problem is due
|
||||||
|
* to WC Admin bundling @wordpress/components instead of enqueuing and using
|
||||||
|
* wp.components from the window.
|
||||||
|
*
|
||||||
|
* @param {Object} param0
|
||||||
|
* @param {Array} param0.children - Node children.
|
||||||
|
*/
|
||||||
|
export const NavSlotFillProvider = ( { children } ) => (
|
||||||
|
<SlotFillProvider>{ children }</SlotFillProvider>
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Similar to NavSlotFillProvider above, this is a workaround because components
|
||||||
|
* exported from this package do not have the same `context` as those created
|
||||||
|
* in the /client folder. This problem is due to WC Admin bundling @wordpress/components
|
||||||
|
* instead of enqueuing and using wp.components from the window.
|
||||||
|
*
|
||||||
|
* @param {string} name - slot name.
|
||||||
|
*/
|
||||||
|
export const useNavSlot = ( name ) => useSlot( name );
|
||||||
|
|
|
@ -1,72 +0,0 @@
|
||||||
<?php
|
|
||||||
/**
|
|
||||||
* Navigation Experience
|
|
||||||
*
|
|
||||||
* @package Woocommerce Admin
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Automattic\WooCommerce\Admin\Features;
|
|
||||||
|
|
||||||
use Automattic\WooCommerce\Admin\Loader;
|
|
||||||
use Automattic\WooCommerce\Admin\Features\Navigation\Screen;
|
|
||||||
use Automattic\WooCommerce\Admin\Features\Navigation\Menu;
|
|
||||||
use Automattic\WooCommerce\Admin\Features\Navigation\CoreMenu;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Contains logic for the Navigation
|
|
||||||
*/
|
|
||||||
class Navigation {
|
|
||||||
/**
|
|
||||||
* Hook into WooCommerce.
|
|
||||||
*/
|
|
||||||
public function __construct() {
|
|
||||||
add_filter( 'woocommerce_admin_preload_options', array( $this, 'preload_options' ) );
|
|
||||||
add_filter( 'woocommerce_admin_features', array( $this, 'maybe_remove_nav_feature' ), 0 );
|
|
||||||
|
|
||||||
if ( Loader::is_feature_enabled( 'navigation' ) ) {
|
|
||||||
add_action( 'in_admin_header', array( __CLASS__, 'embed_navigation' ) );
|
|
||||||
|
|
||||||
Menu::instance()->init();
|
|
||||||
CoreMenu::instance()->init();
|
|
||||||
Screen::instance()->init();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Overwrites the allowed features array using a local `feature-config.php` file.
|
|
||||||
*
|
|
||||||
* @param array $features Array of feature slugs.
|
|
||||||
*/
|
|
||||||
public function maybe_remove_nav_feature( $features ) {
|
|
||||||
if ( in_array( 'navigation', $features, true ) && 'yes' !== get_option( 'woocommerce_navigation_enabled', 'no' ) ) {
|
|
||||||
$features = array_diff( $features, array( 'navigation' ) );
|
|
||||||
}
|
|
||||||
return $features;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Preload options to prime state of the application.
|
|
||||||
*
|
|
||||||
* @param array $options Array of options to preload.
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function preload_options( $options ) {
|
|
||||||
$options[] = 'woocommerce_navigation_enabled';
|
|
||||||
|
|
||||||
return $options;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set up a div for the navigation.
|
|
||||||
* The initial contents here are meant as a place loader for when the PHP page initialy loads.
|
|
||||||
*/
|
|
||||||
public static function embed_navigation() {
|
|
||||||
if ( ! Screen::is_woocommerce_page() ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
||||||
<div id="woocommerce-embedded-navigation"></div>
|
|
||||||
<?php
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -451,6 +451,7 @@ class Loader {
|
||||||
'wp-date',
|
'wp-date',
|
||||||
'wp-plugins',
|
'wp-plugins',
|
||||||
'wc-tracks',
|
'wc-tracks',
|
||||||
|
'wc-navigation',
|
||||||
),
|
),
|
||||||
$js_file_version,
|
$js_file_version,
|
||||||
true
|
true
|
||||||
|
|
Loading…
Reference in New Issue