Allow HPOS screens to work for custom order types (#35658)
* Allow `wc_get_order_types()` to return list of order types that have UI * Make `PageController` register menu items for all order types required * Make `PageController` URL generation aware of order types * Make `ListTable` order type aware * Make `Edit` order type aware * Add support to `wc_get_page_screen_id()` for order types * Make `PageController` order type aware * Include custom order type screens as WC screens * Make `get_base_page_url()` in `PageController` public * Make sure Trash links use the correct URL * Gather request vars in `$request` in list table * Add some order type specific filters to ListTable * Fix wrong reference to orders per page in ListTable * Make ListTable columns work in all screens * Make PHPCS happy * Minor PHPCS fix * Add changelog * Set page hidden form field based on the order_type (#35751) * Add ‘woocommerce_order_list_table_extra_tablenav’ hook * Fix PHPCS warnings * Make `wc_get_page_screen_id()` datastore aware * Make `WC_Admin_Assets::is_order_meta_box_screen()` aware of HPOS screen IDs * Remove unnecessary `$context` arg from `wc_get_page_screen_id()` * Add support for custom order types to `PostsRedirectionController` * Make PHPCS happy * Only connect COT admin page when COT is enabled * Properly filter out empty status in ListTable * Fix warning due to uninitialized var * Do not rely on `wc_orders_count()` for counting orders in `ListTable` `wc_orders_count()` assumes that order types correspond to a datastore’s object type, which isn’t necessarily the case, producing incorrect results. Until this is addressed, it’d be best not to rely on it for types other than orders. * Improve performance for status counts in ListTable * Fire both order-type specific and generic hook for default column in ListTable Co-authored-by: bruce aldridge <bruce.aldridge@automattic.com>
This commit is contained in:
parent
c7132ec8f0
commit
778cb130f2
|
@ -0,0 +1,4 @@
|
|||
Significance: minor
|
||||
Type: add
|
||||
|
||||
Add support for custom order types in HPOS admin UI.
|
|
@ -540,8 +540,16 @@ if ( ! class_exists( 'WC_Admin_Assets', false ) ) :
|
|||
* @return bool Whether the current screen is an order edit screen.
|
||||
*/
|
||||
private function is_order_meta_box_screen( $screen_id ) {
|
||||
return in_array( str_replace( 'edit-', '', $screen_id ), wc_get_order_types( 'order-meta-boxes' ), true ) ||
|
||||
wc_get_page_screen_id( 'shop-order' ) === $screen_id;
|
||||
$screen_id = str_replace( 'edit-', '', $screen_id );
|
||||
|
||||
$types_with_metaboxes_screen_ids = array_filter(
|
||||
array_map(
|
||||
'wc_get_page_screen_id',
|
||||
wc_get_order_types( 'order-meta-boxes' )
|
||||
)
|
||||
);
|
||||
|
||||
return in_array( $screen_id, $types_with_metaboxes_screen_ids, true );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
* @version 2.1.0
|
||||
*/
|
||||
|
||||
use Automattic\WooCommerce\Internal\Admin\Orders\PageController;
|
||||
use Automattic\WooCommerce\Utilities\OrderUtil;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
|
@ -97,7 +98,8 @@ class WC_Meta_Box_Order_Actions {
|
|||
*/
|
||||
private static function get_trash_or_delete_order_link( int $order_id ): string {
|
||||
if ( OrderUtil::custom_orders_table_usage_is_enabled() ) {
|
||||
$order_list_url = admin_url( 'admin.php?page=wc-orders' );
|
||||
$order_type = wc_get_order( $order_id )->get_type();
|
||||
$order_list_url = wc_get_container()->get( PageController::class )->get_base_page_url( $order_type );
|
||||
$trash_order_url = add_query_arg(
|
||||
array(
|
||||
'action' => 'trash',
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
* @version 2.4.0
|
||||
*/
|
||||
|
||||
use Automattic\WooCommerce\Utilities\OrderUtil;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
@ -39,12 +41,12 @@ function wc_get_screen_ids() {
|
|||
'edit-product_tag',
|
||||
'profile',
|
||||
'user-edit',
|
||||
wc_get_page_screen_id( 'shop-order' ),
|
||||
);
|
||||
|
||||
foreach ( wc_get_order_types() as $type ) {
|
||||
$screen_ids[] = $type;
|
||||
$screen_ids[] = 'edit-' . $type;
|
||||
$screen_ids[] = wc_get_page_screen_id( $type );
|
||||
}
|
||||
|
||||
$attributes = wc_get_attribute_taxonomies();
|
||||
|
@ -68,11 +70,18 @@ function wc_get_screen_ids() {
|
|||
* @return string Page ID. Empty string if resource not found.
|
||||
*/
|
||||
function wc_get_page_screen_id( $for ) {
|
||||
switch ( $for ) {
|
||||
case 'shop-order':
|
||||
return 'woocommerce_page_wc-orders';
|
||||
$screen_id = '';
|
||||
$for = str_replace( '-', '_', $for );
|
||||
|
||||
if ( in_array( $for, wc_get_order_types( 'admin-menu' ), true ) ) {
|
||||
if ( OrderUtil::custom_orders_table_usage_is_enabled() ) {
|
||||
$screen_id = 'woocommerce_page_wc-orders' . ( 'shop_order' === $for ? '' : '--' . $for );
|
||||
} else {
|
||||
$screen_id = $for;
|
||||
}
|
||||
}
|
||||
return '';
|
||||
|
||||
return $screen_id;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
use Automattic\WooCommerce\Admin\PageController;
|
||||
use Automattic\WooCommerce\Admin\Features\Features;
|
||||
use Automattic\WooCommerce\Utilities\OrderUtil;
|
||||
|
||||
/**
|
||||
* Returns core WC pages to connect to WC-Admin.
|
||||
|
@ -135,16 +136,6 @@ wc_admin_connect_page(
|
|||
)
|
||||
);
|
||||
|
||||
// WooCommerce > Orders (COT).
|
||||
wc_admin_connect_page(
|
||||
array(
|
||||
'id' => 'woocommerce-custom-orders',
|
||||
'screen_id' => wc_get_page_screen_id( 'shop-order' ),
|
||||
'title' => __( 'Orders', 'woocommerce' ),
|
||||
'path' => 'admin.php?page=wc-orders',
|
||||
)
|
||||
);
|
||||
|
||||
// WooCommerce > Orders > Add New.
|
||||
wc_admin_connect_page(
|
||||
array(
|
||||
|
@ -165,6 +156,18 @@ wc_admin_connect_page(
|
|||
)
|
||||
);
|
||||
|
||||
if ( OrderUtil::custom_orders_table_usage_is_enabled() ) {
|
||||
// WooCommerce > Orders (COT).
|
||||
wc_admin_connect_page(
|
||||
array(
|
||||
'id' => 'woocommerce-custom-orders',
|
||||
'screen_id' => wc_get_page_screen_id( 'shop-order' ),
|
||||
'title' => __( 'Orders', 'woocommerce' ),
|
||||
'path' => 'admin.php?page=wc-orders',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// WooCommerce > Coupons.
|
||||
wc_admin_connect_page(
|
||||
array(
|
||||
|
|
|
@ -244,6 +244,17 @@ function wc_get_order_types( $for = '' ) {
|
|||
}
|
||||
}
|
||||
break;
|
||||
case 'admin-menu':
|
||||
$order_types = array_intersect(
|
||||
array_keys( $wc_order_types ),
|
||||
get_post_types(
|
||||
array(
|
||||
'show_ui' => true,
|
||||
'show_in_menu' => 'woocommerce',
|
||||
)
|
||||
)
|
||||
);
|
||||
break;
|
||||
default:
|
||||
$order_types = array_keys( $wc_order_types );
|
||||
break;
|
||||
|
|
|
@ -188,18 +188,20 @@ class Edit {
|
|||
* @param string $message Message to display, if any.
|
||||
*/
|
||||
private function render_wrapper_start( $notice = '', $message = '' ) {
|
||||
$edit_page_url = admin_url( 'admin.php?page=wc-orders&action=edit&id=' . $this->order->get_id() );
|
||||
$post_type = get_post_type_object( $this->order->get_type() );
|
||||
|
||||
$edit_page_url = wc_get_container()->get( PageController::class )->get_edit_url( $this->order->get_id() );
|
||||
$form_action = 'edit_order';
|
||||
$referer = wp_get_referer();
|
||||
$new_page_url = wc_get_container()->get( PageController::class )->get_new_page_url();
|
||||
$new_page_url = wc_get_container()->get( PageController::class )->get_new_page_url( $this->order->get_type() );
|
||||
|
||||
?>
|
||||
<div class="wrap">
|
||||
<h1 class="wp-heading-inline">
|
||||
<?php echo esc_html( 'Edit order' ); ?>
|
||||
<?php echo esc_html( $post_type->labels->edit_item ); ?>
|
||||
</h1>
|
||||
<?php
|
||||
echo ' <a href="' . esc_url( $new_page_url ) . '" class="page-title-action"> Add order </a>';
|
||||
echo ' <a href="' . esc_url( $new_page_url ) . '" class="page-title-action">' . esc_html( $post_type->labels->add_new ) . '</a>';
|
||||
?>
|
||||
<hr class="wp-header-end">
|
||||
|
||||
|
|
|
@ -12,6 +12,21 @@ use WP_Screen;
|
|||
* Admin list table for orders as managed by the OrdersTableDataStore.
|
||||
*/
|
||||
class ListTable extends WP_List_Table {
|
||||
|
||||
/**
|
||||
* Order type.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $order_type;
|
||||
|
||||
/**
|
||||
* Request vars.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $request = array();
|
||||
|
||||
/**
|
||||
* Contains the arguments to be used in the order query.
|
||||
*
|
||||
|
@ -40,6 +55,13 @@ class ListTable extends WP_List_Table {
|
|||
*/
|
||||
private $is_trash = false;
|
||||
|
||||
/**
|
||||
* Caches order counts by status.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $status_count_cache = null;
|
||||
|
||||
/**
|
||||
* Sets up the admin list table for orders (specifically, for orders managed by the OrdersTableDataStore).
|
||||
*
|
||||
|
@ -68,18 +90,23 @@ class ListTable extends WP_List_Table {
|
|||
/**
|
||||
* Performs setup work required before rendering the table.
|
||||
*
|
||||
* @param array $args Args to initialize this list table.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setup(): void {
|
||||
public function setup( $args = array() ): void {
|
||||
$this->order_type = $args['order_type'] ?? 'shop_order';
|
||||
|
||||
add_action( 'admin_notices', array( $this, 'bulk_action_notices' ) );
|
||||
add_filter( 'manage_woocommerce_page_wc-orders_columns', array( $this, 'get_columns' ), 0 );
|
||||
add_filter( 'set_screen_option_edit_orders_per_page', array( $this, 'set_items_per_page' ), 10, 3 );
|
||||
add_filter( "manage_{$this->screen->id}_columns", array( $this, 'get_columns' ), 0 );
|
||||
add_filter( 'set_screen_option_edit_' . $this->order_type . '_per_page', array( $this, 'set_items_per_page' ), 10, 3 );
|
||||
add_filter( 'default_hidden_columns', array( $this, 'default_hidden_columns' ), 10, 2 );
|
||||
add_action( 'admin_footer', array( $this, 'enqueue_scripts' ) );
|
||||
|
||||
$this->items_per_page();
|
||||
set_screen_options();
|
||||
add_action( 'manage_' . wc_get_page_screen_id( 'shop-order' ) . '_custom_column', array( $this, 'render_column' ), 10, 2 );
|
||||
|
||||
add_action( 'manage_' . wc_get_page_screen_id( $this->order_type ) . '_custom_column', array( $this, 'render_column' ), 10, 2 );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -105,6 +132,17 @@ class ListTable extends WP_List_Table {
|
|||
* @param string $column_name Identifier for the custom column.
|
||||
*/
|
||||
public function column_default( $order, $column_name ) {
|
||||
/**
|
||||
* Fires for each custom column for a specific order type. This hook takes precedence over the generic
|
||||
* action `manage_{$this->screen->id}_custom_column`.
|
||||
*
|
||||
* @param string $column_name Identifier for the custom column.
|
||||
* @param \WC_Order $order Current WooCommerce order object.
|
||||
*
|
||||
* @since 7.3.0
|
||||
*/
|
||||
do_action( 'woocommerce_' . $this->order_type . '_list_table_custom_column', $column_name, $order );
|
||||
|
||||
/**
|
||||
* Fires for each custom column in the Custom Order Table in the administrative screen.
|
||||
*
|
||||
|
@ -124,7 +162,7 @@ class ListTable extends WP_List_Table {
|
|||
'per_page',
|
||||
array(
|
||||
'default' => 20,
|
||||
'option' => 'edit_orders_per_page',
|
||||
'option' => 'edit_' . $this->order_type . '_per_page',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -139,7 +177,7 @@ class ListTable extends WP_List_Table {
|
|||
* @return mixed
|
||||
*/
|
||||
public function set_items_per_page( $default, string $option, int $value ) {
|
||||
return 'edit_orders_per_page' === $option ? absint( $value ) : $default;
|
||||
return 'edit_' . $this->order_type . '_per_page' === $option ? absint( $value ) : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -148,9 +186,11 @@ class ListTable extends WP_List_Table {
|
|||
* @return void
|
||||
*/
|
||||
public function display() {
|
||||
$title = esc_html__( 'Orders', 'woocommerce' );
|
||||
$add_new = esc_html__( 'Add Order', 'woocommerce' );
|
||||
$new_page_link = $this->page_controller->get_new_page_url();
|
||||
$post_type = get_post_type_object( $this->order_type );
|
||||
|
||||
$title = esc_html( $post_type->labels->name );
|
||||
$add_new = esc_html( $post_type->labels->add_new );
|
||||
$new_page_link = $this->page_controller->get_new_page_url( $this->order_type );
|
||||
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo wp_kses_post(
|
||||
|
@ -240,15 +280,28 @@ class ListTable extends WP_List_Table {
|
|||
* Prepares the list of items for displaying.
|
||||
*/
|
||||
public function prepare_items() {
|
||||
$limit = $this->get_items_per_page( 'edit_orders_per_page' );
|
||||
$limit = $this->get_items_per_page( 'edit_' . $this->order_type . '_per_page' );
|
||||
|
||||
$this->order_query_args = array(
|
||||
'limit' => $limit,
|
||||
'page' => $this->get_pagenum(),
|
||||
'paginate' => true,
|
||||
'type' => 'shop_order',
|
||||
'type' => $this->order_type,
|
||||
);
|
||||
|
||||
foreach ( array( 'status', 's', 'm', '_customer_user' ) as $query_var ) {
|
||||
$this->request[ $query_var ] = sanitize_text_field( wp_unslash( $_REQUEST[ $query_var ] ?? '' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows 3rd parties to filter the initial request vars before defaults and other logic is applied.
|
||||
*
|
||||
* @param array $request Request to be passed to `wc_get_orders()`.
|
||||
*
|
||||
* @since 7.3.0
|
||||
*/
|
||||
$this->request = apply_filters( 'woocommerce_' . $this->order_type . '_list_table_request', $this->request );
|
||||
|
||||
$this->set_status_args();
|
||||
$this->set_order_args();
|
||||
$this->set_date_args();
|
||||
|
@ -265,6 +318,15 @@ class ListTable extends WP_List_Table {
|
|||
*/
|
||||
$order_query_args = (array) apply_filters( 'woocommerce_order_list_table_prepare_items_query_args', $this->order_query_args );
|
||||
|
||||
/**
|
||||
* Same as `woocommerce_order_list_table_prepare_items_query_args` but for a specific order type.
|
||||
*
|
||||
* @param array $query_args Arguments to be passed to `wc_get_orders()`.
|
||||
*
|
||||
* @since 7.3.0
|
||||
*/
|
||||
$order_query_args = apply_filters( 'woocommerce_' . $this->order_type . '_list_table_prepare_items_query_args', $this->order_query_args );
|
||||
|
||||
// We must ensure the 'paginate' argument is set.
|
||||
$order_query_args['paginate'] = true;
|
||||
|
||||
|
@ -291,7 +353,7 @@ class ListTable extends WP_List_Table {
|
|||
);
|
||||
|
||||
// Are we inside the trash?
|
||||
$this->is_trash = isset( $_REQUEST['status'] ) && 'trash' === $_REQUEST['status'];
|
||||
$this->is_trash = 'trash' === $this->request['status'];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -351,27 +413,35 @@ class ListTable extends WP_List_Table {
|
|||
* Implements filtering of orders by status.
|
||||
*/
|
||||
private function set_status_args() {
|
||||
$status = trim( sanitize_text_field( wp_unslash( $_REQUEST['status'] ?? '' ) ) );
|
||||
$query_statuses = array();
|
||||
$status = array_filter( array_map( 'trim', (array) $this->request['status'] ) );
|
||||
|
||||
if ( empty( $status ) || 'all' === $status ) {
|
||||
$query_statuses = array_intersect(
|
||||
array_keys( wc_get_order_statuses() ),
|
||||
get_post_stati( array( 'show_in_admin_all_list' => true ), 'names' )
|
||||
if ( empty( $status ) || in_array( 'all', $status, true ) ) {
|
||||
/**
|
||||
* Allows 3rd parties to set the default list of statuses for a given order type.
|
||||
*
|
||||
* @param string[] $statuses Statuses.
|
||||
*
|
||||
* @since 7.3.0
|
||||
*/
|
||||
$status = apply_filters(
|
||||
'woocommerce_' . $this->order_type . '_list_table_default_statuses',
|
||||
array_intersect(
|
||||
array_keys( wc_get_order_statuses() ),
|
||||
get_post_stati( array( 'show_in_admin_all_list' => true ), 'names' )
|
||||
)
|
||||
);
|
||||
} else {
|
||||
$query_statuses[] = $status;
|
||||
$this->has_filter = true;
|
||||
}
|
||||
|
||||
$this->order_query_args['status'] = $query_statuses;
|
||||
$this->order_query_args['status'] = $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements order search.
|
||||
*/
|
||||
private function set_search_args(): void {
|
||||
$search_term = trim( sanitize_text_field( wp_unslash( $_REQUEST['s'] ?? '' ) ) );
|
||||
$search_term = trim( sanitize_text_field( $this->request['s'] ) );
|
||||
|
||||
if ( ! empty( $search_term ) ) {
|
||||
$this->order_query_args['s'] = $search_term;
|
||||
|
@ -389,7 +459,7 @@ class ListTable extends WP_List_Table {
|
|||
$view_counts = array();
|
||||
$view_links = array();
|
||||
$statuses = $this->get_visible_statuses();
|
||||
$current = isset( $_GET['status'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['status'] ?? '' ) ) : 'all';
|
||||
$current = ! empty( $this->request['status'] ) ? sanitize_text_field( $this->request['status'] ) : 'all';
|
||||
$all_count = 0;
|
||||
|
||||
foreach ( array_keys( $statuses ) as $slug ) {
|
||||
|
@ -421,13 +491,40 @@ class ListTable extends WP_List_Table {
|
|||
* @return int
|
||||
*/
|
||||
private function count_orders_by_status( $status ): int {
|
||||
return array_sum(
|
||||
array_map(
|
||||
function( $order_status ) {
|
||||
return wc_orders_count( $order_status, 'shop_order' );
|
||||
},
|
||||
(array) $status
|
||||
)
|
||||
global $wpdb;
|
||||
|
||||
// Compute all counts and cache if necessary.
|
||||
if ( is_null( $this->status_count_cache ) ) {
|
||||
$orders_table = OrdersTableDataStore::get_orders_table_name();
|
||||
|
||||
$res = $wpdb->get_results(
|
||||
$wpdb->prepare(
|
||||
"SELECT status, COUNT(*) AS cnt FROM {$orders_table} WHERE type = %s GROUP BY status", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
|
||||
$this->order_type
|
||||
),
|
||||
ARRAY_A
|
||||
);
|
||||
|
||||
$this->status_count_cache =
|
||||
$res
|
||||
? array_combine( array_column( $res, 'status' ), array_map( 'absint', array_column( $res, 'cnt' ) ) )
|
||||
: array();
|
||||
}
|
||||
|
||||
$status = (array) $status;
|
||||
$count = array_sum( array_intersect_key( $this->status_count_cache, array_flip( $status ) ) );
|
||||
|
||||
/**
|
||||
* Allows 3rd parties to modify the count of orders by status.
|
||||
*
|
||||
* @param int $count Number of orders for the given status.
|
||||
* @param string[] $status List of order statuses in the count.
|
||||
* @since 7.3.0
|
||||
*/
|
||||
return apply_filters(
|
||||
'woocommerce_' . $this->order_type . '_list_table_order_count',
|
||||
$count,
|
||||
$status
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -470,10 +567,11 @@ class ListTable extends WP_List_Table {
|
|||
* @return string
|
||||
*/
|
||||
private function get_view_link( string $slug, string $name, int $count, bool $current ): string {
|
||||
$url = esc_url( add_query_arg( 'status', $slug, get_admin_url( null, 'admin.php?page=wc-orders' ) ) );
|
||||
$name = esc_html( $name );
|
||||
$count = absint( $count );
|
||||
$class = $current ? 'class="current"' : '';
|
||||
$base_url = get_admin_url( null, 'admin.php?page=wc-orders' . ( 'shop_order' === $this->order_type ? '' : '--' . $this->order_type ) );
|
||||
$url = esc_url( add_query_arg( 'status', $slug, $base_url ) );
|
||||
$name = esc_html( $name );
|
||||
$count = absint( $count );
|
||||
$class = $current ? 'class="current"' : '';
|
||||
|
||||
return "<a href='$url' $class>$name <span class='count'>($count)</span></a>";
|
||||
}
|
||||
|
@ -487,10 +585,26 @@ class ListTable extends WP_List_Table {
|
|||
echo '<div class="alignleft actions">';
|
||||
|
||||
if ( 'top' === $which ) {
|
||||
ob_start();
|
||||
|
||||
$this->months_filter();
|
||||
$this->customers_filter();
|
||||
|
||||
submit_button( __( 'Filter', 'woocommerce' ), '', 'filter_action', false, array( 'id' => 'order-query-submit' ) );
|
||||
/**
|
||||
* Fires before the "Filter" button on the list table for orders and other order types.
|
||||
*
|
||||
* @since x.x.x
|
||||
* @param string $order_type The order type.
|
||||
* @param string $which The location of the extra table nav: 'top' or 'bottom'.
|
||||
*/
|
||||
do_action( 'woocommerce_order_list_table_extra_tablenav', $this->order_type, $which );
|
||||
|
||||
$output = ob_get_clean();
|
||||
|
||||
if ( ! empty( $output ) ) {
|
||||
echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
submit_button( __( 'Filter', 'woocommerce' ), '', 'filter_action', false, array( 'id' => 'order-query-submit' ) );
|
||||
}
|
||||
}
|
||||
|
||||
if ( $this->is_trash && $this->has_items() && current_user_can( 'edit_others_shop_orders' ) ) {
|
||||
|
@ -590,15 +704,25 @@ class ListTable extends WP_List_Table {
|
|||
* @return array
|
||||
*/
|
||||
public function get_columns() {
|
||||
return array(
|
||||
'cb' => '<input type="checkbox" />',
|
||||
'order_number' => esc_html__( 'Order', 'woocommerce' ),
|
||||
'order_date' => esc_html__( 'Date', 'woocommerce' ),
|
||||
'order_status' => esc_html__( 'Status', 'woocommerce' ),
|
||||
'billing_address' => esc_html__( 'Billing', 'woocommerce' ),
|
||||
'shipping_address' => esc_html__( 'Ship to', 'woocommerce' ),
|
||||
'order_total' => esc_html__( 'Total', 'woocommerce' ),
|
||||
'wc_actions' => esc_html__( 'Actions', 'woocommerce' ),
|
||||
/**
|
||||
* Filters the list of columns.
|
||||
*
|
||||
* @param array $columns List of sortable columns.
|
||||
*
|
||||
* @since 7.3.0
|
||||
*/
|
||||
return apply_filters(
|
||||
'woocommerce_' . $this->order_type . '_list_table_columns',
|
||||
array(
|
||||
'cb' => '<input type="checkbox" />',
|
||||
'order_number' => esc_html__( 'Order', 'woocommerce' ),
|
||||
'order_date' => esc_html__( 'Date', 'woocommerce' ),
|
||||
'order_status' => esc_html__( 'Status', 'woocommerce' ),
|
||||
'billing_address' => esc_html__( 'Billing', 'woocommerce' ),
|
||||
'shipping_address' => esc_html__( 'Ship to', 'woocommerce' ),
|
||||
'order_total' => esc_html__( 'Total', 'woocommerce' ),
|
||||
'wc_actions' => esc_html__( 'Actions', 'woocommerce' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -608,10 +732,20 @@ class ListTable extends WP_List_Table {
|
|||
* @return string[]
|
||||
*/
|
||||
public function get_sortable_columns() {
|
||||
return array(
|
||||
'order_number' => 'ID',
|
||||
'order_date' => 'date',
|
||||
'order_total' => 'order_total',
|
||||
/**
|
||||
* Filters the list of sortable columns.
|
||||
*
|
||||
* @param array $sortable_columns List of sortable columns.
|
||||
*
|
||||
* @since 7.3.0
|
||||
*/
|
||||
return apply_filters(
|
||||
'woocommerce_' . $this->order_type . '_list_table_sortable_columns',
|
||||
array(
|
||||
'order_number' => 'ID',
|
||||
'order_date' => 'date',
|
||||
'order_total' => 'order_total',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -907,7 +1041,7 @@ class ListTable extends WP_List_Table {
|
|||
* @return void
|
||||
*/
|
||||
private function print_hidden_form_fields(): void {
|
||||
echo '<input type="hidden" name="page" value="wc-orders" >';
|
||||
echo '<input type="hidden" name="page" value="wc-orders' . ( 'shop_order' === $this->order_type ? '' : '--' . $this->order_type ) . '" >'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
|
||||
$state_params = array(
|
||||
'paged',
|
||||
|
@ -955,7 +1089,7 @@ class ListTable extends WP_List_Table {
|
|||
// Get all trashed orders.
|
||||
$ids = wc_get_orders(
|
||||
array(
|
||||
'type' => 'shop_order',
|
||||
'type' => $this->order_type,
|
||||
'status' => 'trash',
|
||||
'limit' => -1,
|
||||
'return' => 'ids',
|
||||
|
|
|
@ -11,6 +11,13 @@ class PageController {
|
|||
|
||||
use AccessiblePrivateMethods;
|
||||
|
||||
/**
|
||||
* The order type.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $order_type = '';
|
||||
|
||||
/**
|
||||
* Instance of the posts redirection controller.
|
||||
*
|
||||
|
@ -55,9 +62,15 @@ class PageController {
|
|||
if ( 'edit_order' === $this->current_action && ( ! isset( $this->order ) || ! $this->order ) ) {
|
||||
wp_die( esc_html__( 'You attempted to edit an order that does not exist. Perhaps it was deleted?', 'woocommerce' ) );
|
||||
}
|
||||
if ( ! current_user_can( 'edit_others_shop_orders' ) && ! current_user_can( 'manage_woocommerce' ) ) {
|
||||
|
||||
if ( $this->order->get_type() !== $this->order_type ) {
|
||||
wp_die( esc_html__( 'Order type mismatch.', 'woocommerce' ) );
|
||||
}
|
||||
|
||||
if ( ! current_user_can( get_post_type_object( $this->order_type )->cap->edit_post, $this->order->get_id() ) && ! current_user_can( 'manage_woocommerce' ) ) {
|
||||
wp_die( esc_html__( 'You do not have permission to edit this order', 'woocommerce' ) );
|
||||
}
|
||||
|
||||
if ( 'trash' === $this->order->get_status() ) {
|
||||
wp_die( esc_html__( 'You cannot edit this item because it is in the Trash. Please restore it and try again.', 'woocommerce' ) );
|
||||
}
|
||||
|
@ -69,9 +82,10 @@ class PageController {
|
|||
* @return void
|
||||
*/
|
||||
private function verify_create_permission() {
|
||||
if ( ! current_user_can( 'publish_shop_orders' ) && ! current_user_can( 'manage_woocommerce' ) ) {
|
||||
if ( ! current_user_can( get_post_type_object( $this->order_type )->cap->publish_posts ) && ! current_user_can( 'manage_woocommerce' ) ) {
|
||||
wp_die( esc_html__( 'You don\'t have permission to create a new order', 'woocommerce' ) );
|
||||
}
|
||||
|
||||
if ( isset( $this->order ) ) {
|
||||
$this->verify_edit_permission();
|
||||
}
|
||||
|
@ -92,9 +106,12 @@ class PageController {
|
|||
add_action( 'admin_menu', 'register_menu', 9 );
|
||||
}
|
||||
|
||||
$this->set_order_type();
|
||||
$this->set_action();
|
||||
|
||||
self::add_action( 'load-woocommerce_page_wc-orders', array( $this, 'handle_load_page_action' ) );
|
||||
$page_suffix = ( 'shop_order' === $this->order_type ? '' : '--' . $this->order_type );
|
||||
|
||||
self::add_action( 'load-woocommerce_page_wc-orders' . $page_suffix, array( $this, 'handle_load_page_action' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -106,6 +123,29 @@ class PageController {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the order type for the current screen.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function set_order_type() {
|
||||
global $plugin_page, $pagenow;
|
||||
|
||||
if ( 'admin.php' !== $pagenow || 0 !== strpos( $plugin_page, 'wc-orders' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->order_type = str_replace( array( 'wc-orders--', 'wc-orders' ), '', $plugin_page );
|
||||
$this->order_type = empty( $this->order_type ) ? 'shop_order' : $this->order_type;
|
||||
|
||||
$wc_order_type = wc_get_order_type( $this->order_type );
|
||||
$wp_order_type = get_post_type_object( $this->order_type );
|
||||
|
||||
if ( ! $wc_order_type || ! $wp_order_type || ! $wp_order_type->show_ui || ! current_user_can( $wp_order_type->cap->edit_posts ) ) {
|
||||
wp_die();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current action based on querystring arguments. Defaults to 'list_orders'.
|
||||
*
|
||||
|
@ -131,21 +171,29 @@ class PageController {
|
|||
* @return void
|
||||
*/
|
||||
public function register_menu(): void {
|
||||
add_submenu_page(
|
||||
'woocommerce',
|
||||
__( 'Orders', 'woocommerce' ),
|
||||
__( 'Orders', 'woocommerce' ),
|
||||
'edit_others_shop_orders',
|
||||
'wc-orders',
|
||||
array( $this, 'output' )
|
||||
);
|
||||
$order_types = wc_get_order_types( 'admin-menu' );
|
||||
|
||||
foreach ( $order_types as $order_type ) {
|
||||
$post_type = get_post_type_object( $order_type );
|
||||
|
||||
add_submenu_page(
|
||||
'woocommerce',
|
||||
$post_type->labels->name,
|
||||
$post_type->labels->menu_name,
|
||||
$post_type->cap->edit_posts,
|
||||
'wc-orders' . ( 'shop_order' === $order_type ? '' : '--' . $order_type ),
|
||||
array( $this, 'output' )
|
||||
);
|
||||
}
|
||||
|
||||
// In some cases (such as if the authoritative order store was changed earlier in the current request) we
|
||||
// need an extra step to remove the menu entry for the menu post type.
|
||||
add_action(
|
||||
'admin_init',
|
||||
function() {
|
||||
remove_submenu_page( 'woocommerce', 'edit.php?post_type=shop_order' );
|
||||
function() use ( $order_types ) {
|
||||
foreach ( $order_types as $order_type ) {
|
||||
remove_submenu_page( 'woocommerce', 'edit.php?post_type=' . $order_type );
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -180,7 +228,12 @@ class PageController {
|
|||
*/
|
||||
private function setup_action_list_orders(): void {
|
||||
$this->orders_table = wc_get_container()->get( ListTable::class );
|
||||
$this->orders_table->setup();
|
||||
$this->orders_table->setup(
|
||||
array(
|
||||
'order_type' => $this->order_type,
|
||||
)
|
||||
);
|
||||
|
||||
if ( $this->orders_table->current_action() ) {
|
||||
$this->orders_table->handle_bulk_actions();
|
||||
}
|
||||
|
@ -222,14 +275,31 @@ class PageController {
|
|||
*/
|
||||
private function setup_action_new_order(): void {
|
||||
global $theorder;
|
||||
|
||||
$this->verify_create_permission();
|
||||
$this->order = new \WC_Order();
|
||||
|
||||
$order_class_name = wc_get_order_type( $this->order_type )['class_name'];
|
||||
if ( ! $order_class_name || ! class_exists( $order_class_name ) ) {
|
||||
wp_die();
|
||||
}
|
||||
|
||||
$this->order = new $order_class_name();
|
||||
$this->order->set_object_read( false );
|
||||
$this->order->set_status( 'auto-draft' );
|
||||
$this->order->save();
|
||||
|
||||
$theorder = $this->order;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current order type.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_order_type() {
|
||||
return $this->order_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to generate a link to the main orders screen.
|
||||
*
|
||||
|
@ -249,20 +319,51 @@ class PageController {
|
|||
* @return string Edit link.
|
||||
*/
|
||||
public function get_edit_url( int $order_id ) : string {
|
||||
return wc_get_container()->get( CustomOrdersTableController::class )->custom_orders_table_usage_is_enabled() ?
|
||||
admin_url( 'admin.php?page=wc-orders&id=' . absint( $order_id ) ) . '&action=edit' :
|
||||
admin_url( 'post.php?post=' . absint( $order_id ) ) . '&action=edit';
|
||||
if ( ! wc_get_container()->get( CustomOrdersTableController::class )->custom_orders_table_usage_is_enabled() ) {
|
||||
return admin_url( 'post.php?post=' . absint( $order_id ) ) . '&action=edit';
|
||||
}
|
||||
|
||||
return add_query_arg(
|
||||
array(
|
||||
'action' => 'edit',
|
||||
'id' => absint( $order_id ),
|
||||
),
|
||||
$this->get_base_page_url( wc_get_order( $order_id )->get_type() )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to generate a link for creating order.
|
||||
*
|
||||
* @param string $order_type The order type. Defaults to 'shop_order'.
|
||||
* @return string
|
||||
*/
|
||||
public function get_new_page_url() : string {
|
||||
return wc_get_container()->get( CustomOrdersTableController::class )->custom_orders_table_usage_is_enabled() ?
|
||||
admin_url( 'admin.php?page=wc-orders&action=new' ) :
|
||||
admin_url( 'post-new.php?post_type=shop_order' );
|
||||
public function get_new_page_url( $order_type = 'shop_order' ) : string {
|
||||
$url = wc_get_container()->get( CustomOrdersTableController::class )->custom_orders_table_usage_is_enabled() ?
|
||||
add_query_arg( 'action', 'new', $this->get_base_page_url( $order_type ) ) :
|
||||
admin_url( 'post-new.php?post_type=' . $order_type );
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to generate a link to the main screen for a custom order type.
|
||||
*
|
||||
* @param string $order_type The order type.
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @throws \Exception When an invalid order type is passed.
|
||||
*/
|
||||
public function get_base_page_url( $order_type ): string {
|
||||
$order_types_with_ui = wc_get_order_types( 'admin-menu' );
|
||||
|
||||
if ( ! in_array( $order_type, $order_types_with_ui, true ) ) {
|
||||
// translators: %s is a custom order type.
|
||||
throw new \Exception( sprintf( __( 'Invalid order type: %s.', 'woocommerce' ), esc_html( $order_type ) ) );
|
||||
}
|
||||
|
||||
return admin_url( 'admin.php?page=wc-orders' . ( 'shop_order' === $order_type ? '' : '--' . $order_type ) );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -56,7 +56,9 @@ class PostsRedirectionController {
|
|||
* @return void
|
||||
*/
|
||||
private function maybe_redirect_to_orders_page(): void {
|
||||
if ( ! isset( $_GET['post_type'] ) || 'shop_order' !== $_GET['post_type'] ) {
|
||||
$post_type = $_GET['post_type'] ?? ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
|
||||
|
||||
if ( ! $post_type || ! in_array( $post_type, wc_get_order_types( 'admin-menu' ), true ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -72,7 +74,7 @@ class PostsRedirectionController {
|
|||
unset( $query_args['post_status'] );
|
||||
}
|
||||
|
||||
$new_url = $this->page_controller->get_orders_url();
|
||||
$new_url = $this->page_controller->get_base_page_url( $post_type );
|
||||
$new_url = add_query_arg( $query_args, $new_url );
|
||||
|
||||
// Handle bulk actions.
|
||||
|
@ -100,7 +102,9 @@ class PostsRedirectionController {
|
|||
* @return void
|
||||
*/
|
||||
private function maybe_redirect_to_new_order_page(): void {
|
||||
if ( ! isset( $_GET['post_type'] ) || 'shop_order' !== $_GET['post_type'] ) {
|
||||
$post_type = $_GET['post_type'] ?? ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
|
||||
|
||||
if ( ! $post_type || ! in_array( $post_type, wc_get_order_types( 'admin-menu' ), true ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -108,7 +112,7 @@ class PostsRedirectionController {
|
|||
$query_args = wp_unslash( $_GET );
|
||||
unset( $query_args['post_type'] );
|
||||
|
||||
$new_url = $this->page_controller->get_new_page_url();
|
||||
$new_url = $this->page_controller->get_new_page_url( $post_type );
|
||||
$new_url = add_query_arg( $query_args, $new_url );
|
||||
|
||||
wp_safe_redirect( $new_url, 301 );
|
||||
|
@ -123,7 +127,10 @@ class PostsRedirectionController {
|
|||
private function maybe_redirect_to_edit_order_page(): void {
|
||||
$post_id = absint( $_GET['post'] ?? 0 );
|
||||
|
||||
if ( ! $post_id || ! in_array( get_post_type( $post_id ), array( 'shop_order_placehold', 'shop_order' ), true ) || ! isset( $_GET['action'] ) ) {
|
||||
$redirect_from_types = wc_get_order_types( 'admin-menu' );
|
||||
$redirect_from_types[] = 'shop_order_placehold';
|
||||
|
||||
if ( ! $post_id || ! in_array( get_post_type( $post_id ), $redirect_from_types, true ) || ! isset( $_GET['action'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue