Global Header & Activity Panel on all WooCommerce Pages (https://github.com/woocommerce/woocommerce-admin/pull/110)

* Makes the header/sidebar component embeddable on other WooCommerce pages.

* Some mobile CSS fixes to make sure the header bar displays properly on smaller screensizes.

* Refactor notices and pull out success message from the panel

* Handle positioning of screen options, update message handling, css fixes and header height increase to match mockups, some code cleanup

* Only enable the header embed on normal/classic WooCommerce pages, and provide a method for plugins to opt-in.
This change also builds nicer breadcrumbs for pages.

* Code cleanup and consistent naming.

* Some spacing cleanup. Also updated the page title method to correctly set page titles in PHP for classic WC pages
This commit is contained in:
Justin Shreve 2018-06-26 10:49:42 -04:00 committed by GitHub
parent 99ac7728cd
commit bf80e5c649
18 changed files with 603 additions and 74 deletions

View File

@ -6,7 +6,6 @@ import { __ } from '@wordpress/i18n';
import { Component, Fragment } from '@wordpress/element';
import { TabPanel } from '@wordpress/components';
import PropTypes from 'prop-types';
import { Link } from 'react-router-dom';
/**
* Internal dependencies
@ -14,6 +13,7 @@ import { Link } from 'react-router-dom';
import ComparePeriods from './compare-periods';
import { H, Section } from 'layout/section';
import PresetPeriods from './preset-periods';
import Link from 'components/link';
class DatePickerContent extends Component {
render() {

View File

@ -25,5 +25,6 @@ render: function() {
* `sections` (required): Used to generate breadcrumbs. Accepts a single items or an array of items. To make an item a link, wrap it in an array with a relative link (example: `[ '/analytics', __( 'Analytics', 'woo-dash' ) ]` ).
* `onToggle` (required): The toggle callback when "open sidebar" button is clicked.
* `isSidebarOpen`: Boolean describing whether the sidebar is toggled visible.
* `isEmbedded`: Boolean describing if the header is embedded on an existing wp-admin page. False if rendered as part of a full react page.
Note: `onToggle` & `isSidebarOpen` are passed through the `Slot` call, and aren't required when using `<Header />` in section components.

View File

@ -7,7 +7,7 @@ import { decodeEntities } from '@wordpress/utils';
import { Fill } from 'react-slot-fill';
import { isArray, noop } from 'lodash';
import { IconButton } from '@wordpress/components';
import { Link } from 'react-router-dom';
import Link from 'components/link';
import PropTypes from 'prop-types';
/**
@ -16,7 +16,7 @@ import PropTypes from 'prop-types';
import './style.scss';
import WordPressNotices from './wordpress-notices';
const Header = ( { sections, onToggle, isSidebarOpen } ) => {
const Header = ( { sections, onToggle, isSidebarOpen, isEmbedded } ) => {
const _sections = isArray( sections ) ? sections : [ sections ];
const documentTitle = _sections
@ -42,7 +42,9 @@ const Header = ( { sections, onToggle, isSidebarOpen } ) => {
</span>
{ _sections.map( ( section, i ) => {
const sectionPiece = isArray( section ) ? (
<Link to={ section[ 0 ] }> { section[ 1 ] }</Link>
<Link to={ section[ 0 ] } wpAdmin={ isEmbedded }>
{ section[ 1 ] }
</Link>
) : (
section
);
@ -69,10 +71,12 @@ Header.propTypes = {
sections: PropTypes.node.isRequired,
onToggle: PropTypes.func.isRequired,
isSidebarOpen: PropTypes.bool,
isEmbedded: PropTypes.bool,
};
Header.defaultProps = {
onToggle: noop,
isEmbedded: false,
};
export default function( props ) {

View File

@ -9,18 +9,19 @@
box-sizing: border-box;
background: $white;
border-bottom: 1px solid $gray;
padding: 2px 2px 2px 12px;
height: 81px;
.woocommerce-header__breadcrumbs {
font-size: 13px;
span {
display: inline-block;
}
font-weight: normal;
padding: 9px 0 4px 0;
margin-left: 35px;
span + span::before {
content: ' / ';
color: $gray-text;
margin: 0 2px 0 6px;
margin: 0 2px 0 2px;
}
}
}

View File

@ -20,26 +20,79 @@ class WordPressNotices extends Component {
this.updateCount = this.updateCount.bind( this );
this.showNotices = this.showNotices.bind( this );
this.hideNotices = this.hideNotices.bind( this );
this.onToggle = this.onToggle.bind( this );
this.initialize = this.initialize.bind( this );
}
componentDidMount() {
const notices = document.getElementById( 'wpadmin-notice-list' );
let count = notices.children.length - 1; // Subtract 1 for the wp-header-end div, used to show notices
const noticesOpen = notices.classList.contains( 'woocommerce__admin-notice-list-show' );
const primary = document.getElementById( 'woocommerce-layout__primary' );
this.handleWooCommerceEmbedPage();
if ( 'complete' === document.readyState ) {
this.initialize();
} else {
window.addEventListener( 'DOMContentLoaded', this.initialize );
}
}
// Move JITM notices out of the wp toggle
const jitmPlaceholder = notices.getElementsByClassName( 'jetpack-jitm-message' );
if ( jitmPlaceholder.length > 0 ) {
count = count - 1; // Container div
primary.insertAdjacentElement( 'afterbegin', jitmPlaceholder[ 0 ] );
handleWooCommerceEmbedPage() {
if ( ! document.body.classList.contains( 'woocommerce-embed-page' ) ) {
return;
}
// See https://reactjs.org/docs/react-component.html#componentdidmount
this.setState( { count, notices, noticesOpen } ); // eslint-disable-line react/no-did-mount-set-state
// Existing WooCommerce pages already have a designted area for notices, using wp-header-end
// See https://github.com/WordPress/WordPress/blob/f6a37e7d39e2534d05b9e542045174498edfe536/wp-admin/js/common.js#L737
// We want to move most notices, but keep displaying others (like success notice) where they already are
// this renames the element in-line, so we can target it later.
const headerEnds = document.getElementsByClassName( 'wp-header-end' );
for ( let i = 0; i < headerEnds.length; i++ ) {
const headerEnd = headerEnds.item( i );
if ( 'woocommerce-layout__notice-catcher' !== headerEnd.id ) {
headerEnd.className = '';
headerEnd.id = 'wp__notice-list-uncollapsed';
}
}
}
// Move WordPress notifications into the main WooDash body
primary.insertAdjacentElement( 'afterbegin', notices );
initialize() {
const notices = document.getElementById( 'wp__notice-list' );
const noticesOpen = notices.classList.contains( 'woocommerce-layout__notice-list-show' );
// On existing classic WooCommerce pages, screen links like "help" and "screen options" display, and need to be displayed
// along side the notifications expansion.
const screenLinks = document.getElementById( 'screen-meta-links' );
if ( screenLinks ) {
notices.classList.add( 'has-screen-meta-links' );
document
.getElementById( 'woocommerce-layout__notice-list' )
.insertAdjacentElement( 'beforebegin', document.getElementById( 'screen-meta' ) );
document
.getElementById( 'woocommerce-layout__notice-list' )
.insertAdjacentElement( 'beforebegin', screenLinks );
}
const collapsedTargetArea = document.getElementById( 'woocommerce-layout__notice-list' );
const uncollapsedTargetArea =
document.getElementById( 'wp__notice-list-uncollapsed' ) ||
document.getElementById( 'ajax-response' ) ||
document.getElementById( 'woocommerce-layout__notice-list' );
let count = 0;
for ( let i = 0; i <= notices.children.length; i++ ) {
const notice = notices.children[ i ];
if ( ! notice ) {
continue;
} else if ( ! this.shouldCollapseNotice( notice ) ) {
uncollapsedTargetArea.insertAdjacentElement( 'afterend', notice );
} else {
count++;
}
}
count = count - 1; // Remove 1 for `wp-header-end` which is a child of wp__notice-list
this.setState( { count, notices, noticesOpen } );
// Move collapsed WordPress notifications into the main WooDash body
collapsedTargetArea.insertAdjacentElement( 'beforeend', notices );
}
componentWillUnmount() {
@ -56,6 +109,30 @@ class WordPressNotices extends Component {
this.hideNotices();
}
// Some messages should not be displayed in the toggle, like Jetpack JITM messages or update/success messages
shouldCollapseNotice( element ) {
if ( element.classList.contains( 'jetpack-jitm-message' ) ) {
return false;
}
if ( 'woocommerce_errors' === element.id ) {
return false;
}
if ( element.classList.contains( 'hidden' ) ) {
return false;
}
if ( 'message' === element.id && element.classList.contains( 'notice' ) ) {
return false;
}
if ( 'message' === element.id && 'updated' === element.className ) {
return false;
}
return true;
}
updateCount() {
this.setState( { count: this.state.count - 1 } );
}
@ -74,11 +151,13 @@ class WordPressNotices extends Component {
}
showNotices() {
this.state.notices.className = 'woocommerce__admin-notice-list-show';
this.state.notices.classList.add( 'woocommerce-layout__notice-list-show' );
this.state.notices.classList.remove( 'woocommerce-layout__notice-list-hide' );
}
hideNotices() {
this.state.notices.className = 'woocommerce__admin-notice-list-hide';
this.state.notices.classList.add( 'woocommerce-layout__notice-list-hide' );
this.state.notices.classList.remove( 'woocommerce-layout__notice-list-show' );
}
onToggle() {

View File

@ -0,0 +1,47 @@
/** @format */
/**
* External dependencies
*/
import { Component } from '@wordpress/element';
import PropTypes from 'prop-types';
import { Link as RouterLink } from 'react-router-dom';
/**
* Internal dependencies
*/
import { getAdminLink } from 'lib/nav-utils';
class Link extends Component {
render() {
const { children, to, wpAdmin, ...props } = this.props;
if ( this.context.router && ! wpAdmin ) {
return (
<RouterLink to={ to } { ...props }>
{ children }
</RouterLink>
);
}
const path = wpAdmin ? getAdminLink( to ) : getAdminLink( 'admin.php?page=woodash#' + to );
return (
<a href={ path } { ...props }>
{ children }
</a>
);
}
}
Link.propTypes = {
to: PropTypes.string,
wpAdmin: PropTypes.bool,
};
Link.defaultProps = {
wpAdmin: false,
};
Link.contextTypes = {
router: PropTypes.object,
};
export default Link;

View File

@ -0,0 +1,26 @@
/** @format */
/**
* External dependencies
*/
import { APIProvider } from '@wordpress/components';
import { pick } from 'lodash';
import { render } from '@wordpress/element';
import { Provider as SlotFillProvider } from 'react-slot-fill';
/**
* Internal dependencies
*/
import './stylesheets/_wpadmin-reset.scss';
import { EmbedLayout } from './layout';
render(
<APIProvider
{ ...wpApiSettings }
{ ...pick( wp.api, [ 'postTypeRestBaseMapping', 'taxonomyRestBaseMapping' ] ) }
>
<SlotFillProvider>
<EmbedLayout />
</SlotFillProvider>
</APIProvider>,
document.getElementById( 'woocommerce-embedded-root' )
);

View File

@ -11,7 +11,7 @@ import { Provider as SlotFillProvider } from 'react-slot-fill';
* Internal dependencies
*/
import './stylesheets/_wpadmin-reset.scss';
import Layout from './layout';
import { PageLayout } from './layout';
render(
<APIProvider
@ -19,7 +19,7 @@ render(
{ ...pick( wp.api, [ 'postTypeRestBaseMapping', 'taxonomyRestBaseMapping' ] ) }
>
<SlotFillProvider>
<Layout />
<PageLayout />
</SlotFillProvider>
</APIProvider>,
document.getElementById( 'root' )

View File

@ -13,6 +13,7 @@ import Analytics from 'analytics';
import AnalyticsReport from 'analytics/report';
import Dashboard from 'dashboard';
// TODO Remove hasOpenSideBar, as the activity panel will always be closed by default
const getPages = () => {
const pages = [
{

View File

@ -3,15 +3,16 @@
* External dependencies
*/
import classnames from 'classnames';
import { Component } from '@wordpress/element';
import { find } from 'lodash';
import { Component, Fragment } from '@wordpress/element';
import { HashRouter as Router, Route, Switch } from 'react-router-dom';
import { Slot } from 'react-slot-fill';
import PropTypes from 'prop-types';
/**
* Internal dependencies
*/
import './style.scss';
import Header from 'components/header';
import { Controller, getPages } from './controller';
import Notices from './notices';
import Sidebar from './sidebar';
@ -30,26 +31,28 @@ class Layout extends Component {
}
render() {
const { path } = this.props.match;
const page = find( getPages(), { path } );
const className = classnames( {
'woocommerce-layout': true,
'has-visible-sidebar': page.hasOpenSidebar,
'has-hidden-sidebar': ! page.hasOpenSidebar,
// TODO The activity panel will now always be collapsed. We should refactor some of these classnames.
const className = classnames( 'woocommerce-layout', {
'has-visible-sidebar': false,
'has-hidden-sidebar': true,
} );
const headerProps = {
onToggle: this.toggleSidebar,
isSidebarOpen: this.state.isSidebarOpen,
};
const { isEmbeded, ...restProps } = this.props;
return (
<div className={ className }>
<Slot name="header" fillChildProps={ headerProps } />
<div className="woocommerce-layout__primary" id="woocommerce-layout__primary">
<Notices />
<div className="woocommerce-layout__main">
<Controller { ...this.props } />
</div>
{ ! isEmbeded && (
<div className="woocommerce-layout__main">
<Controller { ...restProps } />
</div>
) }
</div>
<Sidebar isOpen={ this.state.isSidebarOpen } onToggle={ this.toggleSidebar } />
@ -58,7 +61,11 @@ class Layout extends Component {
}
}
export default class extends Component {
Layout.propTypes = {
isEmbededLayout: PropTypes.bool,
};
export class PageLayout extends Component {
render() {
return (
<Router>
@ -72,3 +79,14 @@ export default class extends Component {
);
}
}
export class EmbedLayout extends Component {
render() {
return (
<Fragment>
<Header sections={ wcSettings.embedBreadcrumbs } isEmbedded />
<Layout isEmbeded />
</Fragment>
);
}
}

View File

@ -6,7 +6,7 @@ import { Component } from '@wordpress/element';
class Notices extends Component {
render() {
return <div className="woocommerce-layout__notice-list" />;
return <div id="woocommerce-layout__notice-list" className="woocommerce-layout__notice-list" />;
}
}

View File

@ -2,23 +2,16 @@
.woocommerce-layout {
margin: 0;
padding: 0;
min-height: calc(100vh - 32px);
overflow: hidden;
@include breakpoint( '<782px' ) {
min-height: calc(100vh - 46px);
}
}
.woocommerce-header {
min-height: 47px;
min-height: 81px;
margin: 0;
padding: 8px 16px 8px 16px;
}
.woocommerce-layout__primary {
margin: $spacing 0 0 $spacing;
.woocommerce-layout__main {
margin: 0 auto;
max-width: 640px;
@ -28,7 +21,7 @@
.woocommerce-layout.has-visible-sidebar {
display: grid;
grid-template-columns: auto 360px;
grid-template-rows: 47px auto;
grid-template-rows: 81px auto;
grid-gap: 0 $spacing;
@include breakpoint( '<782px' ) {
@ -72,6 +65,7 @@
background: $gray;
border-left: 1px solid $gray;
min-height: calc(100vh - 32px);
z-index: 1000;
@include breakpoint( '<782px' ) {
@include hidden-sidebar;

View File

@ -46,24 +46,80 @@
}
}
.woocommerce-embed-page {
#wpcontent,
#wpbody-content {
overflow-x: initial !important;
}
#wpbody-content .notice {
margin-top: 15px;
}
.wrap {
padding: 20px;
padding-top: 0;
}
#screen-meta {
border-right: 0;
margin: 0;
}
.notice {
margin: 5px 15px 2px;
padding: 1px 12px;
}
#wpbody-content #wp__notice-list {
margin-top: 8px;
}
.woocommerce-layout__primary {
margin: 0;
}
}
.woocommerce-layout * {
box-sizing: border-box;
}
.woocommerce__admin-notice-list-hide {
.woocommerce-layout__notice-list-hide {
opacity: 0;
height: 0;
overflow: hidden;
}
.woocommerce__admin-notice-list-show {
.woocommerce-layout__notice-list-show {
opacity: 1;
height: auto;
transition: all 1s ease-in-out;
margin-top: 0px;
&.has-screen-meta-links {
display: inline-block;
width: 100%;
}
}
.wp-header-end {
margin: 0;
#woocommerce-embedded-root {
@include breakpoint( '<600px' ) {
margin-top: 46px;
}
}
#wp__notice-list-uncollapsed {
visibility: hidden;
margin: -2px 0 0;
}
#wp__notice-list {
padding: 10px;
}
.woocommerce-layout__notice-list .jitm-card {
margin: 5px 15px 2px;
padding: 1px 12px;
}
#wpfooter {

View File

@ -1,5 +1,4 @@
<?php
/**
* Returns true if we are on a JS powered admin page.
*/
@ -11,6 +10,24 @@ function woo_dash_is_admin_page() {
return false;
}
/**
* Returns true if we are on a "classic" (non JS app) powered admin page.
* `wc_get_screen_ids` will also return IDs for extensions that have properly registered themselves.
*/
function woo_dash_is_embed_enabled_wc_page() {
$screen_id = woo_dash_get_current_screen_id();
if ( ! $screen_id ) {
return false;
}
$screens = woo_dash_get_embed_enabled_screen_ids();
if ( in_array( $screen_id, $screens ) ) {
return true;
}
return false;
}
/**
* Register menu pages for the Dashboard and Analytics sections
*/
@ -100,7 +117,7 @@ add_action( 'admin_head', 'woo_dash_link_structure', 20 );
* Load the assets on the Dashboard page
*/
function woo_dash_enqueue_script(){
if ( ! woo_dash_is_admin_page() ) {
if ( ! woo_dash_is_admin_page() && ! woo_dash_is_embed_enabled_wc_page() ) {
return;
}
@ -112,12 +129,15 @@ add_action( 'admin_enqueue_scripts', 'woo_dash_enqueue_script' );
function woo_dash_admin_body_class( $admin_body_class = '' ) {
global $hook_suffix;
if ( ! woo_dash_is_admin_page() ) {
if ( ! woo_dash_is_admin_page() && ! woo_dash_is_embed_enabled_wc_page() ) {
return $admin_body_class;
}
$classes = explode( ' ', trim( $admin_body_class ) );
$classes[] = 'woocommerce-page';
if ( woo_dash_is_embed_enabled_wc_page() ) {
$classes[] = 'woocommerce-embed-page';
}
$admin_body_class = implode( ' ', array_unique( $classes ) );
return " $admin_body_class ";
}
@ -125,29 +145,44 @@ add_filter( 'admin_body_class', 'woo_dash_admin_body_class' );
function woo_dash_admin_before_notices() {
if ( ! woo_dash_is_admin_page() ) {
if ( ! woo_dash_is_admin_page() && ! woo_dash_is_embed_enabled_wc_page() ) {
return;
}
echo '<div class="woocommerce__admin-notice-list-hide" id="wpadmin-notice-list">';
echo '<div class="wp-header-end"></div>'; // https://github.com/WordPress/WordPress/blob/f6a37e7d39e2534d05b9e542045174498edfe536/wp-admin/js/common.js#L737
echo '<div class="woocommerce-layout__notice-list-hide" id="wp__notice-list">';
echo '<div class="wp-header-end" id="woocommerce-layout__notice-catcher"></div>'; // https://github.com/WordPress/WordPress/blob/f6a37e7d39e2534d05b9e542045174498edfe536/wp-admin/js/common.js#L737
}
add_action( 'admin_notices', 'woo_dash_admin_before_notices', 0 );
function woo_dash_admin_after_notices() {
if ( ! woo_dash_is_admin_page() ) {
if ( ! woo_dash_is_admin_page() && ! woo_dash_is_embed_enabled_wc_page() ) {
return;
}
echo '</div>';
}
add_action( 'admin_notices', 'woo_dash_admin_after_notices', PHP_INT_MAX );
// TODO Can we do some URL rewriting so we can figure out which page they are on server side?
function woo_dash_admin_title( $admin_title ) {
if ( ! woo_dash_is_admin_page() ) {
if ( ! woo_dash_is_admin_page() && ! woo_dash_is_embed_enabled_wc_page() ) {
return $admin_title;
}
return sprintf( __( '%1$s &lsaquo; %2$s &#8212; WooCommerce' ), __( 'Dashboard', 'woo-dash' ), get_bloginfo( 'name' ) );
if ( woo_dash_is_embed_enabled_wc_page() ) {
$sections = woo_dash_get_embed_breadcrumbs();
$sections = is_array( $sections ) ? $sections : array( $sections );
$pieces = array();
foreach ( $sections as $section ) {
$pieces[] = is_array( $section ) ? $section[ 1 ] : $section;
}
$pieces = array_reverse( $pieces );
$title = implode( ' &lsaquo; ', $pieces );
} else {
$title = __( 'Dashboard', 'woo-dash' );
}
return sprintf( __( '%1$s &lsaquo; %2$s &#8212; WooCommerce' ), $title, get_bloginfo( 'name' ) );
}
add_filter( 'admin_title', 'woo_dash_admin_title' );
@ -161,3 +196,40 @@ function woo_dash_page(){
</div>
<?php
}
/**
* Set up a div for the header embed to render into.
* The initial contents here are meant as a place loader for when the PHP page initialy loads.
* TODO Icon Placeholders for the ActivityPanel, when we implement the new designs.
*/
function woocommerce_embed_page_header() {
if ( ! woo_dash_is_embed_enabled_wc_page() ) {
return;
}
$sections = woo_dash_get_embed_breadcrumbs();
$sections = is_array( $sections ) ? $sections : array( $sections );
$breadcrumbs = '';
foreach ( $sections as $section ) {
$piece = is_array( $section ) ? '<a href="' . esc_url( admin_url( $section[ 0 ] ) ) .'">' . $section[ 1 ] . '</a>' : $section;
$breadcrumbs .= '<span>' . $piece . '</span>';
}
?>
<div id="woocommerce-embedded-root">
<div class="woocommerce-layout has-hidden-sidebar">
<div class="woocommerce-header is-loading">
<h1 class="woocommerce-header__breadcrumbs">
<span><a href="<?php echo esc_url( admin_url( 'admin.php?page=woodash#/' ) ); ?>">WooCommerce</a></span>
<span><?php echo $breadcrumbs; ?></span>
</h1>
</div>
</div>
<div class="woocommerce-layout__primary" id="woocommerce-layout__primary">
<div id="woocommerce-layout__notice-list" class="woocommerce-layout__notice-list"></div>
</div>
</div>
<?php
}
add_action( 'in_admin_header', 'woocommerce_embed_page_header' );

View File

@ -1,22 +1,32 @@
<?php
/**
* Registers the JS & CSS for the Dashboard
*/
function woo_dash_register_script() {
// Are we displaying the full React app or just embedding the header on a classic screen?
$screen_id = woo_dash_get_current_screen_id();
if ( in_array( $screen_id, woo_dash_get_embed_enabled_screen_ids() ) ) {
$js_entry = 'dist/embedded.js';
$css_entry = 'dist/css/embedded.css';
} else {
$js_entry = 'dist/index.js';
$css_entry = 'dist/css/index.css';
}
wp_register_script(
WOO_DASH_APP,
woo_dash_url( 'dist/index.js' ),
woo_dash_url( $js_entry ),
[ 'wp-components', 'wp-blocks', 'wp-element', 'wp-i18n', 'wp-date' ],
filemtime( woo_dash_dir_path( 'dist/index.js' ) ),
filemtime( woo_dash_dir_path( $js_entry ) ),
true
);
wp_register_style(
WOO_DASH_APP,
woo_dash_url( 'dist/css/style.css' ),
woo_dash_url( $css_entry ),
[ 'wp-edit-blocks' ],
filemtime( woo_dash_dir_path( 'dist/css/style.css' ) )
filemtime( woo_dash_dir_path( $css_entry ) )
);
// Set up the text domain and translations
@ -29,8 +39,10 @@ function woo_dash_register_script() {
// Settings and variables can be passed here for access in the app
$settings = array(
'adminUrl' => admin_url(),
'adminUrl' => admin_url(),
'embedBreadcrumbs' => woo_dash_get_embed_breadcrumbs(),
);
wp_add_inline_script(
WOO_DASH_APP,
'var wcSettings = '. json_encode( $settings ) . ';',
@ -45,7 +57,7 @@ function woo_dash_register_script() {
);
}
add_action( 'init', 'woo_dash_register_script' );
add_action( 'admin_enqueue_scripts', 'woo_dash_register_script' );
/**
* Load plugin text domain for translations.

View File

@ -1,5 +1,4 @@
<?php
/**
* Retrieves the root plugin path.
*
@ -21,3 +20,224 @@ function woo_dash_dir_path( $file = '' ) {
function woo_dash_url( $path ) {
return plugins_url( $path, dirname( __FILE__ ) );
}
/**
* Returns the current screen ID.
* This is slightly different from WP's get_current_screen, in that it attaches an action,
* so certain pages like 'add new' pages can have different breadcrumbs or handling.
* It also catches some more unique dynamic pages like taxonomy/attribute management.
*
* Format: {$current_screen->action}-{$current_screen->action}, or just {$current_screen->action} if no action is found
*
* @return string Current screen ID.
*/
function woo_dash_get_current_screen_id() {
$current_screen = get_current_screen();
if ( ! $current_screen ) {
return false;
}
$current_screen_id = $current_screen->action ? $current_screen->action . '-' . $current_screen->id : $current_screen->id;
if ( ! empty( $_GET['taxonomy' ] ) && ! empty( $_GET['post_type'] ) && 'product' === $_GET['post_type'] ) {
$current_screen_id = 'product_page_product_attributes';
}
return $current_screen_id;
}
/**
* Returns breadcrumbs for the current page.
*
* TODO When merging to core, we should explore a better API for defining breadcrumbs, instead of just defining an array.
*/
function woo_dash_get_embed_breadcrumbs() {
$current_screen_id = woo_dash_get_current_screen_id();
// If a page has a tab, we can append that to the screen ID and show another pagination level
$pages_with_tabs = array(
'wc-reports' => 'orders',
'wc-settings' => 'general',
'wc-status' => 'status',
);
$tab = '';
if ( ! empty( $_GET['page' ] ) ) {
if ( in_array( $_GET['page'], array_keys( $pages_with_tabs ) ) ) {
$tab = ! empty( $_GET['tab'] ) ? $_GET['tab'] . '-' : $pages_with_tabs[ $_GET['page'] ] . '-';
}
}
$breadcrumbs = apply_filters( 'woo_dash_get_breadcrumbs', array(
'edit-shop_order' => __( 'Orders', 'woo-dash' ),
'add-shop_order' => array(
array( '/edit.php?post_type=shop_order', __( 'Orders', 'woo-dash' ) ),
__( 'Add New', 'woo-dash' )
),
'shop_order' => array(
array( '/edit.php?post_type=shop_order', __( 'Orders', 'woo-dash' ) ),
__( 'Edit Order', 'woo-dash' )
),
'edit-shop_coupon' => __( 'Coupons', 'woo-dash' ),
'add-shop_coupon' => array(
array( 'edit.php?post_type=shop_coupon', __( 'Coupons', 'woo-dash' ) ),
__( 'Add New', 'woo-dash' )
),
'shop_coupon' => array(
array( 'edit.php?post_type=shop_coupon', __( 'Coupons', 'woo-dash' ) ),
__( 'Edit Coupon', 'woo-dash' )
),
'woocommerce_page_wc-reports' => array(
array( 'admin.php?page=wc-reports', __( 'Reports', 'woo-dash' ) )
),
'orders-woocommerce_page_wc-reports' => array(
array( 'admin.php?page=wc-reports', __( 'Reports', 'woo-dash' ) ),
__( 'Orders', 'woo-dash' )
),
'customers-woocommerce_page_wc-reports' => array(
array( 'admin.php?page=wc-reports', __( 'Reports', 'woo-dash' ) ),
__( 'Customers', 'woo-dash' )
),
'stock-woocommerce_page_wc-reports' => array(
array( 'admin.php?page=wc-reports', __( 'Reports', 'woo-dash' ) ),
__( 'Stock', 'woo-dash' )
),
'taxes-woocommerce_page_wc-reports' => array(
array( 'admin.php?page=wc-reports', __( 'Reports', 'woo-dash' ) ),
__( 'Taxes', 'woo-dash' )
),
'woocommerce_page_wc-settings' => array(
array( 'admin.php?page=wc-settings', __( 'Settings', 'woo-dash' ) )
),
'general-woocommerce_page_wc-settings' => array(
array( 'admin.php?page=wc-settings', __( 'Settings', 'woo-dash' ) ),
__( 'General', 'woo-dash' ),
),
'products-woocommerce_page_wc-settings' => array(
array( 'admin.php?page=wc-settings', __( 'Settings', 'woo-dash' ) ),
__( 'Products', 'woo-dash' ),
),
'tax-woocommerce_page_wc-settings' => array(
array( 'admin.php?page=wc-settings', __( 'Settings', 'woo-dash' ) ),
__( 'Tax', 'woo-dash' ),
),
'shipping-woocommerce_page_wc-settings' => array(
array( 'admin.php?page=wc-settings', __( 'Settings', 'woo-dash' ) ),
__( 'Shipping', 'woo-dash' ),
),
'checkout-woocommerce_page_wc-settings' => array(
array( 'admin.php?page=wc-settings', __( 'Settings', 'woo-dash' ) ),
__( 'Payments', 'woo-dash' ),
),
'email-woocommerce_page_wc-settings' => array(
array( 'admin.php?page=wc-settings', __( 'Settings', 'woo-dash' ) ),
__( 'Emails', 'woo-dash' ),
),
'advanced-woocommerce_page_wc-settings' => array(
array( 'admin.php?page=wc-settings', __( 'Settings', 'woo-dash' ) ),
__( 'Advanced', 'woo-dash' ),
),
'woocommerce_page_wc-status' => array(
__( 'Status', 'woo-dash' ),
),
'status-woocommerce_page_wc-status' => array(
array( 'admin.php?page=wc-status', __( 'Status', 'woo-dash' ) ),
__( 'System Status', 'woo-dash' ),
),
'tools-woocommerce_page_wc-status' => array(
array( 'admin.php?page=wc-status', __( 'Status', 'woo-dash' ) ),
__( 'Tools', 'woo-dash' ),
),
'logs-woocommerce_page_wc-status' => array(
array( 'admin.php?page=wc-status', __( 'Status', 'woo-dash' ) ),
__( 'Logs', 'woo-dash' ),
),
'connect-woocommerce_page_wc-status' => array(
array( 'admin.php?page=wc-status', __( 'Status', 'woo-dash' ) ),
__( 'WooCommerce Services Status', 'woo-dash' ),
),
'woocommerce_page_wc-addons' => __( 'Extensions', 'woo-dash' ),
'edit-product' => __( 'Products', 'woo-dash' ),
'product_page_product_importer' => array(
array( 'edit.php?post_type=product', __( 'Products', 'woo-dash' ) ),
__( 'Import', 'woo-dash' ),
),
'product_page_product_exporter' => array(
array( 'edit.php?post_type=product', __( 'Products', 'woo-dash' ) ),
__( 'Export', 'woo-dash' ),
),
'add-product' => array(
array( 'edit.php?post_type=product', __( 'Products', 'woo-dash' ) ),
__( 'Add New', 'woo-dash' ),
),
'product' => array(
array( 'edit.php?post_type=product', __( 'Products', 'woo-dash' ) ),
__( 'Edit Product', 'woo-dash' ),
),
'edit-product_cat' => array(
array( 'edit.php?post_type=product', __( 'Products', 'woo-dash' ) ),
__( 'Categories', 'woo-dash' ),
),
'edit-product_tag' => array(
array( 'edit.php?post_type=product', __( 'Products', 'woo-dash' ) ),
__( 'Tags', 'woo-dash' ),
),
'product_page_product_attributes' => array(
array( 'edit.php?post_type=product', __( 'Products', 'woo-dash' ) ),
__( 'Attributes', 'woo-dash' ),
),
) );
if ( ! empty ( $breadcrumbs[ $tab . $current_screen_id ] ) ) {
return $breadcrumbs[ $tab . $current_screen_id ];
} else if ( ! empty( $breadcrumbs[ $current_screen_id ] ) ) {
return $breadcrumbs[ $current_screen_id ];
} else {
return '';
}
}
/**
* `woo_dash_get_embed_enabled_screen_ids`, `woo_dash_get_embed_enabled_plugin_screen_ids`,
* `woo_dash_get_embed_enabled_screen_ids` should be considered temporary functions for the feature plugin.
* This is separate from WC's screen_id functions so that extensions explictly have to opt-in to the feature plugin.
* TODO When merging to core, we should explore a better API for opting into the new header for extensions.
*/
function woo_dash_get_embed_enabled_core_screen_ids() {
$screens = array(
'edit-shop_order',
'shop_order',
'add-shop_order',
'edit-shop_coupon',
'shop_coupon',
'add-shop_coupon',
'woocommerce_page_wc-reports',
'woocommerce_page_wc-settings',
'woocommerce_page_wc-status',
'woocommerce_page_wc-addons',
'edit-product',
'product_page_product_importer',
'product_page_product_exporter',
'add-product',
'product',
'edit-product_cat',
'edit-product_tag',
'product_page_product_attributes',
);
return apply_filters( 'woo_dash_get_embed_enabled_core_screens_ids', $screens );
}
/**
* If any extensions want to show the new header, they can register their screen ids.
* Separate so extensions can register support for the feature plugin separately.
*/
function woo_dash_get_embed_enabled_plugin_screen_ids() {
$screens = array();
return apply_filters( 'woo_dash_get_embed_enabled_plugin_screens_ids', $screens );
}
/**
* Returns core and plugin screen IDs for a list of screens the new header should be enabled on.
*/
function woo_dash_get_embed_enabled_screen_ids() {
return array_merge( woo_dash_get_embed_enabled_core_screen_ids(), woo_dash_get_embed_enabled_plugin_screen_ids() );
}

View File

@ -4975,7 +4975,6 @@
},
"eslint-plugin-wordpress": {
"version": "git://github.com/WordPress-Coding-Standards/eslint-plugin-wordpress.git#1774343f6226052a46b081e01db3fca8793cc9f1",
"from": "git://github.com/WordPress-Coding-Standards/eslint-plugin-wordpress.git#1774343f6226052a46b081e01db3fca8793cc9f1",
"dev": true,
"requires": {
"eslint-plugin-i18n": "1.2.0",
@ -7248,7 +7247,6 @@
},
"gutenberg": {
"version": "github:WordPress/gutenberg#9221170ee6604f21818279230457479a0349187e",
"from": "gutenberg@github:WordPress/gutenberg#9221170ee6604f21818279230457479a0349187e",
"dev": true,
"requires": {
"@wordpress/a11y": "1.0.6",
@ -13073,7 +13071,6 @@
},
"prettier": {
"version": "github:automattic/calypso-prettier#c56b42511ec98ba6d8f72b6c391e0a626e90f531",
"from": "prettier@github:automattic/calypso-prettier#c56b42511ec98ba6d8f72b6c391e0a626e90f531",
"dev": true,
"requires": {
"babel-code-frame": "7.0.0-beta.3",

View File

@ -75,6 +75,7 @@ const webpackConfig = {
mode: NODE_ENV,
entry: {
index: './client/index.js',
embedded: './client/embedded.js',
},
output: {
path: path.resolve( 'dist' ),
@ -113,7 +114,7 @@ const webpackConfig = {
modules: [ path.join( __dirname, 'client' ), 'node_modules' ],
},
plugins: [
new ExtractTextPlugin( 'css/style.css' ),
new ExtractTextPlugin( 'css/[name].css' ),
],
};