diff --git a/plugins/woocommerce-blocks/assets/php/class-wgpb-block-grid-base.php b/plugins/woocommerce-blocks/assets/php/class-wgpb-block-grid-base.php index e4aa6491c15..83080cdc4d0 100644 --- a/plugins/woocommerce-blocks/assets/php/class-wgpb-block-grid-base.php +++ b/plugins/woocommerce-blocks/assets/php/class-wgpb-block-grid-base.php @@ -36,13 +36,6 @@ abstract class WGPB_Block_Grid_Base { */ protected $content = ''; - /** - * Query args. - * - * @var array - */ - protected $query_args = array(); - /** * Initialize block. * @@ -52,7 +45,6 @@ abstract class WGPB_Block_Grid_Base { public function __construct( $attributes = array(), $content = '' ) { $this->attributes = $this->parse_attributes( $attributes ); $this->content = $content; - $this->query_args = $this->parse_query_args(); } /** @@ -76,63 +68,15 @@ abstract class WGPB_Block_Grid_Base { ), ); - return wp_parse_args( $attributes, $defaults ); - } + $attributes = wp_parse_args( $attributes, $defaults ); - /** - * Parse query args. - * - * @return array - */ - protected function parse_query_args() { - $query_args = array( - 'post_type' => 'product', - 'post_status' => 'publish', - 'ignore_sticky_posts' => true, - 'no_found_rows' => false, - 'orderby' => '', - 'order' => '', - ); - - if ( isset( $this->attributes['orderby'] ) ) { - if ( 'price_desc' === $this->attributes['orderby'] ) { - $query_args['orderby'] = 'price'; - $query_args['order'] = 'DESC'; - } elseif ( 'price_asc' === $this->attributes['orderby'] ) { - $query_args['orderby'] = 'price'; - $query_args['order'] = 'ASC'; - } elseif ( 'date' === $this->attributes['orderby'] ) { - $query_args['orderby'] = 'date'; - $query_args['order'] = 'DESC'; - } else { - $query_args['orderby'] = $this->attributes['orderby']; - } + if ( ! empty( $attributes['rows'] ) && ! empty( $attributes['columns'] ) ) { + $attributes['limit'] = intval( $attributes['columns'] ) * intval( $attributes['rows'] ); + } else { + $attributes['limit'] = -1; } - if ( ! empty( $this->attributes['rows'] ) ) { - $this->attributes['limit'] = intval( $this->attributes['columns'] ) * intval( $this->attributes['rows'] ); - } - - $query_args['posts_per_page'] = intval( $this->attributes['limit'] ); - $query_args['meta_query'] = WC()->query->get_meta_query(); // phpcs:ignore WordPress.DB.SlowDBQuery - $query_args['tax_query'] = array(); // phpcs:ignore WordPress.DB.SlowDBQuery - - $this->set_block_query_args( $query_args ); - - $ordering_args = WC()->query->get_catalog_ordering_args( $query_args['orderby'], $query_args['order'] ); - $query_args['orderby'] = $ordering_args['orderby']; - $query_args['order'] = $ordering_args['order']; - if ( $ordering_args['meta_key'] ) { - $query_args['meta_key'] = $ordering_args['meta_key']; // phpcs:ignore WordPress.DB.SlowDBQuery - } - - // Categories. - $this->set_categories_query_args( $query_args ); - - // Always query only IDs. - $query_args['fields'] = 'ids'; - - return $query_args; + return $attributes; } /** @@ -142,6 +86,31 @@ abstract class WGPB_Block_Grid_Base { */ abstract protected function set_block_query_args( &$query_args ); + /** + * Set orderby/order query args. + * + * @param array $query_args Query args. + */ + protected function set_ordering_query_args( &$query_args ) { + $orderby = ''; + $order = ''; + + if ( isset( $this->attributes['orderby'] ) ) { + if ( 'price_desc' === $this->attributes['orderby'] ) { + $orderby = 'price'; + $order = 'DESC'; + } elseif ( 'price_asc' === $this->attributes['orderby'] ) { + $orderby = 'price'; + $order = 'ASC'; + } else { + $orderby = $this->attributes['orderby']; + } + } + + // This handles orderby queries and hooks in custom orderby functions. + $query_args = array_merge( $query_args, WC()->query->get_catalog_ordering_args( $orderby, $order ) ); + } + /** * Set categories query args. * @@ -149,8 +118,7 @@ abstract class WGPB_Block_Grid_Base { */ protected function set_categories_query_args( &$query_args ) { if ( ! empty( $this->attributes['categories'] ) ) { - $categories = array_map( 'absint', $this->attributes['categories'] ); - + $categories = array_map( 'absint', $this->attributes['categories'] ); $query_args['tax_query'][] = array( 'taxonomy' => 'product_cat', 'terms' => $categories, @@ -166,30 +134,60 @@ abstract class WGPB_Block_Grid_Base { } } + /** + * Get all product query args for WP_Query. + * + * @return array + */ + protected function get_products_query_args() { + $query_args = array( + 'post_type' => 'product', + 'post_status' => 'publish', + 'fields' => 'ids', + 'ignore_sticky_posts' => true, + 'no_found_rows' => false, + 'posts_per_page' => intval( $this->attributes['limit'] ), + 'tax_query' => array(), // phpcs:ignore WordPress.DB.SlowDBQuery + 'meta_query' => array(), // phpcs:ignore WordPress.DB.SlowDBQuery + ); + $this->set_ordering_query_args( $query_args ); + $this->set_categories_query_args( $query_args ); + $this->set_block_query_args( $query_args ); + + return $query_args; + } + /** * Run the query and return an array of product IDs * * @return array List of product IDs */ protected function get_products() { - if ( 'product-top-rated' === $this->block_name ) { - add_filter( 'posts_clauses', array( WC()->query, 'order_by_rating_post_clauses' ) ); - $query = new WP_Query( $this->query_args ); - remove_filter( 'posts_clauses', array( WC()->query, 'order_by_rating_post_clauses' ) ); - } else { - $query = new WP_Query( $this->query_args ); - } + $query_hash = md5( wp_json_encode( $this->attributes ) . __CLASS__ ); + $transient_name = 'wc_block_' . $query_hash; + $transient_value = get_transient( $transient_name ); + $transient_version = WC_Cache_Helper::get_transient_version( 'product_query' ); - $results = wp_parse_id_list( $query->posts ); + if ( isset( $transient_value['value'], $transient_value['version'] ) && $transient_value['version'] === $transient_version ) { + $results = $transient_value['value']; + } else { + $query = new WP_Query( $this->get_products_query_args() ); + $results = wp_parse_id_list( $query->posts ); + $transient_value = array( + 'version' => $transient_version, + 'value' => $results, + ); + set_transient( $transient_name, $transient_value, DAY_IN_SECONDS * 30 ); + + // Remove ordering query arguments which may have been added by get_catalog_ordering_args. + WC()->query->remove_ordering_args(); + } // Prime caches to reduce future queries. if ( is_callable( '_prime_post_caches' ) ) { _prime_post_caches( $results ); } - // Remove ordering query arguments which may have been added by get_catalog_ordering_args. - WC()->query->remove_ordering_args(); - return $results; } diff --git a/plugins/woocommerce-blocks/assets/php/class-wgpb-block-product-best-sellers.php b/plugins/woocommerce-blocks/assets/php/class-wgpb-block-product-best-sellers.php index a7ecdc64a04..d0b194f72c9 100644 --- a/plugins/woocommerce-blocks/assets/php/class-wgpb-block-product-best-sellers.php +++ b/plugins/woocommerce-blocks/assets/php/class-wgpb-block-product-best-sellers.php @@ -22,14 +22,25 @@ class WGPB_Block_Product_Best_Sellers extends WGPB_Block_Grid_Base { */ protected $block_name = 'product-best-sellers'; + /** + * Get the block's attributes. + * + * @param array $attributes Block attributes. Default empty array. + * @return array Block attributes merged with defaults. + */ + protected function parse_attributes( $attributes ) { + $attributes = parent::parse_attributes( $attributes ); + + // Force orderby to popularity. + $attributes['orderby'] = 'popularity'; + + return $attributes; + } + /** * Set args specific to this block * * @param array $query_args Query args. */ - protected function set_block_query_args( &$query_args ) { - $query_args['meta_key'] = 'total_sales'; // phpcs:ignore WordPress.DB.SlowDBQuery - $query_args['order'] = 'DESC'; - $query_args['orderby'] = 'meta_value_num'; - } + protected function set_block_query_args( &$query_args ) {} } diff --git a/plugins/woocommerce-blocks/assets/php/class-wgpb-block-product-new.php b/plugins/woocommerce-blocks/assets/php/class-wgpb-block-product-new.php index 8ec0ce18e7e..a1124092ce2 100644 --- a/plugins/woocommerce-blocks/assets/php/class-wgpb-block-product-new.php +++ b/plugins/woocommerce-blocks/assets/php/class-wgpb-block-product-new.php @@ -22,13 +22,25 @@ class WGPB_Block_Product_New extends WGPB_Block_Grid_Base { */ protected $block_name = 'product-new'; + /** + * Get the block's attributes. + * + * @param array $attributes Block attributes. Default empty array. + * @return array Block attributes merged with defaults. + */ + protected function parse_attributes( $attributes ) { + $attributes = parent::parse_attributes( $attributes ); + + // Force orderby to date. + $attributes['orderby'] = 'date'; + + return $attributes; + } + /** * Set args specific to this block * * @param array $query_args Query args. */ - protected function set_block_query_args( &$query_args ) { - $query_args['orderby'] = 'date'; - $query_args['order'] = 'DESC'; - } + protected function set_block_query_args( &$query_args ) {} } diff --git a/plugins/woocommerce-blocks/assets/php/class-wgpb-block-product-top-rated.php b/plugins/woocommerce-blocks/assets/php/class-wgpb-block-product-top-rated.php index 82040a8a3b4..ea3bfbc33c7 100644 --- a/plugins/woocommerce-blocks/assets/php/class-wgpb-block-product-top-rated.php +++ b/plugins/woocommerce-blocks/assets/php/class-wgpb-block-product-top-rated.php @@ -23,7 +23,22 @@ class WGPB_Block_Product_Top_Rated extends WGPB_Block_Grid_Base { protected $block_name = 'product-top-rated'; /** - * This function is not necessary in this block. + * Get the block's attributes. + * + * @param array $attributes Block attributes. Default empty array. + * @return array Block attributes merged with defaults. + */ + protected function parse_attributes( $attributes ) { + $attributes = parent::parse_attributes( $attributes ); + + // Force orderby to rating. + $attributes['orderby'] = 'rating'; + + return $attributes; + } + + /** + * Set args specific to this block * * @param array $query_args Query args. */