From cfa55d17bbd4028d03b8f9a70316ae0e048e3702 Mon Sep 17 00:00:00 2001 From: Jeffrey Schutzman Date: Sat, 1 Nov 2014 10:28:16 -0400 Subject: [PATCH 1/3] Add checks to variation class to avoid walking off the end of internal arrays Add check to see if variations are defined and used, when they are not defined and used don't make calls through WordPress for variation terms unless working inside the admin area. Avoids lots of small empty queries. --- wpsc-core/wpsc-functions.php | 11 ++- wpsc-includes/variations.class.php | 113 ++++++++++++++++++++++++----- 2 files changed, 103 insertions(+), 21 deletions(-) diff --git a/wpsc-core/wpsc-functions.php b/wpsc-core/wpsc-functions.php index b51d7ad79e..97b4fab9d2 100644 --- a/wpsc-core/wpsc-functions.php +++ b/wpsc-core/wpsc-functions.php @@ -674,13 +674,20 @@ function wpsc_update_permalink_slugs() { * @return stdObject[] */ function wpsc_get_product_terms( $product_id, $tax, $field = '' ) { + $terms = get_the_terms( $product_id, $tax ); + // if, albeit for some bizarre reason, the call returns a WordPress error lets behave as if there weren't any terms + if ( is_wp_error( $terms ) ) { + $terms = false; + } - if ( ! $terms ) + if ( ! $terms ) { $terms = array(); + } - if ( $field ) + if ( $field ) { $terms = wp_list_pluck( $terms, $field ); + } // remove the redundant array keys, could cause issues in loops with iterator $terms = array_values( $terms ); diff --git a/wpsc-includes/variations.class.php b/wpsc-includes/variations.class.php index dd126bc14e..81819255da 100755 --- a/wpsc-includes/variations.class.php +++ b/wpsc-includes/variations.class.php @@ -22,12 +22,32 @@ class wpsc_variations { var $current_variation = -1; var $variation; + const VARIATIONS_BEING_USED_OPTION_NAME = 'wpsc_variations_are_being_used'; - function wpsc_variations( $product_id ) { + static function variations_are_being_used() { + + // variations are always enabled on the back-end (admin), for the user facing site we only enable variations + // if there are variation terms saved by the administrator + if ( is_admin() ) { + $variations_are_being_used = true; + } else { + $variations_are_being_used = intval( get_option( self::VARIATIONS_BEING_USED_OPTION_NAME, 1 ) ); + } + + error_log( __CLASS__ . '::' . __FUNCTION__ . ' ' . ( $variations_are_being_used ? 'true' : 'false' ) ); + return (bool) $variations_are_being_used; + } + + function __construct( $product_id ) { global $wpdb; - $product_terms = wpsc_get_product_terms( $product_id, 'wpsc-variation' ); - $product_terms = wpsc_get_terms_variation_sort_filter( $product_terms ); + + if ( self::variations_are_being_used() ) { + $product_terms = wpsc_get_product_terms( $product_id, 'wpsc-variation' ); + $product_terms = wpsc_get_terms_variation_sort_filter( $product_terms ); + } else { + $product_terms = array(); + } $this->variation_groups = array(); $this->first_variations = array(); @@ -87,22 +107,31 @@ function get_variation_groups() { function next_variation_group() { $this->current_variation_group++; - $this->variation_group = $this->variation_groups[$this->current_variation_group]; - return $this->variation_group; - } + // make sure we don't walk off the end of the variation group array + if ( $this->current_variation_group < count( $this->variation_groups ) ) { + $this->variation_group = $this->variation_groups[ $this->current_variation_group ]; + } else { + $this->variation_group = array(); + } + return $this->variation_group; + } + function the_variation_group() { $this->variation_group = $this->next_variation_group(); $this->get_variations(); } function have_variation_groups() { - if ( $this->current_variation_group + 1 < $this->variation_group_count ) { - return true; - } else if ( $this->current_variation_group + 1 == $this->variation_group_count && $this->variation_group_count > 0 ) { - $this->rewind_variation_groups(); + if ( self::variations_are_being_used() ) { + if ( $this->current_variation_group + 1 < $this->variation_group_count ) { + return true; + } else if ( $this->current_variation_group + 1 == $this->variation_group_count && $this->variation_group_count > 0 ) { + $this->rewind_variation_groups(); + } } + return false; } @@ -114,21 +143,33 @@ function rewind_variation_groups() { } function get_first_variations() { - global $wpdb; return null; } function get_variations() { - global $wpdb; - $this->variations = $this->all_associated_variations[$this->variation_group->term_id]; + // check to be sure the variations we are accessing exist in the variations array + if ( isset( $this->all_associated_variations[$this->variation_group->term_id] ) ) { + $this->variations = $this->all_associated_variations[ $this->variation_group->term_id ]; + } else { + $this->variations = array(); + } + $this->variation_count = count( $this->variations ); } function next_variation() { + $this->current_variation++; - $this->variation = $this->variations[$this->current_variation]; + + // check to make sure we don't access off the end of the variation array + if ( $this->current_variation < $this->variation_count ) { + $this->variation = $this->variations[ $this->current_variation ]; + } else { + $this->variation = false; + } + return $this->variation; } @@ -138,12 +179,16 @@ function the_variation() { } function have_variations() { - if ( $this->current_variation + 1 < $this->variation_count ) { - return true; - } else if ( $this->current_variation + 1 == $this->variation_count && $this->variation_count > 0 ) { - // Do some cleaning up after the loop, - $this->rewind_variations(); + + if ( self::variations_are_being_used() ) { + if ( $this->current_variation + 1 < $this->variation_count ) { + return true; + } else if ( $this->current_variation + 1 == $this->variation_count && $this->variation_count > 0 ) { + // Do some cleaning up after the loop, + $this->rewind_variations(); + } } + return false; } @@ -296,3 +341,33 @@ function wpsc_get_child_object_in_terms_var( $parent_id, $terms, $taxonomies, $a return false; } } + +/* + * Remember if variations are being used for products. If not the variation class can skip many requests + * to the database when servicing user requests. Although the transactions are fast when there aren't + * any variation, the number of requests is significant, and the results are not cached. + */ +if ( is_admin() ) { + function _wpsc_remember_if_taxonomy_terms_are_being_used() { + // we are going to look for variations that are assigned to products, if they exist we remember that + // variations are being used + $terms = get_terms( 'wpsc-variation' ); + + $new_variations_are_being_used = false; + if ( ! is_wp_error( $terms ) ) { + if ( ! empty( $terms ) ) { + $new_variations_are_being_used = true; + } + } + + $old_variations_being_used = (bool) intval( get_option( wpsc_variations::VARIATIONS_BEING_USED_OPTION_NAME, true ) ); + + if ( $old_variations_being_used != $new_variations_are_being_used ) { + delete_option( wpsc_variations::VARIATIONS_BEING_USED_OPTION_NAME ); + add_option( wpsc_variations::VARIATIONS_BEING_USED_OPTION_NAME, $new_variations_are_being_used, null, true ); + error_log( __FUNCTION__ . ' updating variations being used option ' . ( $new_variations_are_being_used ? 'true' : 'false' ) ); + } + } + + add_action( 'shutdown', '_wpsc_remember_if_taxonomy_terms_are_being_used' ); +} \ No newline at end of file From 0fb250604c25638cd7393100605d4199866e4f8f Mon Sep 17 00:00:00 2001 From: Jeffrey Schutzman Date: Sat, 1 Nov 2014 10:30:49 -0400 Subject: [PATCH 2/3] remove error_log calls that were used for testing --- wpsc-includes/variations.class.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/wpsc-includes/variations.class.php b/wpsc-includes/variations.class.php index 81819255da..4447aef182 100755 --- a/wpsc-includes/variations.class.php +++ b/wpsc-includes/variations.class.php @@ -34,7 +34,6 @@ static function variations_are_being_used() { $variations_are_being_used = intval( get_option( self::VARIATIONS_BEING_USED_OPTION_NAME, 1 ) ); } - error_log( __CLASS__ . '::' . __FUNCTION__ . ' ' . ( $variations_are_being_used ? 'true' : 'false' ) ); return (bool) $variations_are_being_used; } @@ -117,7 +116,7 @@ function next_variation_group() { return $this->variation_group; } - + function the_variation_group() { $this->variation_group = $this->next_variation_group(); $this->get_variations(); @@ -365,7 +364,6 @@ function _wpsc_remember_if_taxonomy_terms_are_being_used() { if ( $old_variations_being_used != $new_variations_are_being_used ) { delete_option( wpsc_variations::VARIATIONS_BEING_USED_OPTION_NAME ); add_option( wpsc_variations::VARIATIONS_BEING_USED_OPTION_NAME, $new_variations_are_being_used, null, true ); - error_log( __FUNCTION__ . ' updating variations being used option ' . ( $new_variations_are_being_used ? 'true' : 'false' ) ); } } From 2839078a91b6e39cbbc0c9e78908e369ff8438e2 Mon Sep 17 00:00:00 2001 From: Jeffrey Schutzman Date: Sun, 2 Nov 2014 13:29:17 -0500 Subject: [PATCH 3/3] Avoid wpsc_has_variations processing when no variations terms are defined --- wpsc-includes/product-template.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/wpsc-includes/product-template.php b/wpsc-includes/product-template.php index d429635b4b..a820afd3a4 100644 --- a/wpsc-includes/product-template.php +++ b/wpsc-includes/product-template.php @@ -269,6 +269,10 @@ function wpsc_product_has_children( $id, $exclude_unpublished = true ){ function wpsc_product_has_variations( $id = 0 ) { static $has_variations = array(); + if ( ! wpsc_variations::variations_are_being_used() ) { + return false; + } + if ( ! $id ) $id = get_the_ID();