From 01983e6b9664e0060694416d0c00086a5522bf83 Mon Sep 17 00:00:00 2001 From: Claudio Sanches Date: Thu, 16 Nov 2017 15:14:36 -0200 Subject: [PATCH] Query and save only IDs of products when fetching products by shortcode --- .../class-wc-shortcode-products.php | 42 ++++++++++++------- tests/unit-tests/shortcodes/products.php | 14 +++++++ 2 files changed, 40 insertions(+), 16 deletions(-) diff --git a/includes/shortcodes/class-wc-shortcode-products.php b/includes/shortcodes/class-wc-shortcode-products.php index 5fb33ffb4fe..00e9482188d 100644 --- a/includes/shortcodes/class-wc-shortcode-products.php +++ b/includes/shortcodes/class-wc-shortcode-products.php @@ -5,7 +5,7 @@ * @author Automattic * @category Shortcodes * @package WooCommerce/Shortcodes - * @version 3.2.0 + * @version 3.2.4 */ if ( ! defined( 'ABSPATH' ) ) { @@ -195,7 +195,12 @@ class WC_Shortcode_Products { // Categories. $this->set_categories_query_args( $query_args ); - return apply_filters( 'woocommerce_shortcode_products_query', $query_args, $this->attributes, $this->type ); + $query_args = apply_filters( 'woocommerce_shortcode_products_query', $query_args, $this->attributes, $this->type ); + + // Always query only IDs. + $query_args['fields'] = 'ids'; + + return $query_args; } /** @@ -450,16 +455,16 @@ class WC_Shortcode_Products { } /** - * Get products. + * Get products IDs. * - * @since 3.2.0 - * @return WP_Query + * @since 3.2.4 + * @return array */ - protected function get_products() { + protected function get_products_ids() { $transient_name = $this->get_transient_name(); - $products = get_transient( $transient_name ); + $ids = get_transient( $transient_name ); - if ( false === $products || ! is_a( $products, 'WP_Query' ) ) { + if ( false === $ids ) { if ( 'top_rated_products' === $this->type ) { add_filter( 'posts_clauses', array( __CLASS__, 'order_by_rating_post_clauses' ) ); $products = new WP_Query( $this->query_args ); @@ -468,7 +473,9 @@ class WC_Shortcode_Products { $products = new WP_Query( $this->query_args ); } - set_transient( $transient_name, $products, DAY_IN_SECONDS * 30 ); + $ids = wp_parse_id_list( $products->posts ); + + set_transient( $transient_name, $ids, DAY_IN_SECONDS * 30 ); } // Remove ordering query arguments. @@ -476,7 +483,7 @@ class WC_Shortcode_Products { WC()->query->remove_ordering_args(); } - return $products; + return $ids; } /** @@ -492,20 +499,23 @@ class WC_Shortcode_Products { $classes = $this->get_wrapper_classes( $columns ); $woocommerce_loop['columns'] = $columns; $woocommerce_loop['name'] = $this->type; - $products = $this->get_products(); + $products_ids = $this->get_products_ids(); ob_start(); - if ( $products->have_posts() ) { - // Prime caches before grabbing objects. - update_post_caches( $products->posts, array( 'product', 'product_variation' ) ); + if ( $products_ids ) { + // Prime meta cache to reduce future queries. + update_meta_cache( 'post', $products_ids ); + update_object_term_cache( $products_ids, 'product' ); do_action( "woocommerce_shortcode_before_{$this->type}_loop", $this->attributes ); woocommerce_product_loop_start(); - while ( $products->have_posts() ) { - $products->the_post(); + foreach ( $products_ids as $product_id ) { + $post_object = get_post( $product_id ); + $GLOBALS['post'] =& $post_object; // WPCS: override ok. + setup_postdata( $post_object ); // Set custom product visibility when quering hidden products. add_action( 'woocommerce_product_is_visible', array( $this, 'set_product_as_visible' ) ); diff --git a/tests/unit-tests/shortcodes/products.php b/tests/unit-tests/shortcodes/products.php index 025967b6941..787b4f3e107 100644 --- a/tests/unit-tests/shortcodes/products.php +++ b/tests/unit-tests/shortcodes/products.php @@ -70,6 +70,7 @@ class WC_Test_Shortcode_Products extends WC_Unit_Test_Case { 'posts_per_page' => -1, 'meta_query' => $meta_query, 'tax_query' => $tax_query, + 'fields' => 'ids', ); $this->assertEquals( $expected, $shortcode->get_query_args() ); @@ -88,6 +89,7 @@ class WC_Test_Shortcode_Products extends WC_Unit_Test_Case { 'posts_per_page' => -1, 'meta_query' => $meta_query, 'tax_query' => $tax_query, + 'fields' => 'ids', ); $this->assertEquals( $expected2, $shortcode2->get_query_args() ); @@ -106,6 +108,7 @@ class WC_Test_Shortcode_Products extends WC_Unit_Test_Case { 'meta_query' => $meta_query, 'tax_query' => $tax_query, 'post__in' => array( '1', '2', '3' ), + 'fields' => 'ids', ); $expected3['meta_query'][] = array( 'key' => '_sku', @@ -135,6 +138,7 @@ class WC_Test_Shortcode_Products extends WC_Unit_Test_Case { 'meta_query' => $meta_query, 'tax_query' => $tax_query, 'meta_key' => '', + 'fields' => 'ids', ); $expected4['tax_query'][] = array( 'taxonomy' => 'product_cat', @@ -164,6 +168,7 @@ class WC_Test_Shortcode_Products extends WC_Unit_Test_Case { 'posts_per_page' => 12, 'meta_query' => $meta_query, 'tax_query' => $tax_query, + 'fields' => 'ids', ); $this->assertEquals( $expected5, $shortcode5->get_query_args() ); @@ -184,6 +189,7 @@ class WC_Test_Shortcode_Products extends WC_Unit_Test_Case { 'meta_query' => $meta_query, 'tax_query' => $tax_query, 'p' => '1', + 'fields' => 'ids', ); $this->assertEquals( $expected6, $shortcode6->get_query_args() ); @@ -208,6 +214,7 @@ class WC_Test_Shortcode_Products extends WC_Unit_Test_Case { 'meta_query' => $meta_query, 'tax_query' => $tax_query, 'post__in' => array_merge( array( 0 ), wc_get_product_ids_on_sale() ), + 'fields' => 'ids', ); $this->assertEquals( $expected7, $shortcode7->get_query_args() ); @@ -230,6 +237,7 @@ class WC_Test_Shortcode_Products extends WC_Unit_Test_Case { 'meta_query' => $meta_query, 'tax_query' => $tax_query, 'meta_key' => 'total_sales', + 'fields' => 'ids', ); $this->assertEquals( $expected8, $shortcode8->get_query_args() ); @@ -253,6 +261,7 @@ class WC_Test_Shortcode_Products extends WC_Unit_Test_Case { 'posts_per_page' => 12, 'meta_query' => $meta_query, 'tax_query' => $tax_query, + 'fields' => 'ids', ); $this->assertEquals( $expected9, $shortcode9->get_query_args() ); @@ -285,6 +294,7 @@ class WC_Test_Shortcode_Products extends WC_Unit_Test_Case { 'include_children' => false, ), ) ), + 'fields' => 'ids', ); $this->assertEquals( $expected10, $shortcode10->get_query_args() ); @@ -315,6 +325,7 @@ class WC_Test_Shortcode_Products extends WC_Unit_Test_Case { 'operator' => 'IN', ), ) ), + 'fields' => 'ids', ); $this->assertEquals( $expected11, $shortcode11->get_query_args() ); @@ -341,6 +352,7 @@ class WC_Test_Shortcode_Products extends WC_Unit_Test_Case { 'include_children' => false, ), ), + 'fields' => 'ids', ); $this->assertEquals( $expected12, $shortcode12->get_query_args() ); @@ -373,6 +385,7 @@ class WC_Test_Shortcode_Products extends WC_Unit_Test_Case { 'include_children' => false, ), ), + 'fields' => 'ids', ); $this->assertEquals( $expected13, $shortcode13->get_query_args() ); @@ -405,6 +418,7 @@ class WC_Test_Shortcode_Products extends WC_Unit_Test_Case { 'include_children' => false, ), ), + 'fields' => 'ids', ); $this->assertEquals( $expected14, $shortcode14->get_query_args() );