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:
Paul Sealock 2020-10-22 16:01:25 +13:00 committed by GitHub
parent 29f6bcc126
commit 7e351c18a3
9 changed files with 144 additions and 97 deletions

View File

@ -57,58 +57,63 @@ export default () => {
report: 'revenue',
title: __( 'Revenue', 'woocommerce-admin' ),
component: RevenueReport,
id: 'woocommerce-analytics-revenue',
},
{
report: 'products',
title: __( 'Products', 'woocommerce-admin' ),
component: ProductsReport,
id: 'woocommerce-analytics-products',
},
{
report: 'variations',
title: __( 'Variations', 'woocommerce-admin' ),
component: VariationsReport,
id: 'woocommerce-analytics-variations',
},
{
report: 'orders',
title: __( 'Orders', 'woocommerce-admin' ),
component: OrdersReport,
id: 'woocommerce-analytics-orders',
},
{
report: 'categories',
title: __( 'Categories', 'woocommerce-admin' ),
component: CategoriesReport,
id: 'woocommerce-analytics-categories',
},
{
report: 'coupons',
title: __( 'Coupons', 'woocommerce-admin' ),
component: CouponsReport,
id: 'woocommerce-analytics-coupons',
},
{
report: 'taxes',
title: __( 'Taxes', 'woocommerce-admin' ),
component: TaxesReport,
},
{
report: 'downloads',
title: __( 'Downloads', 'woocommerce-admin' ),
component: DownloadsReport,
id: 'woocommerce-analytics-taxes',
},
manageStock === 'yes'
? {
report: 'stock',
title: __( 'Stock', 'woocommerce-admin' ),
component: StockReport,
id: 'woocommerce-analytics-stock',
}
: null,
{
report: 'customers',
title: __( 'Customers', 'woocommerce-admin' ),
component: CustomersReport,
id: 'woocommerce-analytics-customers',
},
{
report: 'downloads',
title: __( 'Downloads', 'woocommerce-admin' ),
component: DownloadsReport,
id: 'woocommerce-analytics-downloads',
},
].filter( Boolean );

View File

@ -59,6 +59,7 @@ export const getPages = () => {
__( 'Home', 'woocommerce-admin' ),
],
wpOpenMenu: 'toplevel_page_woocommerce',
id: 'woocommerce-home',
} );
if ( window.wcAdminFeatures.analytics ) {
@ -74,6 +75,7 @@ export const getPages = () => {
__( 'Overview', 'woocommerce-admin' ),
],
wpOpenMenu: 'toplevel_page_wc-admin-path--analytics-overview',
id: 'woocommerce-analytics-overview',
} );
pages.push( {
container: AnalyticsSettings,
@ -87,6 +89,7 @@ export const getPages = () => {
__( 'Settings', 'woocommerce-admin' ),
],
wpOpenMenu: 'toplevel_page_wc-admin-path--analytics-overview',
id: 'woocommerce-analytics-settings',
} );
pages.push( {
container: AnalyticsReport,
@ -96,6 +99,7 @@ export const getPages = () => {
__( 'Customers', 'woocommerce-admin' ),
],
wpOpenMenu: 'toplevel_page_woocommerce',
id: 'woocommerce-analytics-customers',
} );
pages.push( {
container: AnalyticsReport,
@ -130,6 +134,7 @@ export const getPages = () => {
__( 'Overview', 'woocommerce-admin' ),
],
wpOpenMenu: 'toplevel_page_woocommerce-marketing',
id: 'woocommerce-marketing',
} );
}

View File

@ -26,6 +26,7 @@ import { Controller, getPages } from './controller';
import { Header } from '../header';
import Notices from './notices';
import TransientNotices from './transient-notices';
import './navigation';
const StoreAlerts = lazy( () =>
import( /* webpackChunkName: "store-alerts" */ './store-alerts' )

View File

@ -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 } );

View File

@ -1,20 +1,22 @@
/**
* External dependencies
*/
import {
__experimentalNavigationItem as NavigationItem,
__experimentalUseSlot as useSlot,
} from '@wordpress/components';
import { WooNavigationItem } from '@woocommerce/navigation';
import { __experimentalNavigationItem as NavigationItem } from '@wordpress/components';
import { WooNavigationItem, useNavSlot } from '@woocommerce/navigation';
const Item = ( { item } ) => {
const slot = useSlot( item.id );
const slot = useNavSlot( 'woocommerce_navigation_' + item.id );
const hasFills = Boolean( slot.fills && slot.fills.length );
// Only render a slot if a coresponding Fill exists and the item is not a category
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 (
<NavigationItem
key={ item.id }

View File

@ -1,8 +1,8 @@
/**
* External dependencies
*/
import { SlotFillProvider } from '@wordpress/components';
import { PluginArea } from '@wordpress/plugins';
import { NavSlotFillProvider } from '@woocommerce/navigation';
import { withNavigationHydration } from '@woocommerce/data';
/**
@ -12,10 +12,10 @@ import './stylesheets/index.scss';
import Container from './components/container';
const Navigation = () => (
<SlotFillProvider>
<NavSlotFillProvider>
<Container />
<PluginArea />
</SlotFillProvider>
</NavSlotFillProvider>
);
const HydratedNavigation = withNavigationHydration( window.wcNavigation )(

View File

@ -6,9 +6,10 @@ import { parse } from 'qs';
import { pick, uniq } from 'lodash';
import { applyFilters } from '@wordpress/hooks';
import {
__experimentalNavigationItem as NavigationItem,
Slot,
Fill,
SlotFillProvider,
__experimentalUseSlot as useSlot,
} from '@wordpress/components';
/**
@ -170,13 +171,42 @@ export function updateQueryString(
getHistory().push( newPath );
}
export const WooNavigationItem = ( { children, item, ...passProps } ) => {
return (
<Fill name={ item }>
<NavigationItem item={ item } { ...passProps }>
{ children }
</NavigationItem>
</Fill>
);
/**
* Create a Fill for extensions to add client facing custom Navigation Items.
*
* @param {Object} param0
* @param {Array} param0.children - Node children.
* @param {string} param0.item - Navigation item slug.
*/
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 );

View File

@ -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
}
}

View File

@ -451,6 +451,7 @@ class Loader {
'wp-date',
'wp-plugins',
'wc-tracks',
'wc-navigation',
),
$js_file_version,
true