Merge branch 'master' into update/refactor-main-file

This commit is contained in:
Mike Jolley 2019-05-14 19:21:32 +01:00
commit 2752605f54
11 changed files with 1469 additions and 442 deletions

View File

@ -0,0 +1,134 @@
WooCommerce Admin Page Controller
=================================
Pages rendered with React and pages that include the WooCommmerce Admin header (containing the Activity Panel) need to be registered with the WooCommerce Admin Page Controller.
This is the API you will use to add your own React-powered page, or to include the WooCommerce Admin header on your plugin pages.
### Connecting a PHP-powered Page
To show the WooCommerce Admin header on existing PHP-powered admin pages (most plugin pages), use the `wc_admin_connect_page()` function.
Connecting pages uses five parameters to `wc_admin_connect_page()`:
* `id` - Identifies the page with the controller. Required.
* `parent` - Denotes the page as a child of `parent`. Used for breadcrumbs. Optional.
* `screen_id` - Corresponds to [`WC_Admin_Page_Controller::get_current_screen_id()`](../includes/page-controller/class-wc-admin-page-controller.php#L219) to determine the current page. Required.
* `title` - Page title. Used to build breadcrumbs. String or array of breadcrumb pieces. Required.
* `path` - Page path (relative). Used for linking breadcrumb pieces when this page is a `parent`. Optional.
#### Examples
```php
// WooCommerce > Settings > General (default tab).
wc_admin_connect_page(
array(
'id' => 'woocommerce-settings',
'screen_id' => 'woocommerce_page_wc-settings-general',
'title' => array(
__( 'Settings', 'woocommerce-admin' ),
__( 'General', 'woocommerce-admin' ),
),
'path' => add_query_arg( 'page', 'wc-settings', 'admin.php' ),
)
);
```
The `WooCommerce > Settings > General` example shows how to set up multiple breadcrumb pieces for a page. When building the breadcrumbs, WooCommerce will attach a link to `path` to the first piece in the `title` array. All subsequent pieces are plain text (not linked).
```php
// WooCommerce > Settings > Payments.
wc_admin_connect_page(
array(
'id' => 'woocommerce-settings-payments',
'parent' => 'woocommerce-settings',
'screen_id' => 'woocommerce_page_wc-settings-checkout',
'title' => __( 'Payments', 'woocommerce-admin' ),
'path' => add_query_arg(
array(
'page' => 'wc-settings',
'tab' => 'checkout',
),
'admin.php'
),
)
);
// WooCommerce > Orders.
wc_admin_connect_page(
array(
'id' => 'woocommerce-orders',
'screen_id' => 'edit-shop_order',
'title' => __( 'Orders', 'woocommerce-admin' ),
'path' => add_query_arg( 'post_type', 'shop_order', 'edit.php' ),
)
);
```
### Determining Screen ID
WooCommerce Admin implements it's own version of `get_current_screen()` to allow for more precise identification of admin pages.
Some screen ID formats that the function will generate are:
* - `{$current_screen->action}-{$current_screen->action}-tab-section`
* - `{$current_screen->action}-{$current_screen->action}-tab`
* - `{$current_screen->action}-{$current_screen->action}` if no tab is present
* - `{$current_screen->action}` if no action or tab is present
WooCommerce Admin can recognize WooCommerce pages that have both tabs and sub sections. For example, `woocommerce_page_wc-settings-products-inventory` is the `WooCommerce > Settings > Products > Inventory` page.
If your plugin adds new pages with tabs and sub sections, use the `wc_admin_pages_with_tabs` and `wc_admin_page_tab_sections` filters to have WooCommerce Admin generate accurate screen IDs for them.
You can also use the `wc_admin_current_screen_id` filter to make any changes necessary to the behavior.
### Registering a React-powered Page
Registering a React-powered page is similar to connecting a PHP page, but with some key differences. Registering pages will automatically create WordPress menu items for them, with the appropriate hierarchy based on `parent`.
Register pages with `wc_admin_register_page()` using these parameters:
* `id` - Identifies the page with the controller. Required.
* `parent` - Denotes the page as a child of `parent`. Used for breadcrumbs. Optional.
* `title` - Page title. Used to build breadcrumbs. String or array of breadcrumb pieces. Required.
* `path` - Page path (relative to `#wc-admin`). Used for identifying this page and for linking breadcrumb pieces when this page is a `parent`. Required.
* `capability` - User capability needed to access this page. Optional (defaults to `manage_options`).
* `icon` - Dashicons helper class or base64-encoded SVG. Optional.
* `position` - Menu item position for parent pages. Optional. See: `add_menu_page()`.
#### Example - Adding a New Analytics Report
Add our new report using the appropriate filter:
```javascript
import { addFilter } from '@wordpress/hooks';
addFilter( 'woocommerce_admin_reports_list', 'my-namespace', ( reports ) => {
reports.push( {
report: 'example',
title: __( 'Example', 'my-textdomain' ),
component: ExampleReportComponent,
} );
return reports;
} );
```
Register the report page with the controller:
```php
wc_admin_register_page(
array(
'id' => 'woocommerce-analytics-example',
'title' => __( 'Example', 'my-textdomain' ),
'parent' => 'woocommerce-analytics',
'path' => '/analytics/example',
)
);
```
### Further Reading
* Check out the [`WC_Admin_Page_Controller`](../includes/page-controller/class-wc-admin-page-controller.php) class.
* See how we're [connecting existing WooCommerce pages](../includes/page-controller/connect-existing-pages.php).
* See how we're [registering Analytics Reports](../includes/features/analytics/class-wc-admin-analytics.php#L75).

View File

@ -6,38 +6,14 @@
* @package Woocommerce Admin * @package Woocommerce Admin
*/ */
if ( ! function_exists( 'wc_admin_register_page' ) ) {
/**
* Add a single page to a given parent top-level-item.
*
* @param array $options {
* Array describing the menu item.
*
* @type string $title Menu title
* @type string $parent Parent path or menu ID
* @type string $path Path for this page, full path in app context; ex /analytics/report
* }
*/
function wc_admin_register_page( $options ) {
$defaults = array(
'parent' => '/analytics',
);
$options = wp_parse_args( $options, $defaults );
add_submenu_page(
'/' === $options['parent'][0] ? "wc-admin#{$options['parent']}" : $options['parent'],
$options['title'],
$options['title'],
'manage_options',
"wc-admin#{$options['path']}",
array( 'WC_Admin_Loader', 'page_wrapper' )
);
}
}
/** /**
* WC_Admin_Loader Class. * WC_Admin_Loader Class.
*/ */
class WC_Admin_Loader { class WC_Admin_Loader {
/**
* App entry point.
*/
const APP_ENTRY_POINT = 'wc-admin';
/** /**
* Class instance. * Class instance.
@ -84,7 +60,7 @@ class WC_Admin_Loader {
add_action( 'admin_notices', array( 'WC_Admin_Loader', 'inject_after_notices' ), PHP_INT_MAX ); add_action( 'admin_notices', array( 'WC_Admin_Loader', 'inject_after_notices' ), PHP_INT_MAX );
// priority is 20 to run after https://github.com/woocommerce/woocommerce/blob/a55ae325306fc2179149ba9b97e66f32f84fdd9c/includes/admin/class-wc-admin-menus.php#L165. // priority is 20 to run after https://github.com/woocommerce/woocommerce/blob/a55ae325306fc2179149ba9b97e66f32f84fdd9c/includes/admin/class-wc-admin-menus.php#L165.
add_action( 'admin_head', array( 'WC_Admin_Loader', 'update_link_structure' ), 20 ); add_action( 'admin_head', array( 'WC_Admin_Loader', 'remove_app_entry_page_menu_item' ), 20 );
} }
/** /**
@ -145,6 +121,9 @@ class WC_Admin_Loader {
* Class loader for enabled WooCommerce Admin features/sections. * Class loader for enabled WooCommerce Admin features/sections.
*/ */
public static function load_features() { public static function load_features() {
require_once WC_ADMIN_ABSPATH . 'includes/page-controller/class-wc-admin-page-controller.php';
require_once WC_ADMIN_ABSPATH . 'includes/page-controller/page-controller-functions.php';
$features = self::get_features(); $features = self::get_features();
foreach ( $features as $feature ) { foreach ( $features as $feature ) {
$feature = strtolower( $feature ); $feature = strtolower( $feature );
@ -163,28 +142,23 @@ class WC_Admin_Loader {
* @todo The entry point for the embed needs moved to this class as well. * @todo The entry point for the embed needs moved to this class as well.
*/ */
public static function register_page_handler() { public static function register_page_handler() {
$page_title = null; wc_admin_register_page(
$menu_title = null; array(
'id' => 'woocommerce-dashboard', // Expected to be overridden if dashboard is enabled.
if ( self::is_feature_enabled( 'analytics-dashboard' ) ) { 'parent' => 'woocommerce',
$page_title = __( 'WooCommerce Dashboard', 'woocommerce-admin' ); 'title' => null,
$menu_title = __( 'Dashboard', 'woocommerce-admin' ); 'path' => self::APP_ENTRY_POINT,
} )
add_submenu_page(
'woocommerce',
$page_title,
$menu_title,
'manage_options',
'wc-admin',
array( 'WC_Admin_Loader', 'page_wrapper' )
); );
// Connect existing WooCommerce pages.
require_once WC_ADMIN_ABSPATH . 'includes/page-controller/connect-existing-pages.php';
} }
/** /**
* Update the WooCommerce menu structure to make our main dashboard/handler the top level link for 'WooCommerce'. * Remove the menu item for the app entry point page.
*/ */
public static function update_link_structure() { public static function remove_app_entry_page_menu_item() {
global $submenu; global $submenu;
// User does not have capabilites to see the submenu. // User does not have capabilites to see the submenu.
if ( ! current_user_can( 'manage_woocommerce' ) || empty( $submenu['woocommerce'] ) ) { if ( ! current_user_can( 'manage_woocommerce' ) || empty( $submenu['woocommerce'] ) ) {
@ -193,7 +167,8 @@ class WC_Admin_Loader {
$wc_admin_key = null; $wc_admin_key = null;
foreach ( $submenu['woocommerce'] as $submenu_key => $submenu_item ) { foreach ( $submenu['woocommerce'] as $submenu_key => $submenu_item ) {
if ( 'wc-admin' === $submenu_item[2] ) { // Our app entry page menu item has no title.
if ( is_null( $submenu_item[0] ) && self::APP_ENTRY_POINT === $submenu_item[2] ) {
$wc_admin_key = $submenu_key; $wc_admin_key = $submenu_key;
break; break;
} }
@ -203,11 +178,7 @@ class WC_Admin_Loader {
return; return;
} }
$menu = $submenu['woocommerce'][ $wc_admin_key ];
// Move menu item to top of array.
unset( $submenu['woocommerce'][ $wc_admin_key ] ); unset( $submenu['woocommerce'][ $wc_admin_key ] );
array_unshift( $submenu['woocommerce'], $menu );
} }
/** /**
@ -351,11 +322,7 @@ class WC_Admin_Loader {
* Returns true if we are on a JS powered admin page. * Returns true if we are on a JS powered admin page.
*/ */
public static function is_admin_page() { public static function is_admin_page() {
$current_screen = get_current_screen(); return wc_admin_is_registered_page();
if ( '_page_wc-admin' === substr( $current_screen->id, -14 ) ) {
return true;
}
return false;
} }
/** /**
@ -364,248 +331,14 @@ class WC_Admin_Loader {
* @todo See usage in `admin.php`. This needs refactored and implemented properly in core. * @todo See usage in `admin.php`. This needs refactored and implemented properly in core.
*/ */
public static function is_embed_page() { public static function is_embed_page() {
$is_embed = false; return wc_admin_is_connected_page();
$screen_id = self::get_current_screen_id();
if ( ! $screen_id ) {
return false;
}
$screens = self::get_embed_enabled_screen_ids();
if ( in_array( $screen_id, $screens, true ) ) {
$is_embed = true;
}
return apply_filters( 'woocommerce_page_is_embed_page', $is_embed );
}
/**
* 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
*
* @todo Refactor: https://github.com/woocommerce/woocommerce-admin/issues/1432.
* @return string Current screen ID.
*/
public static function 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;
}
/**
* `WC_Admin_Loader::get_embed_enabled_screen_ids`, `WC_Admin_Loader::get_embed_enabled_plugin_screen_ids`,
* `WC_Admin_Loader::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 Refactor: https://github.com/woocommerce/woocommerce-admin/issues/1432.
*/
public static function 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( 'wc_admin_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.
*
* @todo Refactor: https://github.com/woocommerce/woocommerce-admin/issues/1432.
*/
public static function get_embed_enabled_plugin_screen_ids() {
$screens = array();
return apply_filters( 'wc_admin_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.
*/
public static function get_embed_enabled_screen_ids() {
return array_merge( self::get_embed_enabled_core_screen_ids(), self::get_embed_enabled_plugin_screen_ids() );
} }
/** /**
* Returns breadcrumbs for the current page. * Returns breadcrumbs for the current page.
*
* @todo Refactor: https://github.com/woocommerce/woocommerce-admin/issues/1432.
*/ */
private static function get_embed_breadcrumbs() { private static function get_embed_breadcrumbs() {
$current_screen_id = self::get_current_screen_id(); return wc_admin_get_breadcrumbs();
// 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 = '';
$get_tab = isset( $_GET['tab'] ) ? sanitize_text_field( wp_unslash( $_GET['tab'] ) ) : '';
if ( isset( $_GET['page'] ) ) {
$page = sanitize_text_field( wp_unslash( $_GET['page'] ) );
if ( in_array( $page, array_keys( $pages_with_tabs ) ) ) {
$tab = ! empty( $get_tab ) ? $get_tab . '-' : $pages_with_tabs[ $page ] . '-';
}
}
$breadcrumbs = apply_filters(
'wc_admin_get_breadcrumbs',
array(
'edit-shop_order' => __( 'Orders', 'woocommerce-admin' ),
'add-shop_order' => array(
array( '/edit.php?post_type=shop_order', __( 'Orders', 'woocommerce-admin' ) ),
__( 'Add New', 'woocommerce-admin' ),
),
'shop_order' => array(
array( '/edit.php?post_type=shop_order', __( 'Orders', 'woocommerce-admin' ) ),
__( 'Edit Order', 'woocommerce-admin' ),
),
'edit-shop_coupon' => __( 'Coupons', 'woocommerce-admin' ),
'add-shop_coupon' => array(
array( 'edit.php?post_type=shop_coupon', __( 'Coupons', 'woocommerce-admin' ) ),
__( 'Add New', 'woocommerce-admin' ),
),
'shop_coupon' => array(
array( 'edit.php?post_type=shop_coupon', __( 'Coupons', 'woocommerce-admin' ) ),
__( 'Edit Coupon', 'woocommerce-admin' ),
),
'woocommerce_page_wc-reports' => array(
array( 'admin.php?page=wc-reports', __( 'Reports', 'woocommerce-admin' ) ),
),
'orders-woocommerce_page_wc-reports' => array(
array( 'admin.php?page=wc-reports', __( 'Reports', 'woocommerce-admin' ) ),
__( 'Orders', 'woocommerce-admin' ),
),
'customers-woocommerce_page_wc-reports' => array(
array( 'admin.php?page=wc-reports', __( 'Reports', 'woocommerce-admin' ) ),
__( 'Customers', 'woocommerce-admin' ),
),
'stock-woocommerce_page_wc-reports' => array(
array( 'admin.php?page=wc-reports', __( 'Reports', 'woocommerce-admin' ) ),
__( 'Stock', 'woocommerce-admin' ),
),
'taxes-woocommerce_page_wc-reports' => array(
array( 'admin.php?page=wc-reports', __( 'Reports', 'woocommerce-admin' ) ),
__( 'Taxes', 'woocommerce-admin' ),
),
'woocommerce_page_wc-settings' => array(
array( 'admin.php?page=wc-settings', __( 'Settings', 'woocommerce-admin' ) ),
),
'general-woocommerce_page_wc-settings' => array(
array( 'admin.php?page=wc-settings', __( 'Settings', 'woocommerce-admin' ) ),
__( 'General', 'woocommerce-admin' ),
),
'products-woocommerce_page_wc-settings' => array(
array( 'admin.php?page=wc-settings', __( 'Settings', 'woocommerce-admin' ) ),
__( 'Products', 'woocommerce-admin' ),
),
'tax-woocommerce_page_wc-settings' => array(
array( 'admin.php?page=wc-settings', __( 'Settings', 'woocommerce-admin' ) ),
__( 'Tax', 'woocommerce-admin' ),
),
'shipping-woocommerce_page_wc-settings' => array(
array( 'admin.php?page=wc-settings', __( 'Settings', 'woocommerce-admin' ) ),
__( 'Shipping', 'woocommerce-admin' ),
),
'checkout-woocommerce_page_wc-settings' => array(
array( 'admin.php?page=wc-settings', __( 'Settings', 'woocommerce-admin' ) ),
__( 'Payments', 'woocommerce-admin' ),
),
'email-woocommerce_page_wc-settings' => array(
array( 'admin.php?page=wc-settings', __( 'Settings', 'woocommerce-admin' ) ),
__( 'Emails', 'woocommerce-admin' ),
),
'advanced-woocommerce_page_wc-settings' => array(
array( 'admin.php?page=wc-settings', __( 'Settings', 'woocommerce-admin' ) ),
__( 'Advanced', 'woocommerce-admin' ),
),
'woocommerce_page_wc-status' => array(
__( 'Status', 'woocommerce-admin' ),
),
'status-woocommerce_page_wc-status' => array(
array( 'admin.php?page=wc-status', __( 'Status', 'woocommerce-admin' ) ),
__( 'System Status', 'woocommerce-admin' ),
),
'tools-woocommerce_page_wc-status' => array(
array( 'admin.php?page=wc-status', __( 'Status', 'woocommerce-admin' ) ),
__( 'Tools', 'woocommerce-admin' ),
),
'logs-woocommerce_page_wc-status' => array(
array( 'admin.php?page=wc-status', __( 'Status', 'woocommerce-admin' ) ),
__( 'Logs', 'woocommerce-admin' ),
),
'connect-woocommerce_page_wc-status' => array(
array( 'admin.php?page=wc-status', __( 'Status', 'woocommerce-admin' ) ),
__( 'WooCommerce Services Status', 'woocommerce-admin' ),
),
'woocommerce_page_wc-addons' => __( 'Extensions', 'woocommerce-admin' ),
'edit-product' => __( 'Products', 'woocommerce-admin' ),
'product_page_product_importer' => array(
array( 'edit.php?post_type=product', __( 'Products', 'woocommerce-admin' ) ),
__( 'Import', 'woocommerce-admin' ),
),
'product_page_product_exporter' => array(
array( 'edit.php?post_type=product', __( 'Products', 'woocommerce-admin' ) ),
__( 'Export', 'woocommerce-admin' ),
),
'add-product' => array(
array( 'edit.php?post_type=product', __( 'Products', 'woocommerce-admin' ) ),
__( 'Add New', 'woocommerce-admin' ),
),
'product' => array(
array( 'edit.php?post_type=product', __( 'Products', 'woocommerce-admin' ) ),
__( 'Edit Product', 'woocommerce-admin' ),
),
'edit-product_cat' => array(
array( 'edit.php?post_type=product', __( 'Products', 'woocommerce-admin' ) ),
__( 'Categories', 'woocommerce-admin' ),
),
'edit-product_tag' => array(
array( 'edit.php?post_type=product', __( 'Products', 'woocommerce-admin' ) ),
__( 'Tags', 'woocommerce-admin' ),
),
'product_page_product_attributes' => array(
array( 'edit.php?post_type=product', __( 'Products', 'woocommerce-admin' ) ),
__( 'Attributes', 'woocommerce-admin' ),
),
)
);
if ( ! empty( $breadcrumbs[ $tab . $current_screen_id ] ) ) {
return $breadcrumbs[ $tab . $current_screen_id ];
} elseif ( ! empty( $breadcrumbs[ $current_screen_id ] ) ) {
return $breadcrumbs[ $current_screen_id ];
} else {
return '';
}
} }
/** /**
@ -617,9 +350,7 @@ class WC_Admin_Loader {
?> ?>
<span> <span>
<?php if ( is_array( $section ) ) : ?> <?php if ( is_array( $section ) ) : ?>
<a href="<?php echo esc_url( admin_url( $section[0] ) ); ?>"> <a href="<?php echo esc_url( admin_url( $section[0] ) ); ?>"><?php echo esc_html( $section[1] ); ?></a>
<?php echo esc_html( $section[1] ); ?>
</a>
<?php else : ?> <?php else : ?>
<?php echo esc_html( $section ); ?> <?php echo esc_html( $section ); ?>
<?php endif; ?> <?php endif; ?>
@ -643,7 +374,9 @@ class WC_Admin_Loader {
<div class="woocommerce-layout"> <div class="woocommerce-layout">
<div class="woocommerce-layout__header is-embed-loading"> <div class="woocommerce-layout__header is-embed-loading">
<h1 class="woocommerce-layout__header-breadcrumbs"> <h1 class="woocommerce-layout__header-breadcrumbs">
<span><a href="<?php echo esc_url( admin_url( 'admin.php?page=wc-admin#/' ) ); ?>">WooCommerce</a></span> <span>
<a href="<?php echo esc_url( admin_url( 'admin.php?page=wc-admin#/' ) ); ?>"><?php esc_html_e( 'WooCommerce', 'woocommerce-admin' ); ?></a>
</span>
<?php foreach ( $sections as $section ) : ?> <?php foreach ( $sections as $section ) : ?>
<?php self::output_breadcrumbs( $section ); ?> <?php self::output_breadcrumbs( $section ); ?>
<?php endforeach; ?> <?php endforeach; ?>
@ -731,9 +464,7 @@ class WC_Admin_Loader {
return $admin_title; return $admin_title;
} }
if ( self::is_embed_page() ) {
$sections = self::get_embed_breadcrumbs(); $sections = self::get_embed_breadcrumbs();
$sections = is_array( $sections ) ? $sections : array( $sections );
$pieces = array(); $pieces = array();
foreach ( $sections as $section ) { foreach ( $sections as $section ) {
@ -742,11 +473,9 @@ class WC_Admin_Loader {
$pieces = array_reverse( $pieces ); $pieces = array_reverse( $pieces );
$title = implode( ' &lsaquo; ', $pieces ); $title = implode( ' &lsaquo; ', $pieces );
} else {
$title = __( 'Dashboard', 'woocommerce-admin' );
}
/* translators: %1$s: updated title, %2$s: blog info name */ /* translators: %1$s: updated title, %2$s: blog info name */
return sprintf( __( '%1$s &lsaquo; %2$s &#8212; WooCommerce', 'woocommerce-admin' ), $title, get_bloginfo( 'name' ) ); return sprintf( __( '%1$s &lsaquo; %2$s', 'woocommerce-admin' ), $title, get_bloginfo( 'name' ) );
} }
/** /**

View File

@ -337,23 +337,28 @@ class WC_Admin_Reports_Orders_Data_Store extends WC_Admin_Reports_Data_Store imp
} }
/** /**
* Get customer data from order IDs. * Get customer data from Order data.
* *
* @param array $orders Array of orders. * @param array $orders Array of orders data.
* @return array * @return array
*/ */
protected function get_customers_by_orders( $orders ) { protected function get_customers_by_orders( $orders ) {
global $wpdb; global $wpdb;
$customer_lookup_table = $wpdb->prefix . 'wc_customer_lookup';
$customer_lookup_table = $wpdb->prefix . 'wc_customer_lookup';
$customer_ids = array(); $customer_ids = array();
foreach ( $orders as $order ) { foreach ( $orders as $order ) {
if ( $order['customer_id'] ) { if ( $order['customer_id'] ) {
$customer_ids[] = $order['customer_id']; $customer_ids[] = intval( $order['customer_id'] );
} }
} }
$customer_ids = implode( ',', $customer_ids );
if ( empty( $customer_ids ) ) {
return array();
}
$customer_ids = implode( ',', $customer_ids );
$customers = $wpdb->get_results( $customers = $wpdb->get_results(
"SELECT * FROM {$customer_lookup_table} WHERE customer_id IN ({$customer_ids})", "SELECT * FROM {$customer_lookup_table} WHERE customer_id IN ({$customer_ids})",
ARRAY_A ARRAY_A

View File

@ -10,6 +10,11 @@
* Contains backend logic for the dashboard feature. * Contains backend logic for the dashboard feature.
*/ */
class WC_Admin_Analytics_Dashboard { class WC_Admin_Analytics_Dashboard {
/**
* Menu slug.
*/
const MENU_SLUG = 'wc-admin';
/** /**
* Class instance. * Class instance.
* *
@ -33,6 +38,9 @@ class WC_Admin_Analytics_Dashboard {
public function __construct() { public function __construct() {
add_filter( 'woocommerce_component_settings_preload_endpoints', array( $this, 'add_preload_endpoints' ) ); add_filter( 'woocommerce_component_settings_preload_endpoints', array( $this, 'add_preload_endpoints' ) );
add_filter( 'wc_admin_get_user_data_fields', array( $this, 'add_user_data_fields' ) ); add_filter( 'wc_admin_get_user_data_fields', array( $this, 'add_user_data_fields' ) );
add_action( 'admin_menu', array( $this, 'register_page' ) );
// priority is 20 to run after https://github.com/woocommerce/woocommerce/blob/a55ae325306fc2179149ba9b97e66f32f84fdd9c/includes/admin/class-wc-admin-menus.php#L165.
add_action( 'admin_head', array( $this, 'update_link_structure' ), 20 );
} }
/** /**
@ -64,6 +72,50 @@ class WC_Admin_Analytics_Dashboard {
) )
); );
} }
/**
* Registers dashboard page.
*/
public function register_page() {
wc_admin_register_page(
array(
'id' => 'woocommerce-dashboard',
'title' => __( 'Dashboard', 'woocommerce-admin' ),
'parent' => 'woocommerce',
'path' => self::MENU_SLUG,
)
);
}
/**
* Update the WooCommerce menu structure to make our main dashboard/handler
* the top level link for 'WooCommerce'.
*/
public function update_link_structure() {
global $submenu;
// User does not have capabilites to see the submenu.
if ( ! current_user_can( 'manage_woocommerce' ) || empty( $submenu['woocommerce'] ) ) {
return;
}
$wc_admin_key = null;
foreach ( $submenu['woocommerce'] as $submenu_key => $submenu_item ) {
if ( self::MENU_SLUG === $submenu_item[2] ) {
$wc_admin_key = $submenu_key;
break;
}
}
if ( ! $wc_admin_key ) {
return;
}
$menu = $submenu['woocommerce'][ $wc_admin_key ];
// Move menu item to top of array.
unset( $submenu['woocommerce'][ $wc_admin_key ] );
array_unshift( $submenu['woocommerce'], $menu );
}
} }
new WC_Admin_Analytics_Dashboard(); new WC_Admin_Analytics_Dashboard();

View File

@ -73,65 +73,72 @@ class WC_Admin_Analytics {
* Registers report pages. * Registers report pages.
*/ */
public function register_pages() { public function register_pages() {
add_menu_page(
__( 'WooCommerce Analytics', 'woocommerce-admin' ),
__( 'Analytics', 'woocommerce-admin' ),
'manage_options',
'wc-admin#/analytics/revenue',
array( 'WC_Admin_Loader', 'page_wrapper' ),
'dashicons-chart-bar',
56 // After WooCommerce & Product menu items.
);
$report_pages = array( $report_pages = array(
array( array(
'id' => 'woocommerce-analytics',
'title' => __( 'Analytics', 'woocommerce-admin' ),
'path' => '/analytics/revenue',
'icon' => 'dashicons-chart-bar',
'position' => 56, // After WooCommerce & Product menu items.
),
array(
'id' => 'woocommerce-analytics-revenue',
'title' => __( 'Revenue', 'woocommerce-admin' ), 'title' => __( 'Revenue', 'woocommerce-admin' ),
'parent' => '/analytics/revenue', 'parent' => 'woocommerce-analytics',
'path' => '/analytics/revenue', 'path' => '/analytics/revenue',
), ),
array( array(
'id' => 'woocommerce-analytics-orders',
'title' => __( 'Orders', 'woocommerce-admin' ), 'title' => __( 'Orders', 'woocommerce-admin' ),
'parent' => '/analytics/revenue', 'parent' => 'woocommerce-analytics',
'path' => '/analytics/orders', 'path' => '/analytics/orders',
), ),
array( array(
'id' => 'woocommerce-analytics-products',
'title' => __( 'Products', 'woocommerce-admin' ), 'title' => __( 'Products', 'woocommerce-admin' ),
'parent' => '/analytics/revenue', 'parent' => 'woocommerce-analytics',
'path' => '/analytics/products', 'path' => '/analytics/products',
), ),
array( array(
'id' => 'woocommerce-analytics-categories',
'title' => __( 'Categories', 'woocommerce-admin' ), 'title' => __( 'Categories', 'woocommerce-admin' ),
'parent' => '/analytics/revenue', 'parent' => 'woocommerce-analytics',
'path' => '/analytics/categories', 'path' => '/analytics/categories',
), ),
array( array(
'id' => 'woocommerce-analytics-coupons',
'title' => __( 'Coupons', 'woocommerce-admin' ), 'title' => __( 'Coupons', 'woocommerce-admin' ),
'parent' => '/analytics/revenue', 'parent' => 'woocommerce-analytics',
'path' => '/analytics/coupons', 'path' => '/analytics/coupons',
), ),
array( array(
'id' => 'woocommerce-analytics-taxes',
'title' => __( 'Taxes', 'woocommerce-admin' ), 'title' => __( 'Taxes', 'woocommerce-admin' ),
'parent' => '/analytics/revenue', 'parent' => 'woocommerce-analytics',
'path' => '/analytics/taxes', 'path' => '/analytics/taxes',
), ),
array( array(
'id' => 'woocommerce-analytics-downloads',
'title' => __( 'Downloads', 'woocommerce-admin' ), 'title' => __( 'Downloads', 'woocommerce-admin' ),
'parent' => '/analytics/revenue', 'parent' => 'woocommerce-analytics',
'path' => '/analytics/downloads', 'path' => '/analytics/downloads',
), ),
'yes' === get_option( 'woocommerce_manage_stock' ) ? array( 'yes' === get_option( 'woocommerce_manage_stock' ) ? array(
'id' => 'woocommerce-analytics-stock',
'title' => __( 'Stock', 'woocommerce-admin' ), 'title' => __( 'Stock', 'woocommerce-admin' ),
'parent' => '/analytics/revenue', 'parent' => 'woocommerce-analytics',
'path' => '/analytics/stock', 'path' => '/analytics/stock',
) : null, ) : null,
array( array(
'id' => 'woocommerce-analytics-customers',
'title' => __( 'Customers', 'woocommerce-admin' ), 'title' => __( 'Customers', 'woocommerce-admin' ),
'parent' => '/analytics/revenue', 'parent' => 'woocommerce-analytics',
'path' => '/analytics/customers', 'path' => '/analytics/customers',
), ),
array( array(
'id' => 'woocommerce-analytics-settings',
'title' => __( 'Settings', 'woocommerce-admin' ), 'title' => __( 'Settings', 'woocommerce-admin' ),
'parent' => '/analytics/revenue', 'parent' => 'woocommerce-analytics',
'path' => '/analytics/settings', 'path' => '/analytics/settings',
), ),
); );

View File

@ -13,16 +13,6 @@ defined( 'ABSPATH' ) || exit;
* WC_Admin_Notes_Order_Milestones * WC_Admin_Notes_Order_Milestones
*/ */
class WC_Admin_Notes_Order_Milestones { class WC_Admin_Notes_Order_Milestones {
/**
* Name of the "first order" note.
*/
const FIRST_ORDER_NOTE_NAME = 'wc-admin-first-order';
/**
* Name of the "ten orders" note.
*/
const TEN_ORDERS_NOTE_NAME = 'wc-admin-ten-orders';
/** /**
* Name of the "other milestones" note. * Name of the "other milestones" note.
*/ */
@ -62,6 +52,8 @@ class WC_Admin_Notes_Order_Milestones {
* @var array * @var array
*/ */
protected $milestones = array( protected $milestones = array(
1,
10,
100, 100,
250, 250,
500, 500,
@ -101,10 +93,6 @@ class WC_Admin_Notes_Order_Milestones {
add_action( 'wc_admin_installed', array( $this, 'backfill_last_milestone' ) ); add_action( 'wc_admin_installed', array( $this, 'backfill_last_milestone' ) );
if ( $this->get_orders_count() <= 10 ) {
add_action( 'woocommerce_new_order', array( $this, 'first_two_milestones' ) );
}
add_action( self::PROCESS_ORDERS_MILESTONE_HOOK, array( $this, 'other_milestones' ) ); add_action( self::PROCESS_ORDERS_MILESTONE_HOOK, array( $this, 'other_milestones' ) );
} }
@ -130,59 +118,6 @@ class WC_Admin_Notes_Order_Milestones {
return $this->orders_count; return $this->orders_count;
} }
/**
* Add a milestone notes for the store's first order and first 10 orders.
*
* @param int $order_id WC_Order ID.
*/
public function first_two_milestones( $order_id ) {
$order = wc_get_order( $order_id );
// Make sure this is the first pending/processing/completed order.
if ( ! in_array( $order->get_status(), $this->allowed_statuses ) ) {
return;
}
// Retrieve the orders count, forcing a cache refresh.
$orders_count = $this->get_orders_count( true );
if ( 1 === $orders_count ) {
// Add the first order note.
$note = new WC_Admin_Note();
$note->set_title( __( 'First order', 'woocommerce-admin' ) );
$note->set_content(
__( 'Congratulations on getting your first order from a customer! Learn how to manage your orders.', 'woocommerce-admin' )
);
$note->set_type( WC_Admin_Note::E_WC_ADMIN_NOTE_INFORMATIONAL );
$note->set_icon( 'trophy' );
$note->set_name( self::FIRST_ORDER_NOTE_NAME );
$note->set_source( 'woocommerce-admin' );
$note->add_action( 'learn-more', __( 'Learn more', 'woocommerce-admin' ), 'https://docs.woocommerce.com/document/managing-orders/' );
$note->save();
}
if ( 10 === $orders_count ) {
// Add the first ten orders note.
$note = new WC_Admin_Note();
$note->set_title(
sprintf(
/* translators: Number of orders processed. */
__( 'Congratulations on processing %s orders!', 'woocommerce-admin' ),
wc_format_decimal( 10 )
)
);
$note->set_content(
__( "You've hit the 10 orders milestone! Look at you go. Browse some WooCommerce success stories for inspiration.", 'woocommerce-admin' )
);
$note->set_type( WC_Admin_Note::E_WC_ADMIN_NOTE_INFORMATIONAL );
$note->set_icon( 'trophy' );
$note->set_name( self::TEN_ORDERS_NOTE_NAME );
$note->set_source( 'woocommerce-admin' );
$note->add_action( 'browse', __( 'Browse', 'woocommerce-admin' ), 'https://woocommerce.com/success-stories/' );
$note->save();
}
}
/** /**
* Backfill the store's current milestone. * Backfill the store's current milestone.
* *
@ -230,6 +165,103 @@ class WC_Admin_Notes_Order_Milestones {
return $milestone_reached; return $milestone_reached;
} }
/**
* Get the appropriate note title for a given milestone.
*
* @param int $milestone Order milestone.
* @return string Note title for the milestone.
*/
public function get_note_title_for_milestone( $milestone ) {
switch ( $milestone ) {
case 1:
return __( 'First order', 'woocommerce-admin' );
case 10:
case 100:
case 250:
case 500:
case 1000:
case 5000:
case 10000:
case 500000:
case 1000000:
return sprintf(
/* translators: Number of orders processed. */
__( 'Congratulations on processing %s orders!', 'woocommerce-admin' ),
wc_format_decimal( $milestone )
);
default:
return '';
}
}
/**
* Get the appropriate note content for a given milestone.
*
* @param int $milestone Order milestone.
* @return string Note content for the milestone.
*/
public function get_note_content_for_milestone( $milestone ) {
switch ( $milestone ) {
case 1:
return __( 'Congratulations on getting your first order from a customer! Learn how to manage your orders.', 'woocommerce-admin' );
case 10:
return __( "You've hit the 10 orders milestone! Look at you go. Browse some WooCommerce success stories for inspiration.", 'woocommerce-admin' );
case 100:
case 250:
case 500:
case 1000:
case 5000:
case 10000:
case 500000:
case 1000000:
return __( 'Another order milestone! Take a look at your Orders Report to review your orders to date.', 'woocommerce-admin' );
default:
return '';
}
}
/**
* Get the appropriate note action for a given milestone.
*
* @param int $milestone Order milestone.
* @return array Note actoion (name, label, query) for the milestone.
*/
public function get_note_action_for_milestone( $milestone ) {
switch ( $milestone ) {
case 1:
return array(
'name' => 'learn-more',
'label' => __( 'Learn more', 'woocommerce-admin' ),
'query' => 'https://docs.woocommerce.com/document/managing-orders/',
);
case 10:
return array(
'name' => 'browse',
'label' => __( 'Browse', 'woocommerce-admin' ),
'query' => 'https://woocommerce.com/success-stories/',
);
case 100:
case 250:
case 500:
case 1000:
case 5000:
case 10000:
case 500000:
case 1000000:
return array(
'name' => 'review-orders',
'label' => __( 'Review your orders', 'woocommerce-admin' ),
'query' => '?page=wc-admin#/analytics/orders',
);
default:
return array(
'name' => '',
'label' => '',
'query' => '',
);
}
}
/** /**
* Add milestone notes for other significant thresholds. * Add milestone notes for other significant thresholds.
*/ */
@ -248,21 +280,14 @@ class WC_Admin_Notes_Order_Milestones {
// Add the milestone note. // Add the milestone note.
$note = new WC_Admin_Note(); $note = new WC_Admin_Note();
$note->set_title( $note->set_title( $this->get_note_title_for_milestone( $current_milestone ) );
sprintf( $note->set_content( $this->get_note_content_for_milestone( $current_milestone ) );
/* translators: Number of orders processed. */ $note_action = $this->get_note_action_for_milestone( $current_milestone );
__( 'Congratulations on processing %s orders!', 'woocommerce-admin' ), $note->add_action( $note_action['name'], $note_action['label'], $note_action['query'] );
wc_format_decimal( $current_milestone )
)
);
$note->set_content(
__( 'Another order milestone! Take a look at your Orders Report to review your orders to date.', 'woocommerce-admin' )
);
$note->set_type( WC_Admin_Note::E_WC_ADMIN_NOTE_INFORMATIONAL ); $note->set_type( WC_Admin_Note::E_WC_ADMIN_NOTE_INFORMATIONAL );
$note->set_icon( 'trophy' ); $note->set_icon( 'trophy' );
$note->set_name( self::ORDERS_MILESTONE_NOTE_NAME ); $note->set_name( self::ORDERS_MILESTONE_NOTE_NAME );
$note->set_source( 'woocommerce-admin' ); $note->set_source( 'woocommerce-admin' );
$note->add_action( 'review-orders', __( 'Review your orders', 'woocommerce-admin' ), '?page=wc-admin#/analytics/orders' );
$note->save(); $note->save();
} }
} }

View File

@ -0,0 +1,450 @@
<?php
/**
* WC_Admin_Page_Controller
*
* @package Woocommerce Admin
*/
/**
* WC_Admin_Page_Controller
*/
class WC_Admin_Page_Controller {
// JS-powered page root.
const PAGE_ROOT = 'wc-admin';
/**
* Singleton instance of self.
*
* @var WC_Admin_Page_Controller
*/
private static $instance = false;
/**
* Current page ID (or false if not registered with this controller).
*
* @var string
*/
private $current_page = null;
/**
* Registered pages
* Contains information (breadcrumbs, menu info) about JS powered pages and classic WooCommerce pages.
*
* @var array
*/
private $pages = array();
/**
* We want a single instance of this class so we can accurately track registered menus and pages.
*/
public static function get_instance() {
if ( ! self::$instance ) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Connect an existing page to wc-admin.
*
* @param array $options {
* Array describing the page.
*
* @type string id Id to reference the page.
* @type string|array title Page title. Used in menus and breadcrumbs.
* @type string|null parent Parent ID. Null for new top level page.
* @type string path Path for this page. E.g. admin.php?page=wc-settings&tab=checkout
* @type string capability Capability needed to access the page.
* @type string icon Icon. Dashicons helper class, base64-encoded SVG, or 'none'.
* @type int position Menu item position.
* @type boolean js_page If this is a JS-powered page.
* }
*/
public function connect_page( $options ) {
if ( ! is_array( $options['title'] ) ) {
$options['title'] = array( $options['title'] );
}
/**
* Filter the options when connecting or registering a page.
*
* Use the `js_page` option to determine if registering.
*
* @param array $options {
* Array describing the page.
*
* @type string id Id to reference the page.
* @type string|array title Page title. Used in menus and breadcrumbs.
* @type string|null parent Parent ID. Null for new top level page.
* @type string screen_id The screen ID that represents the connected page. (Not required for registering).
* @type string path Path for this page. E.g. admin.php?page=wc-settings&tab=checkout
* @type string capability Capability needed to access the page.
* @type string icon Icon. Dashicons helper class, base64-encoded SVG, or 'none'.
* @type int position Menu item position.
* @type boolean js_page If this is a JS-powered page.
* }
*/
$options = apply_filters( 'wc_admin_connect_page_options', $options );
// @todo check for null ID, or collision.
$this->pages[ $options['id'] ] = $options;
}
/**
* Determine the current page ID, if it was registered with this controller.
*/
public function determine_current_page() {
$current_url = '';
$current_screen_id = $this->get_current_screen_id();
if ( isset( $_SERVER['REQUEST_URI'] ) ) {
$current_url = esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) );
}
$current_path = wp_parse_url( $current_url, PHP_URL_PATH );
$current_query = wp_parse_url( $current_url, PHP_URL_QUERY );
$current_fragment = wp_parse_url( $current_url, PHP_URL_FRAGMENT );
foreach ( $this->pages as $page ) {
if ( isset( $page['js_page'] ) && $page['js_page'] ) {
// Check registered admin pages.
$full_page_path = add_query_arg( 'page', $page['path'], admin_url( 'admin.php' ) );
$page_path = wp_parse_url( $full_page_path, PHP_URL_PATH );
$page_query = wp_parse_url( $full_page_path, PHP_URL_QUERY );
$page_fragment = wp_parse_url( $full_page_path, PHP_URL_FRAGMENT );
if (
$page_path === $current_path &&
$page_query === $current_query &&
$page_fragment === $current_fragment
) {
$this->current_page = $page;
return;
}
} else {
// Check connected admin pages.
if (
isset( $page['screen_id'] ) &&
$page['screen_id'] === $current_screen_id
) {
$this->current_page = $page;
return;
}
}
}
$this->current_page = false;
}
/**
* Get breadcrumbs for WooCommerce Admin Page navigation.
*
* @return array Navigation pieces (breadcrumbs).
*/
public function get_breadcrumbs() {
$current_page = $this->get_current_page();
// Bail if this isn't a page registered with this controller.
if ( false === $current_page ) {
// Filter documentation below.
return apply_filters( 'wc_admin_get_breadcrumbs', array( '' ), $current_page );
}
if ( 1 === count( $current_page['title'] ) ) {
$breadcrumbs = $current_page['title'];
} else {
// If this page has multiple title pieces, only link the first one.
$breadcrumbs = array_merge(
array(
array( $current_page['path'], reset( $current_page['title'] ) ),
),
array_slice( $current_page['title'], 1 )
);
}
if ( isset( $current_page['parent'] ) ) {
$parent_id = $current_page['parent'];
while ( $parent_id ) {
if ( isset( $this->pages[ $parent_id ] ) ) {
$parent = $this->pages[ $parent_id ];
array_unshift( $breadcrumbs, array( $parent['path'], reset( $parent['title'] ) ) );
$parent_id = isset( $parent['parent'] ) ? $parent['parent'] : false;
} else {
$parent_id = false;
}
}
}
/**
* The navigation breadcrumbs for the current page.
*
* @param array $breadcrumbs Navigation pieces (breadcrumbs).
* @param array|boolean $current_page The connected page data or false if not identified.
*/
return apply_filters( 'wc_admin_get_breadcrumbs', $breadcrumbs, $current_page );
}
/**
* Get the current page.
*
* @return array|boolean Current page or false if not registered with this controller.
*/
public function get_current_page() {
if ( is_null( $this->current_page ) ) {
$this->determine_current_page();
}
return $this->current_page;
}
/**
* 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}-tab-section
* - {$current_screen->action}-{$current_screen->action}-tab
* - {$current_screen->action}-{$current_screen->action} if no tab is present
* - {$current_screen->action} if no action or tab is present
*
* @return string Current screen ID.
*/
public function get_current_screen_id() {
$current_screen = get_current_screen();
if ( ! $current_screen ) {
// Filter documentation below.
return apply_filters( 'wc_admin_current_screen_id', false, $current_screen );
}
$screen_pieces = array( $current_screen->id );
if ( $current_screen->action ) {
$screen_pieces[] = $current_screen->action;
}
if (
! empty( $current_screen->taxonomy ) &&
isset( $current_screen->post_type ) &&
'product' === $current_screen->post_type
) {
// Editing a product attribute.
if ( 0 === strpos( $current_screen->taxonomy, 'pa_' ) ) {
$screen_pieces = array( 'product_page_product_attribute-edit' );
}
// Editing a product taxonomy term.
if ( ! empty( $_GET['tag_ID'] ) ) {
$screen_pieces = array( $current_screen->taxonomy );
}
}
// Pages with default tab values.
$pages_with_tabs = apply_filters(
'wc_admin_pages_with_tabs',
array(
'wc-reports' => 'orders',
'wc-settings' => 'general',
'wc-status' => 'status',
'wc-addons' => 'browse-extensions',
)
);
// Tabs that have sections as well.
$wc_emails = WC_Emails::instance();
$wc_email_ids = array_map( 'sanitize_title', array_keys( $wc_emails->get_emails() ) );
$tabs_with_sections = apply_filters(
'wc_admin_page_tab_sections',
array(
'products' => array( '', 'inventory', 'downloadable' ),
'shipping' => array( '', 'options', 'classes' ),
'checkout' => array( 'bacs', 'cheque', 'cod', 'paypal' ),
'email' => $wc_email_ids,
'advanced' => array(
'',
'keys',
'webhooks',
'legacy_api',
'woocommerce_com',
),
'browse-extensions' => array( 'helper' ),
)
);
if ( ! empty( $_GET['page'] ) ) {
if ( in_array( $_GET['page'], array_keys( $pages_with_tabs ) ) ) { // WPCS: sanitization ok.
if ( ! empty( $_GET['tab'] ) ) {
$tab = wc_clean( wp_unslash( $_GET['tab'] ) );
} else {
$tab = $pages_with_tabs[ $_GET['page'] ]; // WPCS: sanitization ok.
}
$screen_pieces[] = $tab;
if ( ! empty( $_GET['section'] ) ) {
if (
isset( $tabs_with_sections[ $tab ] ) &&
in_array( $_GET['section'], array_keys( $tabs_with_sections[ $tab ] ) ) // WPCS: sanitization ok.
) {
$screen_pieces[] = wc_clean( wp_unslash( $_GET['section'] ) );
}
}
// Editing a shipping zone.
if ( ( 'shipping' === $tab ) && isset( $_GET['zone_id'] ) ) {
$screen_pieces[] = 'edit_zone';
}
}
}
/**
* The current screen id.
*
* Used for identifying pages to render the WooCommerce Admin header.
*
* @param string|boolean $screen_id The screen id or false if not identified.
* @param WP_Screen $current_screen The current WP_Screen.
*/
return apply_filters( 'wc_admin_current_screen_id', implode( '-', $screen_pieces ), $current_screen );
}
/**
* Returns the path from an ID.
*
* @param string $id ID to get path for.
* @return string Path for the given ID, or the ID on lookup miss.
*/
public function get_path_from_id( $id ) {
if ( isset( $this->pages[ $id ] ) && isset( $this->pages[ $id ]['path'] ) ) {
return $this->pages[ $id ]['path'];
}
return $id;
}
/**
* Returns true if we are on a page connected to this controller.
*
* @return boolean
*/
public function is_connected_page() {
$current_page = $this->get_current_page();
if ( false === $current_page ) {
$is_connected_page = false;
} else {
$is_connected_page = isset( $current_page['js_page'] ) ? ! $current_page['js_page'] : true;
}
/**
* Whether or not the current page is an existing page connected to this controller.
*
* Used to determine if the WooCommerce Admin header should be rendered.
*
* @param boolean $is_connected_page True if the current page is connected.
* @param array|boolean $current_page The connected page data or false if not identified.
*/
return apply_filters( 'woocommerce_page_is_connected_page', $is_connected_page, $current_page );
}
/**
* Returns true if we are on a page registed with this controller.
*
* @return boolean
*/
public function is_registered_page() {
$current_page = $this->get_current_page();
if ( false === $current_page ) {
$is_registered_page = false;
} else {
$is_registered_page = isset( $current_page['js_page'] ) && $current_page['js_page'];
}
/**
* Whether or not the current page was registered with this controller.
*
* Used to determine if this is a JS-powered WooCommerce Admin page.
*
* @param boolean $is_registered_page True if the current page was registered with this controller.
* @param array|boolean $current_page The registered page data or false if not identified.
*/
return apply_filters( 'woocommerce_page_is_registered_page', $is_registered_page, $current_page );
}
/**
* Adds a JS powered page to wc-admin.
*
* @param array $options {
* Array describing the page.
*
* @type string id Id to reference the page.
* @type string title Page title. Used in menus and breadcrumbs.
* @type string|null parent Parent ID. Null for new top level page.
* @type string path Path for this page, full path in app context; ex /analytics/report
* @type string capability Capability needed to access the page.
* @type string icon Icon. Dashicons helper class, base64-encoded SVG, or 'none'.
* @type int position Menu item position.
* }
*/
public function register_page( $options ) {
$defaults = array(
'id' => null,
'parent' => null,
'title' => '',
'capability' => 'manage_options',
'path' => '',
'icon' => '',
'position' => null,
'js_page' => true,
);
$options = wp_parse_args( $options, $defaults );
if ( 0 !== strpos( $options['path'], self::PAGE_ROOT ) ) {
$options['path'] = self::PAGE_ROOT . '#' . $options['path'];
}
if ( is_null( $options['parent'] ) ) {
add_menu_page(
$options['title'],
$options['title'],
$options['capability'],
$options['path'],
array( __CLASS__, 'page_wrapper' ),
$options['icon'],
$options['position']
);
} else {
$parent_path = $this->get_path_from_id( $options['parent'] );
// @todo check for null path.
add_submenu_page(
$parent_path,
$options['title'],
$options['title'],
$options['capability'],
$options['path'],
array( __CLASS__, 'page_wrapper' )
);
}
$this->connect_page( $options );
}
/**
* Set up a div for the app to render into.
*/
public static function page_wrapper() {
?>
<div class="wrap">
<div id="root"></div>
</div>
<?php
}
}

View File

@ -0,0 +1,560 @@
<?php
/**
* Connect existing WooCommerce pages to WooCommerce Admin.
*
* @package Woocommerce Admin
*/
$admin_page_base = 'admin.php';
$posttype_list_base = 'edit.php';
// WooCommerce > Settings > General (default tab).
wc_admin_connect_page(
array(
'id' => 'woocommerce-settings',
'screen_id' => 'woocommerce_page_wc-settings-general',
'title' => array(
__( 'Settings', 'woocommerce-admin' ),
__( 'General', 'woocommerce-admin' ),
),
'path' => add_query_arg( 'page', 'wc-settings', $admin_page_base ),
)
);
// WooCommerce > Settings > Products > General (default tab).
wc_admin_connect_page(
array(
'id' => 'woocommerce-settings-products',
'parent' => 'woocommerce-settings',
'screen_id' => 'woocommerce_page_wc-settings-products',
'title' => array(
__( 'Products', 'woocommerce-admin' ),
__( 'General', 'woocommerce-admin' ),
),
'path' => add_query_arg(
array(
'page' => 'wc-settings',
'tab' => 'products',
),
$admin_page_base
),
)
);
// WooCommerce > Settings > Products > Inventory.
wc_admin_connect_page(
array(
'id' => 'woocommerce-settings-products-inventory',
'parent' => 'woocommerce-settings-products',
'screen_id' => 'woocommerce_page_wc-settings-products-inventory',
'title' => __( 'Inventory', 'woocommerce-admin' ),
)
);
// WooCommerce > Settings > Products > Downloadable products.
wc_admin_connect_page(
array(
'id' => 'woocommerce-settings-products-downloadable',
'parent' => 'woocommerce-settings-products',
'screen_id' => 'woocommerce_page_wc-settings-products-downloadable',
'title' => __( 'Downloadable products', 'woocommerce-admin' ),
)
);
// WooCommerce > Settings > Shipping > Shipping zones (default tab).
wc_admin_connect_page(
array(
'id' => 'woocommerce-settings-shipping',
'parent' => 'woocommerce-settings',
'screen_id' => 'woocommerce_page_wc-settings-shipping',
'title' => array(
__( 'Shipping', 'woocommerce-admin' ),
__( 'Shipping zones', 'woocommerce-admin' ),
),
'path' => add_query_arg(
array(
'page' => 'wc-settings',
'tab' => 'shipping',
),
$admin_page_base
),
)
);
// WooCommerce > Settings > Shipping > Shipping zones > Edit zone.
wc_admin_connect_page(
array(
'id' => 'woocommerce-settings-edit-shipping-zone',
'parent' => 'woocommerce-settings',
'screen_id' => 'woocommerce_page_wc-settings-shipping-edit_zone',
'title' => array(
__( 'Shipping zones', 'woocommerce-admin' ),
__( 'Edit zone', 'woocommerce-admin' ),
),
'path' => add_query_arg(
array(
'page' => 'wc-settings',
'tab' => 'shipping',
),
$admin_page_base
),
)
);
// WooCommerce > Settings > Shipping > Shipping options.
wc_admin_connect_page(
array(
'id' => 'woocommerce-settings-shipping-options',
'parent' => 'woocommerce-settings-shipping',
'screen_id' => 'woocommerce_page_wc-settings-shipping-options',
'title' => __( 'Shipping options', 'woocommerce-admin' ),
)
);
// WooCommerce > Settings > Shipping > Shipping classes.
wc_admin_connect_page(
array(
'id' => 'woocommerce-settings-shipping-classes',
'parent' => 'woocommerce-settings-shipping',
'screen_id' => 'woocommerce_page_wc-settings-shipping-classes',
'title' => __( 'Shipping classes', 'woocommerce-admin' ),
)
);
// WooCommerce > Settings > Payments.
wc_admin_connect_page(
array(
'id' => 'woocommerce-settings-payments',
'parent' => 'woocommerce-settings',
'screen_id' => 'woocommerce_page_wc-settings-checkout',
'title' => __( 'Payments', 'woocommerce-admin' ),
'path' => add_query_arg(
array(
'page' => 'wc-settings',
'tab' => 'checkout',
),
$admin_page_base
),
)
);
// WooCommerce > Settings > Payments > Direct bank transfer.
wc_admin_connect_page(
array(
'id' => 'woocommerce-settings-payments-bacs',
'parent' => 'woocommerce-settings-payments',
'screen_id' => 'woocommerce_page_wc-settings-checkout-bacs',
'title' => __( 'Direct bank transfer', 'woocommerce-admin' ),
)
);
// WooCommerce > Settings > Payments > Check payments.
wc_admin_connect_page(
array(
'id' => 'woocommerce-settings-payments-cheque',
'parent' => 'woocommerce-settings-payments',
'screen_id' => 'woocommerce_page_wc-settings-checkout-cheque',
'title' => __( 'Check payments', 'woocommerce-admin' ),
)
);
// WooCommerce > Settings > Payments > Cash on delivery.
wc_admin_connect_page(
array(
'id' => 'woocommerce-settings-payments-cod',
'parent' => 'woocommerce-settings-payments',
'screen_id' => 'woocommerce_page_wc-settings-checkout-cod',
'title' => __( 'Cash on delivery', 'woocommerce-admin' ),
)
);
// WooCommerce > Settings > Payments > PayPal.
wc_admin_connect_page(
array(
'id' => 'woocommerce-settings-payments-paypal',
'parent' => 'woocommerce-settings-payments',
'screen_id' => 'woocommerce_page_wc-settings-checkout-paypal',
'title' => __( 'PayPal', 'woocommerce-admin' ),
)
);
// WooCommerce > Settings > Accounts & Privacy.
wc_admin_connect_page(
array(
'id' => 'woocommerce-settings-accounts-privacy',
'parent' => 'woocommerce-settings',
'screen_id' => 'woocommerce_page_wc-settings-account',
'title' => __( 'Accounts & Privacy', 'woocommerce-admin' ),
)
);
// WooCommerce > Settings > Emails.
wc_admin_connect_page(
array(
'id' => 'woocommerce-settings-email',
'parent' => 'woocommerce-settings',
'screen_id' => 'woocommerce_page_wc-settings-email',
'title' => __( 'Emails', 'woocommerce-admin' ),
'path' => add_query_arg(
array(
'page' => 'wc-settings',
'tab' => 'email',
),
$admin_page_base
),
)
);
// WooCommerce > Settings > Emails > Edit email (all email editing).
$wc_emails = WC_Emails::instance();
$wc_email_ids = array_map( 'sanitize_title', array_keys( $wc_emails->get_emails() ) );
foreach ( $wc_email_ids as $email_id ) {
wc_admin_connect_page(
array(
'id' => 'woocommerce-settings-email-' . $email_id,
'parent' => 'woocommerce-settings-email',
'screen_id' => 'woocommerce_page_wc-settings-email-' . $email_id,
'title' => __( 'Edit email', 'woocommerce-admin' ),
)
);
}
// WooCommerce > Settings > Advanced > Page setup (default tab).
wc_admin_connect_page(
array(
'id' => 'woocommerce-settings-advanced',
'parent' => 'woocommerce-settings',
'screen_id' => 'woocommerce_page_wc-settings-advanced',
'title' => array(
__( 'Advanced', 'woocommerce-admin' ),
__( 'Page setup', 'woocommerce-admin' ),
),
'path' => add_query_arg(
array(
'page' => 'wc-settings',
'tab' => 'advanced',
),
$admin_page_base
),
)
);
// WooCommerce > Settings > Advanced > REST API.
wc_admin_connect_page(
array(
'id' => 'woocommerce-settings-advanced-rest-api',
'parent' => 'woocommerce-settings-advanced',
'screen_id' => 'woocommerce_page_wc-settings-advanced-keys',
'title' => __( 'REST API', 'woocommerce-admin' ),
)
);
// WooCommerce > Settings > Advanced > Webhooks.
wc_admin_connect_page(
array(
'id' => 'woocommerce-settings-advanced-webhooks',
'parent' => 'woocommerce-settings-advanced',
'screen_id' => 'woocommerce_page_wc-settings-advanced-webhooks',
'title' => __( 'Webhooks', 'woocommerce-admin' ),
)
);
// WooCommerce > Settings > Advanced > Legacy API.
wc_admin_connect_page(
array(
'id' => 'woocommerce-settings-advanced-legacy-api',
'parent' => 'woocommerce-settings-advanced',
'screen_id' => 'woocommerce_page_wc-settings-advanced-legacy_api',
'title' => __( 'Legacy API', 'woocommerce-admin' ),
)
);
// WooCommerce > Settings > Advanced > WooCommerce.com.
wc_admin_connect_page(
array(
'id' => 'woocommerce-settings-advanced-woocommerce-com',
'parent' => 'woocommerce-settings-advanced',
'screen_id' => 'woocommerce_page_wc-settings-advanced-woocommerce_com',
'title' => __( 'WooCommerce.com', 'woocommerce-admin' ),
)
);
// WooCommerce > Orders.
wc_admin_connect_page(
array(
'id' => 'woocommerce-orders',
'screen_id' => 'edit-shop_order',
'title' => __( 'Orders', 'woocommerce-admin' ),
'path' => add_query_arg( 'post_type', 'shop_order', $posttype_list_base ),
)
);
// WooCommerce > Orders > Add New.
wc_admin_connect_page(
array(
'id' => 'woocommerce-add-order',
'parent' => 'woocommerce-orders',
'screen_id' => 'shop_order-add',
'title' => __( 'Add New', 'woocommerce-admin' ),
)
);
// WooCommerce > Orders > Edit Order.
wc_admin_connect_page(
array(
'id' => 'woocommerce-edit-order',
'parent' => 'woocommerce-orders',
'screen_id' => 'shop_order',
'title' => __( 'Edit Order', 'woocommerce-admin' ),
)
);
// WooCommerce > Coupons.
wc_admin_connect_page(
array(
'id' => 'woocommerce-coupons',
'screen_id' => 'edit-shop_coupon',
'title' => __( 'Coupons', 'woocommerce-admin' ),
'path' => add_query_arg( 'post_type', 'shop_coupon', $posttype_list_base ),
)
);
// WooCommerce > Coupons > Add New.
wc_admin_connect_page(
array(
'id' => 'woocommerce-add-coupon',
'parent' => 'woocommerce-coupons',
'screen_id' => 'shop_coupon-add',
'title' => __( 'Add New', 'woocommerce-admin' ),
)
);
// WooCommerce > Coupons > Edit Coupon.
wc_admin_connect_page(
array(
'id' => 'woocommerce-edit-coupon',
'parent' => 'woocommerce-coupons',
'screen_id' => 'shop_coupon',
'title' => __( 'Edit Coupon', 'woocommerce-admin' ),
)
);
// WooCommerce > Reports > Orders (default tab).
wc_admin_connect_page(
array(
'id' => 'woocommerce-reports',
'screen_id' => 'woocommerce_page_wc-reports-orders',
'title' => array(
__( 'Reports', 'woocommerce-admin' ),
__( 'Orders', 'woocommerce-admin' ),
),
'path' => add_query_arg( 'page', 'wc-reports', $admin_page_base ),
)
);
// WooCommerce > Reports > Customers.
wc_admin_connect_page(
array(
'id' => 'woocommerce-reports-customers',
'parent' => 'woocommerce-reports',
'screen_id' => 'woocommerce_page_wc-reports-customers',
'title' => __( 'Customers', 'woocommerce-admin' ),
)
);
// WooCommerce > Reports > Stock.
wc_admin_connect_page(
array(
'id' => 'woocommerce-reports-stock',
'parent' => 'woocommerce-reports',
'screen_id' => 'woocommerce_page_wc-reports-stock',
'title' => __( 'Stock', 'woocommerce-admin' ),
)
);
// WooCommerce > Reports > Taxes.
wc_admin_connect_page(
array(
'id' => 'woocommerce-reports-taxes',
'parent' => 'woocommerce-reports',
'screen_id' => 'woocommerce_page_wc-reports-taxes',
'title' => __( 'Taxes', 'woocommerce-admin' ),
)
);
// WooCommerce > Status > System status (default tab).
wc_admin_connect_page(
array(
'id' => 'woocommerce-status',
'screen_id' => 'woocommerce_page_wc-status-status',
'title' => array(
__( 'Status', 'woocommerce-admin' ),
__( 'System status', 'woocommerce-admin' ),
),
'path' => add_query_arg( 'page', 'wc-status', $admin_page_base ),
)
);
// WooCommerce > Status > Tools.
wc_admin_connect_page(
array(
'id' => 'woocommerce-status-tools',
'parent' => 'woocommerce-status',
'screen_id' => 'woocommerce_page_wc-status-tools',
'title' => __( 'Tools', 'woocommerce-admin' ),
)
);
// WooCommerce > Status > Logs.
wc_admin_connect_page(
array(
'id' => 'woocommerce-status-logs',
'parent' => 'woocommerce-status',
'screen_id' => 'woocommerce_page_wc-status-tools',
'title' => __( 'Tools', 'woocommerce-admin' ),
)
);
// WooCommerce > Status > Scheduled Actions.
wc_admin_connect_page(
array(
'id' => 'woocommerce-status-action-scheduler',
'parent' => 'woocommerce-status',
'screen_id' => 'woocommerce_page_wc-status-action-scheduler',
'title' => __( 'Scheduled Actions', 'woocommerce-admin' ),
)
);
// WooCommerce > Extensions > Browse Extensions (default tab).
wc_admin_connect_page(
array(
'id' => 'woocommerce-addons',
'screen_id' => 'woocommerce_page_wc-addons-browse-extensions',
'title' => array(
__( 'Extensions', 'woocommerce-admin' ),
__( 'Browse Extensions', 'woocommerce-admin' ),
),
'path' => add_query_arg( 'page', 'wc-addons', $admin_page_base ),
)
);
// WooCommerce > Extensions > WooCommerce.com Subscriptions.
wc_admin_connect_page(
array(
'id' => 'woocommerce-addons-subscriptions',
'parent' => 'woocommerce-addons',
'screen_id' => 'woocommerce_page_wc-addons-browse-extensions-helper',
'title' => __( 'WooCommerce.com Subscriptions', 'woocommerce-admin' ),
)
);
// WooCommerce > Products.
wc_admin_connect_page(
array(
'id' => 'woocommerce-products',
'screen_id' => 'edit-product',
'title' => __( 'Products', 'woocommerce-admin' ),
'path' => add_query_arg( 'post_type', 'product', $posttype_list_base ),
)
);
// WooCommerce > Products > Add New.
wc_admin_connect_page(
array(
'id' => 'woocommerce-add-product',
'parent' => 'woocommerce-products',
'screen_id' => 'product-add',
'title' => __( 'Add New', 'woocommerce-admin' ),
)
);
// WooCommerce > Products > Edit Order.
wc_admin_connect_page(
array(
'id' => 'woocommerce-edit-product',
'parent' => 'woocommerce-products',
'screen_id' => 'product',
'title' => __( 'Edit Product', 'woocommerce-admin' ),
)
);
// WooCommerce > Products > Import Products.
wc_admin_connect_page(
array(
'id' => 'woocommerce-import-products',
'parent' => 'woocommerce-products',
'screen_id' => 'product_page_product_importer',
'title' => __( 'Import Products', 'woocommerce-admin' ),
)
);
// WooCommerce > Products > Export Products.
wc_admin_connect_page(
array(
'id' => 'woocommerce-export-products',
'parent' => 'woocommerce-products',
'screen_id' => 'product_page_product_exporter',
'title' => __( 'Export Products', 'woocommerce-admin' ),
)
);
// WooCommerce > Products > Product categories.
wc_admin_connect_page(
array(
'id' => 'woocommerce-product-categories',
'parent' => 'woocommerce-products',
'screen_id' => 'edit-product_cat',
'title' => __( 'Product categories', 'woocommerce-admin' ),
)
);
// WooCommerce > Products > Edit category.
wc_admin_connect_page(
array(
'id' => 'woocommerce-product-edit-category',
'parent' => 'woocommerce-products',
'screen_id' => 'product_cat',
'title' => __( 'Edit category', 'woocommerce-admin' ),
)
);
// WooCommerce > Products > Product tags.
wc_admin_connect_page(
array(
'id' => 'woocommerce-product-tags',
'parent' => 'woocommerce-products',
'screen_id' => 'edit-product_tag',
'title' => __( 'Product tags', 'woocommerce-admin' ),
)
);
// WooCommerce > Products > Edit tag.
wc_admin_connect_page(
array(
'id' => 'woocommerce-product-edit-tag',
'parent' => 'woocommerce-products',
'screen_id' => 'product_tag',
'title' => __( 'Edit tag', 'woocommerce-admin' ),
)
);
// WooCommerce > Products > Attributes.
wc_admin_connect_page(
array(
'id' => 'woocommerce-product-attributes',
'parent' => 'woocommerce-products',
'screen_id' => 'product_page_product_attributes',
'title' => __( 'Attributes', 'woocommerce-admin' ),
)
);
// WooCommerce > Products > Edit attribute.
wc_admin_connect_page(
array(
'id' => 'woocommerce-product-edit-attribute',
'parent' => 'woocommerce-products',
'screen_id' => 'product_page_product_attribute-edit',
'title' => __( 'Edit attribute', 'woocommerce-admin' ),
)
);

View File

@ -0,0 +1,61 @@
<?php
/**
* Convenience functions for WC_Admin_Page_Controller.
*
* @package Woocommerce Admin
*/
/**
* Connect an existing page to WooCommerce Admin.
* Passthrough to WC_Admin_Page_Controller::connect_page().
*
* @param array $options Options for WC_Admin_Page_Controller::connect_page().
*/
function wc_admin_connect_page( $options ) {
$controller = WC_Admin_Page_Controller::get_instance();
$controller->connect_page( $options );
}
/**
* Register JS-powered WooCommerce Admin Page.
* Passthrough to WC_Admin_Page_Controller::register_page().
*
* @param array $options Options for WC_Admin_Page_Controller::register_page().
*/
function wc_admin_register_page( $options ) {
$controller = WC_Admin_Page_Controller::get_instance();
$controller->register_page( $options );
}
/**
* Is this page connected to WooCommerce Admin?
* Passthrough to WC_Admin_Page_Controller::is_connected_page().
*
* @return boolean True if the page is connected to WooCommerce Admin.
*/
function wc_admin_is_connected_page() {
$controller = WC_Admin_Page_Controller::get_instance();
return $controller->is_connected_page();
}
/**
* Is this a WooCommerce Admin Page?
* Passthrough to WC_Admin_Page_Controller::is_registered_page().
*
* @return boolean True if the page is a WooCommerce Admin page.
*/
function wc_admin_is_registered_page() {
$controller = WC_Admin_Page_Controller::get_instance();
return $controller->is_registered_page();
}
/**
* Get breadcrumbs for WooCommerce Admin Page navigation.
* Passthrough to WC_Admin_Page_Controller::get_breadcrumbs().
*
* @return array Navigation pieces (breadcrumbs).
*/
function wc_admin_get_breadcrumbs() {
$controller = WC_Admin_Page_Controller::get_instance();
return $controller->get_breadcrumbs();
}

View File

@ -1,4 +1,7 @@
/** @format */ /** @format */
.woocommerce-ellipsis-menu {
text-align: center;
}
.woocommerce-ellipsis-menu__toggle { .woocommerce-ellipsis-menu__toggle {
height: 24px; height: 24px;

View File

@ -11,6 +11,13 @@ $inner-border: $core-grey-light-500;
.woocommerce-summary__item-container:nth-of-type(#{$i}n) .woocommerce-summary__item { .woocommerce-summary__item-container:nth-of-type(#{$i}n) .woocommerce-summary__item {
border-right-color: $outer-border; border-right-color: $outer-border;
} }
.woocommerce-summary__item-container:nth-of-type(#{$i}n+1):nth-last-of-type(-n+#{$i}) {
.woocommerce-summary__item,
& ~ .woocommerce-summary__item-container .woocommerce-summary__item {
border-bottom-color: $outer-border;
}
}
} }
@mixin wrap-contents() { @mixin wrap-contents() {
@ -31,24 +38,6 @@ $inner-border: $core-grey-light-500;
} }
} }
@mixin reset-wrap() {
.woocommerce-summary__item-value,
.woocommerce-summary__item-delta {
min-width: auto;
}
.woocommerce-summary__item-prev-label,
.woocommerce-summary__item-prev-value {
display: inline;
}
&.is-placeholder {
.woocommerce-summary__item-prev-label {
margin-right: 0;
}
}
}
.woocommerce-summary { .woocommerce-summary {
margin: $gap 0; margin: $gap 0;
display: grid; display: grid;
@ -149,16 +138,22 @@ $inner-border: $core-grey-light-500;
@include make-cols( 4 ); @include make-cols( 4 );
} }
&.has-5-items, &.has-5-items {
@include make-cols( 5 );
@include wrap-contents;
}
@include breakpoint( '>1440px' ) {
&.has-6-items {
@include make-cols( 6 );
@include wrap-contents;
}
&.has-9-items, &.has-9-items,
&.has-10-items { &.has-10-items {
@include make-cols( 5 ); @include make-cols( 5 );
@include wrap-contents; @include wrap-contents;
} }
&.has-6-items {
@include make-cols( 6 );
@include wrap-contents;
} }
@include breakpoint( '<1440px' ) { @include breakpoint( '<1440px' ) {
@ -171,11 +166,11 @@ $inner-border: $core-grey-light-500;
&.has-6-items, &.has-6-items,
&.has-9-items { &.has-9-items {
@include make-cols( 3 ); @include make-cols( 3 );
@include reset-wrap;
} }
&.has-10-items { &.has-10-items {
@include make-cols( 4 ); @include make-cols( 4 );
@include wrap-contents;
} }
&.has-9-items, &.has-9-items,
@ -221,7 +216,7 @@ $inner-border: $core-grey-light-500;
&:last-of-type .woocommerce-summary__item { &:last-of-type .woocommerce-summary__item {
// Make sure the last item always uses the outer-border color. // Make sure the last item always uses the outer-border color.
border-right-color: $outer-border !important; border-bottom-color: $outer-border !important;
} }
&.is-dropdown-button { &.is-dropdown-button {
@ -285,10 +280,12 @@ $inner-border: $core-grey-light-500;
} }
.woocommerce-summary__item { .woocommerce-summary__item {
display: block; display: flex;
flex-direction: column;
height: 100%;
padding: $spacing; padding: $spacing;
background-color: $core-grey-light-100; background-color: $core-grey-light-100;
border-bottom: 1px solid $outer-border; border-bottom: 1px solid $inner-border;
border-right: 1px solid $inner-border; border-right: 1px solid $inner-border;
line-height: 1.4em; line-height: 1.4em;
text-decoration: none; text-decoration: none;
@ -324,6 +321,10 @@ $inner-border: $core-grey-light-500;
} }
} }
.woocommerce-summary__item-data {
margin-top: auto;
}
.woocommerce-summary__item-label { .woocommerce-summary__item-label {
display: block; display: block;
margin-bottom: $gap; margin-bottom: $gap;