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:
parent
99ac7728cd
commit
bf80e5c649
|
@ -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() {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 ) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
|
@ -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' )
|
||||
);
|
|
@ -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' )
|
||||
|
|
|
@ -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 = [
|
||||
{
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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" />;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 ‹ %2$s — 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( ' ‹ ', $pieces );
|
||||
} else {
|
||||
$title = __( 'Dashboard', 'woo-dash' );
|
||||
}
|
||||
|
||||
return sprintf( __( '%1$s ‹ %2$s — 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' );
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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() );
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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' ),
|
||||
],
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue