POC store navigation (https://github.com/woocommerce/woocommerce-admin/pull/3202)
* Add base nav component * Check if current screen is WC registered page * Add core menu items * Add param for menu items to migrate and hide old menu items * Add body classes for wc navigation * Check capability before adding menu items * Add submenu items to frontend component * Hide wc nav behind option Co-authored-by: Joshua Flowers <joshuatf@gmail.com>
This commit is contained in:
parent
16fdae3d06
commit
5b201365dd
|
@ -9,12 +9,25 @@ import { render } from '@wordpress/element';
|
|||
*/
|
||||
import './stylesheets/_index.scss';
|
||||
import { PageLayout, EmbedLayout, PrimaryLayout as NoticeArea } from './layout';
|
||||
import Navigation from './navigation';
|
||||
import 'wc-api/wp-data-store';
|
||||
import { withSettingsHydration } from '@woocommerce/data';
|
||||
|
||||
const appRoot = document.getElementById( 'root' );
|
||||
const navigationRoot = document.getElementById( 'woocommerce-embedded-navigation' );
|
||||
const settingsGroup = 'wc_admin';
|
||||
|
||||
if ( navigationRoot ) {
|
||||
const HydratedNavigation = withSettingsHydration( settingsGroup, window.wcSettings )(
|
||||
Navigation
|
||||
);
|
||||
render( <HydratedNavigation />, navigationRoot );
|
||||
|
||||
// Collapse the WP Menu.
|
||||
const adminMenu = document.getElementById( 'adminmenumain' );
|
||||
adminMenu.classList.add( 'folded' );
|
||||
}
|
||||
|
||||
if ( appRoot ) {
|
||||
const HydratedPageLayout = withSettingsHydration( settingsGroup, window.wcSettings )(
|
||||
PageLayout
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { Component } from '@wordpress/element';
|
||||
import { withSelect } from '@wordpress/data';
|
||||
|
||||
/**
|
||||
* WooCommerce dependencies
|
||||
*/
|
||||
import { SETTINGS_STORE_NAME } from '@woocommerce/data';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import './style.scss';
|
||||
|
||||
class Navigation extends Component {
|
||||
|
||||
renderMenuItem( item, depth = 0 ) {
|
||||
const { slug, title, url } = item;
|
||||
|
||||
return (
|
||||
<li
|
||||
key={ slug }
|
||||
className={ `woocommerce-navigation__menu-item woocommerce-navigation__menu-item-depth-${depth}` }
|
||||
>
|
||||
<a href={ url }>{ title }</a>
|
||||
{ item.children && item.children.length && (
|
||||
<ul className="woocommerce-navigation__submenu">
|
||||
{ item.children.map( ( childItem ) => {
|
||||
return this.renderMenuItem( childItem, depth + 1 );
|
||||
} ) }
|
||||
</ul>
|
||||
) }
|
||||
</li>
|
||||
)
|
||||
}
|
||||
|
||||
render() {
|
||||
const { items } = this.props;
|
||||
|
||||
return (
|
||||
<div className="woocommerce-navigation">
|
||||
<ul className="woocommerce-navigation__menu">
|
||||
{ items.map( ( item ) => {
|
||||
return this.renderMenuItem( item );
|
||||
} ) }
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withSelect( ( select ) => {
|
||||
const items = select(
|
||||
SETTINGS_STORE_NAME
|
||||
).getSetting( 'wc_admin', 'wcNavigation' );
|
||||
return { items };
|
||||
} )( Navigation );
|
|
@ -0,0 +1,19 @@
|
|||
.woocommerce-navigation {
|
||||
position: fixed;
|
||||
top: $admin-bar-height;
|
||||
left: 0;
|
||||
width: 160px;
|
||||
height: 100%;
|
||||
background: $core-grey-dark-800;
|
||||
}
|
||||
|
||||
.woocommerce-navigation__menu-item {
|
||||
padding: $gap-smaller 0;
|
||||
}
|
||||
|
||||
.has-woocommerce-navigation {
|
||||
#adminmenuwrap,
|
||||
#adminmenuback {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@
|
|||
"analytics-dashboard/customizable": true,
|
||||
"devdocs": false,
|
||||
"marketing": true,
|
||||
"navigation": false,
|
||||
"onboarding": true,
|
||||
"shipping-label-banner": true,
|
||||
"store-alerts": true,
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
"analytics-dashboard/customizable": true,
|
||||
"devdocs": true,
|
||||
"marketing": true,
|
||||
"navigation": true,
|
||||
"onboarding": true,
|
||||
"shipping-label-banner": true,
|
||||
"store-alerts": true,
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
"analytics-dashboard/customizable": true,
|
||||
"devdocs": false,
|
||||
"marketing": true,
|
||||
"navigation": false,
|
||||
"onboarding": true,
|
||||
"shipping-label-banner": true,
|
||||
"store-alerts": true,
|
||||
|
|
|
@ -258,7 +258,7 @@ class FeaturePlugin {
|
|||
*/
|
||||
public function deactivate_self() {
|
||||
deactivate_plugins( plugin_basename( WC_ADMIN_PLUGIN_FILE ) );
|
||||
unset( $_GET['activate'] );
|
||||
unset( $_GET['activate'] ); // phpcs:ignore CSRF ok.
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,459 @@
|
|||
<?php
|
||||
/**
|
||||
* WooCommerce Navigation
|
||||
* NOTE: DO NOT edit this file in WooCommerce core, this is generated from woocommerce-admin.
|
||||
*
|
||||
* @package Woocommerce Admin
|
||||
*/
|
||||
|
||||
namespace Automattic\WooCommerce\Admin\Features;
|
||||
|
||||
/**
|
||||
* Contains logic for the WooCommerce Navigation.
|
||||
*/
|
||||
class Navigation {
|
||||
/**
|
||||
* Class instance.
|
||||
*
|
||||
* @var Navigation instance
|
||||
*/
|
||||
protected static $instance = null;
|
||||
|
||||
/**
|
||||
* Array index of menu capability.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
const CAPABILITY = 1;
|
||||
|
||||
/**
|
||||
* Array index of menu callback.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
const CALLBACK = 2;
|
||||
|
||||
/**
|
||||
* Array index of menu callback.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
const SLUG = 3;
|
||||
|
||||
/**
|
||||
* Array index of menu CSS class string.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
const CSS_CLASSES = 4;
|
||||
|
||||
/**
|
||||
* Store top level categories.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $categories = array();
|
||||
|
||||
/**
|
||||
* Store related menu items.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $menu_items = array();
|
||||
|
||||
/**
|
||||
* Screen IDs of registered pages.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $screen_ids = array();
|
||||
|
||||
/**
|
||||
* Registered post types.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $post_types = array();
|
||||
|
||||
/**
|
||||
* Registered callbacks or URLs with migration boolean as key value pairs.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $callbacks = array();
|
||||
|
||||
/**
|
||||
* Check if we're on a WooCommerce page
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_woocommerce_page() {
|
||||
global $pagenow, $plugin_page;
|
||||
|
||||
// Get post type if on a post screen.
|
||||
$post_type = '';
|
||||
if ( in_array( $pagenow, array( 'edit.php', 'post.php', 'post-new.php' ), true ) ) {
|
||||
if ( isset( $_GET['post'] ) ) { // phpcs:ignore CSRF ok.
|
||||
$post_type = get_post_type( (int) $_GET['post'] ); // phpcs:ignore CSRF ok.
|
||||
} elseif ( isset( $_GET['post_type'] ) ) { // phpcs:ignore CSRF ok.
|
||||
$post_type = sanitize_text_field( wp_unslash( $_GET['post_type'] ) ); // phpcs:ignore CSRF ok.
|
||||
}
|
||||
}
|
||||
$post_types = apply_filters( 'woocommerce_navigation_post_types', self::$post_types );
|
||||
|
||||
// Get current screen ID.
|
||||
$current_screen = get_current_screen();
|
||||
$screen_ids = apply_filters( 'woocommerce_navigation_screen_ids', self::$screen_ids );
|
||||
|
||||
if (
|
||||
in_array( $post_type, $post_types, true ) ||
|
||||
in_array( $current_screen->id, self::$screen_ids, true )
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get class instance.
|
||||
*/
|
||||
final public static function instance() {
|
||||
if ( ! static::$instance ) {
|
||||
static::$instance = new static();
|
||||
}
|
||||
return static::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct() {
|
||||
if ( is_admin() && get_option( 'woocommerce_navigation_enabled', false ) ) {
|
||||
add_action( 'admin_menu', array( $this, 'add_core_menu_items' ) );
|
||||
add_action( 'admin_menu', array( $this, 'add_admin_settings' ) );
|
||||
add_action( 'admin_menu', array( $this, 'add_menu_settings' ), 20 );
|
||||
add_filter( 'add_menu_classes', array( $this, 'migrate_menu_items' ) );
|
||||
add_filter( 'admin_body_class', array( $this, 'add_body_class' ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add navigation classes to body.
|
||||
*
|
||||
* @param string $classes Classes.
|
||||
* @return string
|
||||
*/
|
||||
public function add_body_class( $classes ) {
|
||||
if ( self::is_woocommerce_page() ) {
|
||||
$classes .= ' has-woocommerce-navigation';
|
||||
}
|
||||
|
||||
return $classes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add registered admin settings.
|
||||
*/
|
||||
public function add_admin_settings() {
|
||||
$setting_pages = \WC_Admin_Settings::get_settings_pages();
|
||||
$settings = array();
|
||||
foreach ( $setting_pages as $setting_page ) {
|
||||
$settings = $setting_page->add_settings_page( $settings );
|
||||
}
|
||||
foreach ( $settings as $key => $setting ) {
|
||||
self::add_menu_item(
|
||||
'settings',
|
||||
$setting,
|
||||
'manage_woocommerce',
|
||||
$key,
|
||||
'admin.php?page=wc-status&tab=' . $key
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the core menu items to the new navigation
|
||||
*/
|
||||
public function add_core_menu_items() {
|
||||
// Orders category.
|
||||
self::add_menu_category(
|
||||
__( 'Orders', 'woocommerce-admin' ),
|
||||
'edit_shop_orders',
|
||||
'orders',
|
||||
'edit.php?post_type=shop_order'
|
||||
);
|
||||
|
||||
// Products category.
|
||||
self::add_menu_category(
|
||||
__( 'Products', 'woocommerce-admin' ),
|
||||
'edit_products',
|
||||
'products',
|
||||
'edit.php?post_type=product'
|
||||
);
|
||||
|
||||
// Extensions category.
|
||||
self::add_menu_category(
|
||||
__( 'Extensions', 'woocommerce-admin' ),
|
||||
'activate_plugins',
|
||||
'extensions',
|
||||
'plugins.php',
|
||||
null,
|
||||
null,
|
||||
false
|
||||
);
|
||||
self::add_menu_item(
|
||||
'extensions',
|
||||
__( 'My extensions', 'woocommerce-admin' ),
|
||||
'manage_woocommerce',
|
||||
'my-extensions',
|
||||
'plugins.php',
|
||||
null,
|
||||
null,
|
||||
false
|
||||
);
|
||||
self::add_menu_item(
|
||||
'extensions',
|
||||
__( 'Marketplace', 'woocommerce-admin' ),
|
||||
'manage_woocommerce',
|
||||
'marketplace',
|
||||
'wc-addons'
|
||||
);
|
||||
|
||||
// Settings category.
|
||||
self::add_menu_category(
|
||||
__( 'Settings', 'woocommerce-admin' ),
|
||||
'manage_woocommerce',
|
||||
'settings',
|
||||
'wc-settings'
|
||||
);
|
||||
|
||||
// Tools category.
|
||||
self::add_menu_category(
|
||||
__( 'Tools', 'woocommerce-admin' ),
|
||||
'manage_woocommerce',
|
||||
'tools',
|
||||
'wc-status'
|
||||
);
|
||||
self::add_menu_item(
|
||||
'tools',
|
||||
__( 'System status', 'woocommerce-admin' ),
|
||||
'manage_woocommerce',
|
||||
'system-status',
|
||||
'wc-status'
|
||||
);
|
||||
self::add_menu_item(
|
||||
'tools',
|
||||
__( 'Import / Export', 'woocommerce-admin' ),
|
||||
'import',
|
||||
'import-export',
|
||||
'import.php',
|
||||
null,
|
||||
null,
|
||||
false
|
||||
);
|
||||
self::add_menu_item(
|
||||
'tools',
|
||||
__( 'Utilities', 'woocommerce-admin' ),
|
||||
'manage_woocommerce',
|
||||
'utilities',
|
||||
'admin.php?page=wc-status&tab=tools'
|
||||
);
|
||||
|
||||
// User profile.
|
||||
self::add_menu_category(
|
||||
wp_get_current_user()->user_login,
|
||||
'read',
|
||||
'profile',
|
||||
'profile.php',
|
||||
null,
|
||||
null,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a WordPress menu callback to a URL.
|
||||
*
|
||||
* @param string $callback Menu callback.
|
||||
* @return string
|
||||
*/
|
||||
public static function get_callback_url( $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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a top level menu item to the navigation.
|
||||
*
|
||||
* @param string $title Menu title.
|
||||
* @param string $capability WordPress capability.
|
||||
* @param string $slug Menu slug.
|
||||
* @param string $url URL or menu callback.
|
||||
* @param string $icon Menu icon.
|
||||
* @param int $order Menu order.
|
||||
* @param bool $migrate Migrate the menu option and hide the old one.
|
||||
*/
|
||||
public static function add_menu_category( $title, $capability, $slug, $url = null, $icon = null, $order = null, $migrate = true ) {
|
||||
self::$categories[] = array(
|
||||
'title' => $title,
|
||||
'capability' => $capability,
|
||||
'slug' => $slug,
|
||||
'url' => self::get_callback_url( $url ),
|
||||
'icon' => $icon,
|
||||
'order' => $order,
|
||||
'migrate' => $migrate,
|
||||
);
|
||||
|
||||
self::$callbacks[ $url ] = $migrate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a child menu item to the navigation.
|
||||
*
|
||||
* @param string $parent_slug Parent item slug.
|
||||
* @param string $title Menu title.
|
||||
* @param string $capability WordPress capability.
|
||||
* @param string $slug Menu slug.
|
||||
* @param string $url URL or menu callback.
|
||||
* @param string $icon Menu icon.
|
||||
* @param int $order Menu order.
|
||||
* @param bool $migrate Migrate the menu option and hide the old one.
|
||||
*/
|
||||
public static function add_menu_item( $parent_slug, $title, $capability, $slug, $url = null, $icon = null, $order = null, $migrate = true ) {
|
||||
self::$menu_items[ $parent_slug ][] = array(
|
||||
'title' => $title,
|
||||
'capability' => $capability,
|
||||
'slug' => $slug,
|
||||
'url' => self::get_callback_url( $url ),
|
||||
'icon' => $icon,
|
||||
'order' => $order,
|
||||
'migrate' => $migrate,
|
||||
);
|
||||
|
||||
self::$callbacks[ $url ] = $migrate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the parent menu item if one exists.
|
||||
*
|
||||
* @param string $url URL or callback.
|
||||
* @return string|null
|
||||
*/
|
||||
public static function get_parent_menu_item( $url ) {
|
||||
global $submenu;
|
||||
|
||||
// This is already a parent item.
|
||||
if ( isset( $submenu[ $url ] ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
foreach ( $submenu as $key => $menu ) {
|
||||
foreach ( $menu as $item ) {
|
||||
if ( $item[ self::CALLBACK ] === $url ) {
|
||||
return $key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides all WP admin menus items and adds screen IDs to check for new items.
|
||||
*
|
||||
* @param array $menu Menu items.
|
||||
* @return array
|
||||
*/
|
||||
public static function migrate_menu_items( $menu ) {
|
||||
global $submenu;
|
||||
|
||||
foreach ( $menu as $key => $menu_item ) {
|
||||
if (
|
||||
isset( self::$callbacks[ $menu_item[ self::CALLBACK ] ] ) &&
|
||||
self::$callbacks[ $menu_item[ self::CALLBACK ] ]
|
||||
) {
|
||||
$menu[ $key ][ self::CSS_CLASSES ] .= ' hide-if-js';
|
||||
}
|
||||
}
|
||||
|
||||
foreach ( $submenu as $parent_key => $parent ) {
|
||||
foreach ( $parent as $key => $menu_item ) {
|
||||
if (
|
||||
isset( self::$callbacks[ $menu_item[ self::CALLBACK ] ] ) &&
|
||||
self::$callbacks[ $menu_item[ self::CALLBACK ] ]
|
||||
) {
|
||||
// Disable phpcs since we need to override submenu classes.
|
||||
// Note that `phpcs:ignore WordPress.Variables.GlobalVariables.OverrideProhibited` does not work to disable this check.
|
||||
// phpcs:disable
|
||||
if ( ! isset( $menu_item[ self::SLUG ] ) ) {
|
||||
$submenu[ $parent_key ][ $key ][] = '';
|
||||
}
|
||||
if ( ! isset( $menu_item[ self::CSS_CLASSES ] ) ) {
|
||||
$submenu[ $parent_key ][ $key ][] .= ' hide-if-js';
|
||||
} else {
|
||||
$submenu[ $parent_key ][ $key ][ self::CSS_CLASSES ] .= ' hide-if-js';
|
||||
}
|
||||
// phps:enable
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ( array_keys( self::$callbacks ) as $callback ) {
|
||||
self::add_screen_id( $callback );
|
||||
}
|
||||
|
||||
return $menu;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a screen ID to the list and automatically finds the parent if none is given.
|
||||
*
|
||||
* @param string $url URL or callback for page.
|
||||
* @param string|null $parent Parent slug.
|
||||
*/
|
||||
public static function add_screen_id( $url, $parent = null ) {
|
||||
global $submenu;
|
||||
|
||||
if ( ! $parent ) {
|
||||
$parent = self::get_parent_menu_item( $url );
|
||||
}
|
||||
self::$screen_ids[] = get_plugin_page_hookname( $url, $parent );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the menu to the page output.
|
||||
*/
|
||||
public function add_menu_settings() {
|
||||
global $submenu, $parent_file, $typenow, $self;
|
||||
|
||||
$categories = self::$categories;
|
||||
foreach ( $categories as $index => $category ) {
|
||||
if ( $category[ 'capability' ] && ! current_user_can( $category[ 'capability' ] ) ) {
|
||||
unset( $categories[ $index ] );
|
||||
continue;
|
||||
}
|
||||
|
||||
$categories[ $index ]['children'] = array();
|
||||
if( isset( self::$menu_items[ $category['slug'] ] ) ) {
|
||||
foreach ( self::$menu_items[ $category['slug'] ] as $item ) {
|
||||
if ( $item[ 'capability' ] && ! current_user_can( $item[ 'capability' ] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$categories[ $index ]['children'][] = $item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$data_registry = \Automattic\WooCommerce\Blocks\Package::container()->get(
|
||||
\Automattic\WooCommerce\Blocks\Assets\AssetDataRegistry::class
|
||||
);
|
||||
|
||||
$data_registry->add( 'wcNavigation', $categories );
|
||||
}
|
||||
}
|
|
@ -507,7 +507,16 @@ class Loader {
|
|||
* The initial contents here are meant as a place loader for when the PHP page initialy loads.
|
||||
*/
|
||||
public static function embed_page_header() {
|
||||
if ( ! self::is_embed_page() ) {
|
||||
|
||||
$features = wc_admin_get_feature_config();
|
||||
if (
|
||||
$features['navigation'] &&
|
||||
\Automattic\WooCommerce\Admin\Features\Navigation::instance()->is_woocommerce_page()
|
||||
) {
|
||||
self::embed_navigation_menu();
|
||||
}
|
||||
|
||||
if ( ! self::is_admin_page() && ! self::is_embed_page() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -515,6 +524,10 @@ class Loader {
|
|||
return;
|
||||
}
|
||||
|
||||
if ( ! self::is_embed_page() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$sections = self::get_embed_breadcrumbs();
|
||||
$sections = is_array( $sections ) ? $sections : array( $sections );
|
||||
?>
|
||||
|
@ -532,6 +545,16 @@ class Loader {
|
|||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up a div for the navigation menu.
|
||||
* The initial contents here are meant as a place loader for when the PHP page initialy loads.
|
||||
*/
|
||||
protected static function embed_navigation_menu() {
|
||||
?>
|
||||
<div id="woocommerce-embedded-navigation"></div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds body classes to the main wp-admin wrapper, allowing us to better target elements in specific scenarios.
|
||||
*
|
||||
|
|
|
@ -455,10 +455,6 @@ class PageController {
|
|||
* Set up a div for the app to render into.
|
||||
*/
|
||||
public static function page_wrapper() {
|
||||
?>
|
||||
<div class="wrap">
|
||||
<div id="root"></div>
|
||||
</div>
|
||||
<?php
|
||||
Loader::page_wrapper();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue