fix merge conflicts

This commit is contained in:
Ron Rennick 2019-05-14 15:25:05 -03:00
commit e68eaabaac
22 changed files with 2455 additions and 1277 deletions

View File

@ -30,10 +30,20 @@
}
}
.woocommerce-layout .woocommerce-layout__main {
padding-right: 0;
}
/* Hide wp-admin and WooCommerce elements when viewing the profile wizard*/
#adminmenumain,
#wpadminbar,
.woocommerce-layout__header {
.woocommerce-layout__header,
.update-nag,
.woocommerce-store-alerts,
.woocommerce-message,
.notice,
.error,
.updated {
display: none;
}

View File

@ -22,3 +22,7 @@
padding-right: $gutter-large;
max-width: 100%;
}
.woocommerce-page .update-nag {
display: none;
}

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

@ -71,6 +71,31 @@ class WC_Admin_REST_Reports_Import_Controller extends WC_Admin_REST_Reports_Cont
'schema' => array( $this, 'get_import_public_schema' ),
)
);
register_rest_route(
$this->namespace,
'/' . $this->rest_base . '/status',
array(
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'get_import_status' ),
'permission_callback' => array( $this, 'import_permissions_check' ),
),
'schema' => array( $this, 'get_import_public_schema' ),
)
);
register_rest_route(
$this->namespace,
'/' . $this->rest_base . '/totals',
array(
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'get_import_totals' ),
'permission_callback' => array( $this, 'import_permissions_check' ),
'args' => $this->get_import_collection_params(),
),
'schema' => array( $this, 'get_import_public_schema' ),
)
);
}
/**
@ -249,4 +274,42 @@ class WC_Admin_REST_Reports_Import_Controller extends WC_Admin_REST_Reports_Cont
return rest_ensure_response( $data );
}
/**
* Get the status of the current import.
*
* @param WP_REST_Request $request Request data.
* @return WP_Error|WP_REST_Response
*/
public function get_import_status( $request ) {
$result = array(
'is_importing' => WC_Admin_Reports_Sync::is_importing(),
'customers_total' => get_option( 'wc_admin_import_customers_total', 0 ),
'customers_count' => get_option( 'wc_admin_import_customers_count', 0 ),
'orders_total' => get_option( 'wc_admin_import_orders_total', 0 ),
'orders_count' => get_option( 'wc_admin_import_orders_count', 0 ),
'imported_from' => get_option( 'wc_admin_imported_from_date', false ),
);
$response = $this->prepare_item_for_response( $result, $request );
$data = $this->prepare_response_for_collection( $response );
return rest_ensure_response( $data );
}
/**
* Get the total orders and customers based on user supplied params.
*
* @param WP_REST_Request $request Request data.
* @return WP_Error|WP_REST_Response
*/
public function get_import_totals( $request ) {
$query_args = $this->prepare_objects_query( $request );
$totals = WC_Admin_Reports_Sync::get_import_totals( $query_args['days'], $query_args['skip_existing'] );
$response = $this->prepare_item_for_response( $totals, $request );
$data = $this->prepare_response_for_collection( $response );
return rest_ensure_response( $data );
}
}

View File

