[HPOS] Improve handling of "visible" statuses in orders list (#35370)
This commit is contained in:
parent
e4f6c468cb
commit
4f692a51d2
|
@ -0,0 +1,4 @@
|
|||
Significance: patch
|
||||
Type: fix
|
||||
|
||||
Fix handling of statuses in orders list table (HPOS).
|
|
@ -338,25 +338,31 @@ function wc_processing_order_count() {
|
|||
* Return the orders count of a specific order status.
|
||||
*
|
||||
* @param string $status Status.
|
||||
* @param string $type (Optional) Order type. Leave empty to include all 'for order-count' order types. @{see wc_get_order_types()}.
|
||||
* @return int
|
||||
*/
|
||||
function wc_orders_count( $status ) {
|
||||
$count = 0;
|
||||
$status = 'wc-' . $status;
|
||||
$order_statuses = array_keys( wc_get_order_statuses() );
|
||||
function wc_orders_count( $status, string $type = '' ) {
|
||||
$count = 0;
|
||||
$legacy_statuses = array( 'draft', 'trash' );
|
||||
$valid_statuses = array_merge( array_keys( wc_get_order_statuses() ), $legacy_statuses );
|
||||
$status = ( ! in_array( $status, $legacy_statuses, true ) && 0 !== strpos( $status, 'wc-' ) ) ? 'wc-' . $status : $status;
|
||||
$valid_types = wc_get_order_types( 'order-count' );
|
||||
$type = trim( $type );
|
||||
|
||||
if ( ! in_array( $status, $order_statuses, true ) ) {
|
||||
if ( ! in_array( $status, $valid_statuses, true ) || ( $type && ! in_array( $type, $valid_types, true ) ) ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$cache_key = WC_Cache_Helper::get_cache_prefix( 'orders' ) . $status;
|
||||
$cache_key = WC_Cache_Helper::get_cache_prefix( 'orders' ) . $status . $type;
|
||||
$cached_count = wp_cache_get( $cache_key, 'counts' );
|
||||
|
||||
if ( false !== $cached_count ) {
|
||||
return $cached_count;
|
||||
}
|
||||
|
||||
foreach ( wc_get_order_types( 'order-count' ) as $type ) {
|
||||
$types_for_count = $type ? array( $type ) : $valid_types;
|
||||
|
||||
foreach ( $types_for_count as $type ) {
|
||||
$data_store = WC_Data_Store::load( 'shop_order' === $type ? 'order' : $type );
|
||||
if ( $data_store ) {
|
||||
$count += $data_store->get_order_count( $status );
|
||||
|
|
|
@ -161,18 +161,19 @@ class ListTable extends WP_List_Table {
|
|||
<hr class='wp-header-end'>"
|
||||
);
|
||||
|
||||
if ( $this->has_items() || $this->has_filter ) {
|
||||
$this->views();
|
||||
|
||||
echo '<form id="wc-orders-filter" method="get" action="' . esc_url( get_admin_url( null, 'admin.php' ) ) . '">';
|
||||
$this->print_hidden_form_fields();
|
||||
$this->search_box( esc_html__( 'Search orders', 'woocommerce' ), 'orders-search-input' );
|
||||
|
||||
parent::display();
|
||||
echo '</form> </div>';
|
||||
} else {
|
||||
if ( $this->should_render_blank_state() ) {
|
||||
$this->render_blank_state();
|
||||
return;
|
||||
}
|
||||
|
||||
$this->views();
|
||||
|
||||
echo '<form id="wc-orders-filter" method="get" action="' . esc_url( get_admin_url( null, 'admin.php' ) ) . '">';
|
||||
$this->print_hidden_form_fields();
|
||||
$this->search_box( esc_html__( 'Search orders', 'woocommerce' ), 'orders-search-input' );
|
||||
|
||||
parent::display();
|
||||
echo '</form> </div>';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -387,25 +388,22 @@ class ListTable extends WP_List_Table {
|
|||
public function get_views() {
|
||||
$view_counts = array();
|
||||
$view_links = array();
|
||||
$statuses = wc_get_order_statuses();
|
||||
$statuses = $this->get_visible_statuses();
|
||||
$current = isset( $_GET['status'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['status'] ?? '' ) ) : 'all';
|
||||
$all_count = 0;
|
||||
|
||||
// Add 'draft' and 'trash' to list.
|
||||
foreach ( array( 'draft', 'trash' ) as $wp_status ) {
|
||||
$statuses[ $wp_status ] = ( get_post_status_object( $wp_status ) )->label;
|
||||
}
|
||||
|
||||
$statuses_in_list = array_intersect( array_keys( $statuses ), get_post_stati( array( 'show_in_admin_status_list' => true ) ) );
|
||||
|
||||
foreach ( $statuses_in_list as $slug ) {
|
||||
foreach ( array_keys( $statuses ) as $slug ) {
|
||||
$total_in_status = $this->count_orders_by_status( $slug );
|
||||
|
||||
if ( $total_in_status > 0 ) {
|
||||
$view_counts[ $slug ] = $total_in_status;
|
||||
}
|
||||
|
||||
if ( ( get_post_status_object( $slug ) )->show_in_admin_all_list ) {
|
||||
$all_count += $total_in_status;
|
||||
}
|
||||
}
|
||||
|
||||
$all_count = array_sum( $view_counts );
|
||||
$view_links['all'] = $this->get_view_link( 'all', __( 'All', 'woocommerce' ), $all_count, '' === $current || 'all' === $current );
|
||||
|
||||
foreach ( $view_counts as $slug => $count ) {
|
||||
|
@ -418,20 +416,47 @@ class ListTable extends WP_List_Table {
|
|||
/**
|
||||
* Count orders by status.
|
||||
*
|
||||
* @param string $status The order status we are interested in.
|
||||
* @param string|string[] $status The order status we are interested in.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function count_orders_by_status( string $status ): int {
|
||||
$orders = wc_get_orders(
|
||||
array(
|
||||
'limit' => -1,
|
||||
'return' => 'ids',
|
||||
'status' => $status,
|
||||
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
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return count( $orders );
|
||||
/**
|
||||
* Checks whether the blank state should be rendered or not. This depends on whether there are others with a visible
|
||||
* status.
|
||||
*
|
||||
* @return boolean TRUE when the blank state should be rendered, FALSE otherwise.
|
||||
*/
|
||||
private function should_render_blank_state(): bool {
|
||||
return ( ! $this->has_filter ) && 0 === $this->count_orders_by_status( array_keys( $this->get_visible_statuses() ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of slug and labels for order statuses that should be visible in the status list.
|
||||
*
|
||||
* @return array slug => label array of order statuses.
|
||||
*/
|
||||
private function get_visible_statuses(): array {
|
||||
return array_intersect_key(
|
||||
array_merge(
|
||||
wc_get_order_statuses(),
|
||||
array(
|
||||
'trash' => ( get_post_status_object( 'trash' ) )->label,
|
||||
'draft' => ( get_post_status_object( 'draft' ) )->label,
|
||||
)
|
||||
),
|
||||
array_flip( get_post_stati( array( 'show_in_admin_status_list' => true ) ) )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -80,6 +80,61 @@ class WC_Tests_Order_Functions extends WC_Unit_Test_Case {
|
|||
|
||||
// Invalid status returns 0.
|
||||
$this->assertEquals( 0, wc_orders_count( 'unkown-status' ) );
|
||||
|
||||
// Invalid order type should return 0.
|
||||
$this->assertEquals( 0, wc_orders_count( 'wc-pending', 'invalid-order-type' ) );
|
||||
|
||||
wp_cache_flush();
|
||||
|
||||
// Fake some datastores and order types for testing.
|
||||
$test_counts = array(
|
||||
'order' => array(
|
||||
array( 'wc-on-hold', 2 ),
|
||||
array( 'trash', 1 ),
|
||||
),
|
||||
'order-fake-type' => array(
|
||||
array( 'wc-on-hold', 3 ),
|
||||
array( 'trash', 0 ),
|
||||
),
|
||||
);
|
||||
|
||||
$mock_datastores = array();
|
||||
foreach ( array( 'order', 'order-fake-type' ) as $order_type ) {
|
||||
$mock_datastores[ $order_type ] = $this->getMockBuilder( 'Abstract_WC_Order_Data_Store_CPT' )
|
||||
->setMethods( array( 'get_order_count' ) )
|
||||
->getMock();
|
||||
|
||||
$mock_datastores[ $order_type ]
|
||||
->method( 'get_order_count' )
|
||||
->will( $this->returnValueMap( $test_counts[ $order_type ] ) );
|
||||
}
|
||||
|
||||
$add_mock_datastores = function( $stores ) use ( $mock_datastores ) {
|
||||
return array_merge( $stores, $mock_datastores );
|
||||
};
|
||||
$add_mock_order_type = function( $order_types ) use ( $mock_datastores ) {
|
||||
return array( 'shop_order', 'order-fake-type' );
|
||||
};
|
||||
|
||||
add_filter( 'woocommerce_data_stores', $add_mock_datastores );
|
||||
add_filter( 'wc_order_types', $add_mock_order_type );
|
||||
|
||||
// Check counts for specific order types.
|
||||
$this->assertEquals( 2, wc_orders_count( 'on-hold', 'shop_order' ) );
|
||||
$this->assertEquals( 1, wc_orders_count( 'trash', 'shop_order' ) );
|
||||
$this->assertEquals( 3, wc_orders_count( 'on-hold', 'order-fake-type' ) );
|
||||
$this->assertEquals( 0, wc_orders_count( 'trash', 'order-fake-type' ) );
|
||||
|
||||
// Check that counts with no order type include all order types.
|
||||
$this->assertEquals( 5, wc_orders_count( 'on-hold' ) );
|
||||
$this->assertEquals( 1, wc_orders_count( 'trash' ) );
|
||||
|
||||
remove_filter( 'woocommerce_data_stores', $add_mock_datastores );
|
||||
remove_filter( 'wc_order_types', $add_mock_order_type );
|
||||
|
||||
// Confirm that everything's back to normal.
|
||||
wp_cache_flush();
|
||||
$this->assertEquals( 0, wc_orders_count( 'on-hold' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue