diff --git a/includes/data-stores/class-wc-product-data-store-cpt.php b/includes/data-stores/class-wc-product-data-store-cpt.php index 1b51964abe8..23d82e8c0c8 100644 --- a/includes/data-stores/class-wc-product-data-store-cpt.php +++ b/includes/data-stores/class-wc-product-data-store-cpt.php @@ -848,6 +848,7 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da $exclude_term_ids = array(); $outofstock_join = ''; $outofstock_where = ''; + $non_published_where = ''; $product_visibility_term_ids = wc_get_product_visibility_term_ids(); if ( 'yes' === get_option( 'woocommerce_hide_out_of_stock_items' ) && $product_visibility_term_ids['outofstock'] ) { @@ -859,6 +860,17 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da $outofstock_where = ' AND exclude_join.object_id IS NULL'; } + // Fetch a list of non-published parent products and exlude them, quicker than joining in the main query below. + $non_published_products = $wpdb->get_col( + "SELECT post.ID as id FROM `$wpdb->posts` AS post + WHERE post.post_type = 'product' + AND post.post_parent = 0 + AND post.post_status != 'publish'" + ); + if ( 0 < count( $non_published_products ) ) { + $non_published_where = ' AND post.post_parent NOT IN ( ' . implode( ',', $non_published_products ) . ')'; + } + return $wpdb->get_results( // phpcs:disable WordPress.WP.PreparedSQL.NotPrepared $wpdb->prepare( @@ -874,6 +886,7 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da AND CAST( meta.meta_value AS CHAR ) != '' AND CAST( meta.meta_value AS DECIMAL( 10, %d ) ) = CAST( meta2.meta_value AS DECIMAL( 10, %d ) ) $outofstock_where + $non_published_where GROUP BY post.ID", $decimals, $decimals diff --git a/tests/unit-tests/product/data-store.php b/tests/unit-tests/product/data-store.php index e1e55d0466b..656f9c874f1 100644 --- a/tests/unit-tests/product/data-store.php +++ b/tests/unit-tests/product/data-store.php @@ -495,12 +495,22 @@ class WC_Tests_Product_Data_Store extends WC_Unit_Test_Case { $future_sale_product->set_price( $future_sale_product->get_regular_price() ); $future_sale_product->save(); + $variable_draft_product = WC_Helper_Product::create_variation_product(); + $variable_draft_product->set_status( 'draft' ); + $variable_draft_product->save(); + $children = $variable_draft_product->get_children(); + $variable_draft_product_child = wc_get_product( $children[0] ); + $variable_draft_product_child->set_sale_price( 8 ); + $variable_draft_product_child->save(); + $sale_products = $product_store->get_on_sale_products(); $sale_product_ids = wp_list_pluck( $sale_products, 'id' ); $this->assertContains( $sale_product->get_id(), $sale_product_ids ); $this->assertNotContains( $not_sale_product->get_id(), $sale_product_ids ); $this->assertNotContains( $future_sale_product->get_id(), $sale_product_ids ); + $this->assertNotContains( $variable_draft_product->get_id(), $sale_product_ids ); + $this->assertNotContains( $variable_draft_product_child->get_id(), $sale_product_ids ); } public function test_generate_product_title() {