@ -36,24 +36,16 @@ class WC_Admin_ActionScheduler_WPPostStore extends ActionScheduler_wpPostStore {
/**
* Forcefully delete all pending WC Admin scheduled actions.
*
* Directly trashes items from in database for performance.
*
* @param array $action_types Array of actions to delete.
*/
public function clear_pending_wcadmin_actions() {
public function clear_pending_wcadmin_actions( $action_types ) {
global $wpdb;
// Cancel all pending actions by trashing the posts.
// Action Scheduler will handle the cleanup.
$action_types = array(
WC_Admin_Reports_Sync::QUEUE_BATCH_ACTION,
WC_Admin_Reports_Sync::QUEUE_DEPEDENT_ACTION,
WC_Admin_Reports_Sync::CUSTOMERS_IMPORT_BATCH_ACTION,
WC_Admin_Reports_Sync::ORDERS_IMPORT_BATCH_ACTION,
WC_Admin_Reports_Sync::ORDERS_IMPORT_BATCH_INIT,
WC_Admin_Reports_Sync::SINGLE_ORDER_IMPORT_ACTION,
);
foreach ( $action_types as $action_type ) {
foreach ( (array) $action_types as $action_type ) {
$wpdb->update(
$wpdb->posts,
array(

View File

@ -6,40 +6,14 @@
* @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',
'capability' => 'view_woocommerce_reports',
);
$options = wp_parse_args( $options, $defaults );
add_submenu_page(
'/' === $options['parent'][0] ? "wc-admin#{$options['parent']}" : $options['parent'],
$options['title'],
$options['title'],
$options['capability'],
"wc-admin#{$options['path']}",
array( 'WC_Admin_Loader', 'page_wrapper' )
);
}
}
/**
* WC_Admin_Loader Class.
*/
class WC_Admin_Loader {
/**
* App entry point.
*/
const APP_ENTRY_POINT = 'wc-admin';
/**
* Class instance.
@ -86,7 +60,7 @@ class WC_Admin_Loader {
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.
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 );
}
/**
@ -147,6 +121,9 @@ class WC_Admin_Loader {
* Class loader for enabled WooCommerce Admin features/sections.
*/
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();
foreach ( $features as $feature ) {
$feature = strtolower( $feature );
@ -165,29 +142,23 @@ class WC_Admin_Loader {
* @todo The entry point for the embed needs moved to this class as well.
*/
public static function register_page_handler() {
$page_title = null;
$menu_title = null;
if ( self::is_feature_enabled( 'analytics-dashboard' ) ) {
$page_title = __( 'WooCommerce Dashboard', 'woocommerce-admin' );
$menu_title = __( 'Dashboard', 'woocommerce-admin' );
}
$analytics_cap = apply_filters( 'woocommerce_admin_analytics_menu_capability', 'view_woocommerce_reports' );
add_submenu_page(
'woocommerce',
$page_title,
$menu_title,
$analytics_cap,
'wc-admin',
array( 'WC_Admin_Loader', 'page_wrapper' )
wc_admin_register_page(
array(
'id' => 'woocommerce-dashboard', // Expected to be overridden if dashboard is enabled.
'parent' => 'woocommerce',
'title' => null,
'path' => self::APP_ENTRY_POINT,
)
);
// 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;
// User does not have capabilites to see the submenu.
if ( ! current_user_can( 'manage_woocommerce' ) || empty( $submenu['woocommerce'] ) ) {
@ -196,7 +167,8 @@ class WC_Admin_Loader {
$wc_admin_key = null;
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;
break;
}
@ -206,11 +178,7 @@ class WC_Admin_Loader {
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 );
}
/**
@ -354,11 +322,7 @@ class WC_Admin_Loader {
* Returns true if we are on a JS powered admin page.
*/
public static function is_admin_page() {
$current_screen = get_current_screen();
if ( '_page_wc-admin' === substr( $current_screen->id, -14 ) ) {
return true;
}
return false;
return wc_admin_is_registered_page();
}
/**
@ -367,248 +331,14 @@ class WC_Admin_Loader {
* @todo See usage in `admin.php`. This needs refactored and implemented properly in core.
*/
public static function is_embed_page() {
$is_embed = false;
$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() );
return wc_admin_is_connected_page();
}
/**
* Returns breadcrumbs for the current page.
*
* @todo Refactor: https://github.com/woocommerce/woocommerce-admin/issues/1432.
*/
private static function get_embed_breadcrumbs() {
$current_screen_id = self::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 = '';
$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 '';
}
return wc_admin_get_breadcrumbs();
}
/**
@ -620,9 +350,7 @@ class WC_Admin_Loader {
?>
<span>
<?php if ( is_array( $section ) ) : ?>
<a href="<?php echo esc_url( admin_url( $section[0] ) ); ?>">
<?php echo esc_html( $section[1] ); ?>
</a>
<a href="<?php echo esc_url( admin_url( $section[0] ) ); ?>"><?php echo esc_html( $section[1] ); ?></a>
<?php else : ?>
<?php echo esc_html( $section ); ?>
<?php endif; ?>
@ -646,7 +374,9 @@ class WC_Admin_Loader {
<div class="woocommerce-layout">
<div class="woocommerce-layout__header is-embed-loading">
<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 self::output_breadcrumbs( $section ); ?>
<?php endforeach; ?>
@ -734,22 +464,18 @@ class WC_Admin_Loader {
return $admin_title;
}
if ( self::is_embed_page() ) {
$sections = self::get_embed_breadcrumbs();
$sections = is_array( $sections ) ? $sections : array( $sections );
$pieces = array();
$sections = self::get_embed_breadcrumbs();
$pieces = array();
foreach ( $sections as $section ) {
$pieces[] = is_array( $section ) ? $section[1] : $section;
}
$pieces = array_reverse( $pieces );
$title = implode( ' &lsaquo; ', $pieces );
} else {
$title = __( 'Dashboard', 'woocommerce-admin' );
foreach ( $sections as $section ) {
$pieces[] = is_array( $section ) ? $section[1] : $section;
}
$pieces = array_reverse( $pieces );
$title = implode( ' &lsaquo; ', $pieces );
/* 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

@ -60,7 +60,7 @@ trait WC_Admin_Order_Trait {
if ( $tax_data ) {
foreach ( $order_taxes as $tax_item ) {
$tax_item_id = $tax_item->get_rate_id();
$tax_item_total = isset( $tax_data['total'][ $tax_item_id ] ) ? $tax_data['total'][ $tax_item_id ] : 0;
$tax_item_total = isset( $tax_data['total'][ $tax_item_id ] ) ? (float) $tax_data['total'][ $tax_item_id ] : 0;
$total_shipping_tax_amount += $tax_item_total;
}
}

View File

@ -123,12 +123,77 @@ class WC_Admin_Reports_Sync {
* @return string
*/
public static function regenerate_report_data( $days, $skip_existing ) {
self::reset_import_stats( $days, $skip_existing );
self::customer_lookup_import_batch_init( $days, $skip_existing );
self::queue_dependent_action( self::ORDERS_IMPORT_BATCH_INIT, array( $days, $skip_existing ), self::CUSTOMERS_IMPORT_BATCH_ACTION );
return __( 'Report table data is being rebuilt. Please allow some time for data to fully populate.', 'woocommerce-admin' );
}
/**
* Update the import stat totals and counts.
*
* @param int|bool $days Number of days to import.
* @param bool $skip_existing Skip exisiting records.
*/
public static function reset_import_stats( $days, $skip_existing ) {
$totals = self::get_import_totals( $days, $skip_existing );
update_option( 'wc_admin_import_customers_count', 0 );
update_option( 'wc_admin_import_orders_count', 0 );
update_option( 'wc_admin_import_customers_total', $totals['customers'] );
update_option( 'wc_admin_import_orders_total', $totals['orders'] );
// Update imported from date if older than previous.
$previous_import_date = get_option( 'wc_admin_imported_from_date' );
$current_import_date = $days ? date( 'Y-m-d 00:00:00', time() - ( DAY_IN_SECONDS * $days ) ) : -1;
if ( ! $previous_import_date || -1 === $current_import_date || new DateTime( $previous_import_date ) > new DateTime( $current_import_date ) ) {
update_option( 'wc_admin_imported_from_date', $current_import_date );
}
}
/**
* Get the import totals for customers and orders.
*
* @param int|bool $days Number of days to import.
* @param bool $skip_existing Skip exisiting records.
* @return array
*/
public static function get_import_totals( $days, $skip_existing ) {
$orders = self::get_orders( 1, 1, $days, $skip_existing );
$customer_query = self::get_user_ids_for_batch(
$days,
$skip_existing,
array(
'fields' => 'ID',
'number' => 1,
)
);
return array(
'customers' => $customer_query->get_total(),
'orders' => $orders->total,
);
}
/**
* Returns true if an import is in progress.
*
* @return bool
*/
public static function is_importing() {
$pending_jobs = self::queue()->search(
array(
'status' => 'pending',
'per_page' => 1,
'claimed' => false,
'group' => self::QUEUE_GROUP,
)
);
return ! empty( $pending_jobs );
}
/**
* Clears all queued actions.
*/
@ -137,7 +202,19 @@ class WC_Admin_Reports_Sync {
if ( is_a( $store, 'WC_Admin_ActionScheduler_WPPostStore' ) ) {
// If we're using our data store, call our bespoke deletion method.
$store->clear_pending_wcadmin_actions();
$action_types = array(
self::QUEUE_BATCH_ACTION,
self::QUEUE_DEPEDENT_ACTION,
self::CUSTOMERS_IMPORT_BATCH_ACTION,
self::CUSTOMERS_DELETE_BATCH_INIT,
self::CUSTOMERS_DELETE_BATCH_ACTION,
self::ORDERS_IMPORT_BATCH_ACTION,
self::ORDERS_IMPORT_BATCH_INIT,
self::ORDERS_DELETE_BATCH_INIT,
self::ORDERS_DELETE_BATCH_ACTION,
self::SINGLE_ORDER_IMPORT_ACTION,
);
$store->clear_pending_wcadmin_actions( $action_types );
} else {
self::queue()->cancel_all( null, array(), self::QUEUE_GROUP );
}
@ -247,7 +324,7 @@ class WC_Admin_Reports_Sync {
}
/**
* Get the order IDs and total count that need to be synced.
* Get the order/refund IDs and total count that need to be synced.
*
* @param int $limit Number of records to retrieve.
* @param int $page Page number.
@ -273,14 +350,14 @@ class WC_Admin_Reports_Sync {
$count = $wpdb->get_var(
"SELECT COUNT(*) FROM {$wpdb->posts}
WHERE post_type = 'shop_order'
WHERE post_type IN ( 'shop_order', 'shop_order_refund' )
{$where_clause}"
); // WPCS: unprepared SQL ok.
$order_ids = absint( $count ) > 0 ? $wpdb->get_col(
$wpdb->prepare(
"SELECT ID FROM {$wpdb->posts}
WHERE post_type = 'shop_order'
WHERE post_type IN ( 'shop_order', 'shop_order_refund' )
{$where_clause}
ORDER BY post_date ASC
LIMIT %d
@ -311,6 +388,9 @@ class WC_Admin_Reports_Sync {
foreach ( $orders->order_ids as $order_id ) {
self::orders_lookup_import_order( $order_id );
}
$imported_count = get_option( 'wc_admin_import_orders_count', 0 );
update_option( 'wc_admin_import_orders_count', $imported_count + count( $orders->order_ids ) );
}
/**
@ -556,6 +636,9 @@ class WC_Admin_Reports_Sync {
// @todo Schedule single customer update if this fails?
WC_Admin_Reports_Customers_Data_Store::update_registered_customer( $customer_id );
}
$imported_count = get_option( 'wc_admin_import_customers_count', 0 );
update_option( 'wc_admin_import_customers_count', $imported_count + count( $customer_ids ) );
}
/**

View File

@ -337,24 +337,29 @@ 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
*/
protected function get_customers_by_orders( $orders ) {
global $wpdb;
$customer_lookup_table = $wpdb->prefix . 'wc_customer_lookup';
$customer_ids = array();
$customer_lookup_table = $wpdb->prefix . 'wc_customer_lookup';
$customer_ids = array();
foreach ( $orders as $order ) {
if ( $order['customer_id'] ) {
$customer_ids[] = $order['customer_id'];
$customer_ids[] = intval( $order['customer_id'] );
}
}
$customer_ids = implode( ',', $customer_ids );
$customers = $wpdb->get_results(
if ( empty( $customer_ids ) ) {
return array();
}
$customer_ids = implode( ',', $customer_ids );
$customers = $wpdb->get_results(
"SELECT * FROM {$customer_lookup_table} WHERE customer_id IN ({$customer_ids})",
ARRAY_A
); // WPCS: cache ok, DB call ok, unprepared SQL ok.

View File

@ -10,6 +10,11 @@
* Contains backend logic for the dashboard feature.
*/
class WC_Admin_Analytics_Dashboard {
/**
* Menu slug.
*/
const MENU_SLUG = 'wc-admin';
/**
* Class instance.
*
@ -33,6 +38,9 @@ class WC_Admin_Analytics_Dashboard {
public function __construct() {
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_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();

View File

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

View File

@ -13,16 +13,6 @@ defined( 'ABSPATH' ) || exit;
* 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.
*/
@ -62,6 +52,8 @@ class WC_Admin_Notes_Order_Milestones {
* @var array
*/
protected $milestones = array(
1,
10,
100,
250,
500,
@ -101,10 +93,6 @@ class WC_Admin_Notes_Order_Milestones {
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' ) );
}
@ -130,59 +118,6 @@ class WC_Admin_Notes_Order_Milestones {
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.
*
@ -230,6 +165,103 @@ class WC_Admin_Notes_Order_Milestones {
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.
*/
@ -248,21 +280,14 @@ class WC_Admin_Notes_Order_Milestones {
// Add the milestone 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( $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_title( $this->get_note_title_for_milestone( $current_milestone ) );
$note->set_content( $this->get_note_content_for_milestone( $current_milestone ) );
$note_action = $this->get_note_action_for_milestone( $current_milestone );
$note->add_action( $note_action['name'], $note_action['label'], $note_action['query'] );
$note->set_type( WC_Admin_Note::E_WC_ADMIN_NOTE_INFORMATIONAL );
$note->set_icon( 'trophy' );
$note->set_name( self::ORDERS_MILESTONE_NOTE_NAME );
$note->set_source( 'woocommerce-admin' );
$note->add_action( 'review-orders', __( 'Review your orders', 'woocommerce-admin' ), '?page=wc-admin#/analytics/orders' );
$note->save();
}
}

View File

@ -17,6 +17,11 @@ class WC_Admin_Notes {
*/
const UNSNOOZE_HOOK = 'wc_admin_unsnooze_admin_notes';
/**
* Action scheduler group.
*/
const QUEUE_GROUP = 'wc-admin-notes';
/**
* Hook appropriate actions.
*/
@ -131,7 +136,22 @@ class WC_Admin_Notes {
$next = $queue->get_next( self::UNSNOOZE_HOOK );
if ( ! $next ) {
$queue->schedule_recurring( time(), HOUR_IN_SECONDS, self::UNSNOOZE_HOOK, array(), WC_Admin_Reports_Sync::QUEUE_GROUP );
$queue->schedule_recurring( time(), HOUR_IN_SECONDS, self::UNSNOOZE_HOOK, array(), self::QUEUE_GROUP );
}
}
/**
* Clears all queued actions.
*/
public static function clear_queued_actions() {
$store = ActionScheduler::store();
if ( is_a( $store, 'WC_Admin_ActionScheduler_WPPostStore' ) ) {
// If we're using our data store, call our bespoke deletion method.
$action_types = array( self::UNSNOOZE_HOOK );
$store->clear_pending_wcadmin_actions( $action_types );
} else {
self::queue()->cancel_all( null, array(), self::QUEUE_GROUP );
}
}
}

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

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,7 @@
/** @format */
.woocommerce-ellipsis-menu {
text-align: center;
}
.woocommerce-ellipsis-menu__toggle {
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 {
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() {
@ -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 {
margin: $gap 0;
display: grid;
@ -149,16 +138,22 @@ $inner-border: $core-grey-light-500;
@include make-cols( 4 );
}
&.has-5-items,
&.has-9-items,
&.has-10-items {
&.has-5-items {
@include make-cols( 5 );
@include wrap-contents;
}
&.has-6-items {
@include make-cols( 6 );
@include wrap-contents;
@include breakpoint( '>1440px' ) {
&.has-6-items {
@include make-cols( 6 );
@include wrap-contents;
}
&.has-9-items,
&.has-10-items {
@include make-cols( 5 );
@include wrap-contents;
}
}
@include breakpoint( '<1440px' ) {
@ -171,11 +166,11 @@ $inner-border: $core-grey-light-500;
&.has-6-items,
&.has-9-items {
@include make-cols( 3 );
@include reset-wrap;
}
&.has-10-items {
@include make-cols( 4 );
@include wrap-contents;
}
&.has-9-items,
@ -221,7 +216,7 @@ $inner-border: $core-grey-light-500;
&:last-of-type .woocommerce-summary__item {
// 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 {
@ -285,10 +280,12 @@ $inner-border: $core-grey-light-500;
}
.woocommerce-summary__item {
display: block;
display: flex;
flex-direction: column;
height: 100%;
padding: $spacing;
background-color: $core-grey-light-100;
border-bottom: 1px solid $outer-border;
border-bottom: 1px solid $inner-border;
border-right: 1px solid $inner-border;
line-height: 1.4em;
text-decoration: none;
@ -324,6 +321,10 @@ $inner-border: $core-grey-light-500;
}
}
.woocommerce-summary__item-data {
margin-top: auto;
}
.woocommerce-summary__item-label {
display: block;
margin-bottom: $gap;

View File

@ -285,4 +285,97 @@ class WC_Tests_API_Reports_Import extends WC_REST_Unit_Test_Case {
$this->assertEquals( 200, $response->get_status() );
$this->assertCount( 0, $reports );
}
/**
* Test import status and totals query.
*/
public function test_import_status() {
// Delete any pending actions that weren't fully run.
WC_Admin_Reports_Sync::clear_queued_actions();
wp_set_current_user( $this->user );
// Populate all of the data.
$product = new WC_Product_Simple();
$product->set_name( 'Test Product' );
$product->set_regular_price( 25 );
$product->save();
for ( $i = 0; $i < 5; $i++ ) {
$order = WC_Helper_Order::create_order( 1, $product );
$order->set_status( 'completed' );
$order->set_date_created( time() - ( ( $i + 1 ) * DAY_IN_SECONDS ) );
$order->save();
}
// Test totals and total params.
$request = new WP_REST_Request( 'GET', $this->endpoint . '/totals' );
$response = $this->server->dispatch( $request );
$report = $response->get_data();
$user_query = new WP_User_Query(
array(
'fields' => 'ID',
'number' => 1,
)
);
$this->assertEquals( 200, $response->get_status() );
$this->assertEquals( $i, $report['orders'] );
$this->assertEquals( $user_query->get_total(), $report['customers'] );
// Test totals with days param.
$request = new WP_REST_Request( 'GET', $this->endpoint . '/totals' );
$request->set_query_params( array( 'days' => 2 ) );
$response = $this->server->dispatch( $request );
$report = $response->get_data();
$this->assertEquals( 200, $response->get_status() );
$this->assertEquals( 2, $report['orders'] );
// Test import status.
$request = new WP_REST_Request( 'POST', $this->endpoint );
$response = $this->server->dispatch( $request );
$report = $response->get_data();
$this->assertEquals( 200, $response->get_status() );
$this->assertEquals( 'success', $report['status'] );
$request = new WP_REST_Request( 'GET', $this->endpoint . '/status' );
$response = $this->server->dispatch( $request );
$report = $response->get_data();
$this->assertEquals( 200, $response->get_status() );
$this->assertEquals( true, $report['is_importing'] );
$this->assertEquals( 0, $report['customers_count'] );
$this->assertEquals( 3, $report['customers_total'] );
$this->assertEquals( 0, $report['orders_count'] );
$this->assertEquals( 5, $report['orders_total'] );
// Run pending thrice to process batch and order.
WC_Helper_Queue::process_pending();
WC_Helper_Queue::process_pending();
WC_Helper_Queue::process_pending();
// Test import status after processing.
$request = new WP_REST_Request( 'GET', $this->endpoint . '/status' );
$response = $this->server->dispatch( $request );
$report = $response->get_data();
$this->assertEquals( 200, $response->get_status() );
$this->assertEquals( false, $report['is_importing'] );
$this->assertEquals( 3, $report['customers_count'] );
$this->assertEquals( 3, $report['customers_total'] );
$this->assertEquals( 5, $report['orders_count'] );
$this->assertEquals( 5, $report['orders_total'] );
// Test totals with skip existing param.
$request = new WP_REST_Request( 'GET', $this->endpoint . '/totals' );
$request->set_query_params( array( 'skip_existing' => 1 ) );
$response = $this->server->dispatch( $request );
$report = $response->get_data();
// @todo The following line should be uncommented when https://github.com/woocommerce/woocommerce-admin/issues/2195 is resolved.
// $this->assertEquals( 0, $report['customers'] );
$this->assertEquals( 0, $report['orders'] );
}
}

View File

@ -40,4 +40,18 @@ class WC_Helper_Queue {
$job->execute();
}
}
/**
* Run all pending queued actions.
*
* @return void
*/
public static function process_pending() {
$jobs = self::get_all_pending();
$queue_runner = new ActionScheduler_QueueRunner();
foreach ( $jobs as $job_id => $job ) {
$queue_runner->process_action( $job_id );
}
}
}

View File

@ -169,6 +169,10 @@ function wc_admin_activate_wc_admin_plugin() {
if ( ! wp_next_scheduled( 'wc_admin_daily' ) ) {
wp_schedule_event( time(), 'daily', 'wc_admin_daily' );
}
// Run the installer on activation.
require_once WC_ADMIN_ABSPATH . 'includes/class-wc-admin-install.php';
WC_Admin_Install::create_tables();
}
register_activation_hook( WC_ADMIN_PLUGIN_FILE, 'wc_admin_activate_wc_admin_plugin' );
@ -190,6 +194,7 @@ function wc_admin_deactivate_wc_admin_plugin() {
if ( wc_admin_dependencies_satisfied() ) {
wp_clear_scheduled_hook( 'wc_admin_daily' );
WC_Admin_Reports_Sync::clear_queued_actions();
WC_Admin_Notes::clear_queued_actions();
}
}
register_deactivation_hook( WC_ADMIN_PLUGIN_FILE, 'wc_admin_deactivate_wc_admin_plugin' );