diff --git a/includes/api/legacy/v2/class-wc-api-products.php b/includes/api/legacy/v2/class-wc-api-products.php index b7911573038..d30101f7f96 100644 --- a/includes/api/legacy/v2/class-wc-api-products.php +++ b/includes/api/legacy/v2/class-wc-api-products.php @@ -2023,6 +2023,7 @@ class WC_API_Products extends WC_API_Resource { // Clear transients delete_transient( 'wc_attribute_taxonomies' ); + WC_Cache_Helper::incr_cache_prefix( 'woocommerce-attributes' ); $this->server->send_status( 201 ); @@ -2108,6 +2109,7 @@ class WC_API_Products extends WC_API_Resource { // Clear transients delete_transient( 'wc_attribute_taxonomies' ); + WC_Cache_Helper::incr_cache_prefix( 'woocommerce-attributes' ); return $this->get_product_attribute( $id ); } catch ( WC_API_Exception $e ) { @@ -2169,6 +2171,7 @@ class WC_API_Products extends WC_API_Resource { // Clear transients delete_transient( 'wc_attribute_taxonomies' ); + WC_Cache_Helper::incr_cache_prefix( 'woocommerce-attributes' ); return array( 'message' => sprintf( __( 'Deleted %s', 'woocommerce' ), 'product_attribute' ) ); } catch ( WC_API_Exception $e ) { diff --git a/includes/api/legacy/v3/class-wc-api-products.php b/includes/api/legacy/v3/class-wc-api-products.php index a7bce7c3de1..6395dd0258b 100644 --- a/includes/api/legacy/v3/class-wc-api-products.php +++ b/includes/api/legacy/v3/class-wc-api-products.php @@ -2577,6 +2577,7 @@ class WC_API_Products extends WC_API_Resource { // Clear transients. wp_schedule_single_event( time(), 'woocommerce_flush_rewrite_rules' ); delete_transient( 'wc_attribute_taxonomies' ); + WC_Cache_Helper::incr_cache_prefix( 'woocommerce-attributes' ); $this->server->send_status( 201 ); @@ -2663,6 +2664,7 @@ class WC_API_Products extends WC_API_Resource { // Clear transients. wp_schedule_single_event( time(), 'woocommerce_flush_rewrite_rules' ); delete_transient( 'wc_attribute_taxonomies' ); + WC_Cache_Helper::incr_cache_prefix( 'woocommerce-attributes' ); return $this->get_product_attribute( $id ); } catch ( WC_API_Exception $e ) { @@ -2725,6 +2727,7 @@ class WC_API_Products extends WC_API_Resource { // Clear transients. wp_schedule_single_event( time(), 'woocommerce_flush_rewrite_rules' ); delete_transient( 'wc_attribute_taxonomies' ); + WC_Cache_Helper::incr_cache_prefix( 'woocommerce-attributes' ); return array( 'message' => sprintf( __( 'Deleted %s', 'woocommerce' ), 'product_attribute' ) ); } catch ( WC_API_Exception $e ) { diff --git a/includes/class-wc-install.php b/includes/class-wc-install.php index a5d64cc919a..1c04336cde7 100644 --- a/includes/class-wc-install.php +++ b/includes/class-wc-install.php @@ -642,6 +642,9 @@ class WC_Install { ); // WPCS: unprepared SQL ok. } } + + // Clear table caches. + delete_transient( 'wc_attribute_taxonomies' ); } /** diff --git a/includes/wc-attribute-functions.php b/includes/wc-attribute-functions.php index d8e31c4da24..f4a9535348a 100644 --- a/includes/wc-attribute-functions.php +++ b/includes/wc-attribute-functions.php @@ -44,20 +44,88 @@ function wc_implode_text_attributes( $attributes ) { /** * Get attribute taxonomies. * - * @return array of objects + * @return array of objects, @since 3.6.0 these are also indexed by ID. */ function wc_get_attribute_taxonomies() { - $attribute_taxonomies = get_transient( 'wc_attribute_taxonomies' ); + $prefix = WC_Cache_Helper::get_cache_prefix( 'woocommerce-attributes' ); + $cache_key = $prefix . 'attributes'; + $cache_value = wp_cache_get( $cache_key, 'woocommerce-attributes' ); - if ( false === $attribute_taxonomies ) { - global $wpdb; - - $attribute_taxonomies = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}woocommerce_attribute_taxonomies WHERE attribute_name != '' ORDER BY attribute_name ASC;" ); - - set_transient( 'wc_attribute_taxonomies', $attribute_taxonomies ); + if ( $cache_value ) { + return $cache_value; } - return (array) array_filter( apply_filters( 'woocommerce_attribute_taxonomies', $attribute_taxonomies ) ); + $raw_attribute_taxonomies = get_transient( 'wc_attribute_taxonomies' ); + + if ( false === $raw_attribute_taxonomies ) { + global $wpdb; + + $raw_attribute_taxonomies = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}woocommerce_attribute_taxonomies WHERE attribute_name != '' ORDER BY attribute_name ASC;" ); + + set_transient( 'wc_attribute_taxonomies', $raw_attribute_taxonomies ); + } + + /** + * Filter attribute taxonomies. + * + * @param array $attribute_taxonomies Results of the DB query. Each taxonomy is an object. + */ + $raw_attribute_taxonomies = (array) array_filter( apply_filters( 'woocommerce_attribute_taxonomies', $raw_attribute_taxonomies ) ); + + // Index by ID for easer lookups. + $attribute_taxonomies = array(); + + foreach ( $raw_attribute_taxonomies as $result ) { + $attribute_taxonomies[ 'id:' . $result->attribute_id ] = $result; + } + + wp_cache_set( $cache_key, $attribute_taxonomies, 'woocommerce-attributes' ); + + return $attribute_taxonomies; +} + +/** + * Get (cached) attribute taxonomy ID and name pairs. + * + * @since 3.6.0 + * @return array + */ +function wc_get_attribute_taxonomy_ids() { + $prefix = WC_Cache_Helper::get_cache_prefix( 'woocommerce-attributes' ); + $cache_key = $prefix . 'ids'; + $cache_value = wp_cache_get( $cache_key, 'woocommerce-attributes' ); + + if ( $cache_value ) { + return $cache_value; + } + + $taxonomy_ids = array_map( 'absint', wp_list_pluck( wc_get_attribute_taxonomies(), 'attribute_id', 'attribute_name' ) ); + + wp_cache_set( $cache_key, $taxonomy_ids, 'woocommerce-attributes' ); + + return $taxonomy_ids; +} + +/** + * Get (cached) attribute taxonomy label and name pairs. + * + * @since 3.6.0 + * @return array + */ +function wc_get_attribute_taxonomy_labels() { + $prefix = WC_Cache_Helper::get_cache_prefix( 'woocommerce-attributes' ); + $cache_key = $prefix . 'labels'; + $cache_value = wp_cache_get( $cache_key, 'woocommerce-attributes' ); + + if ( $cache_value ) { + return $cache_value; + } + + $taxonomy_labels = wp_list_pluck( wc_get_attribute_taxonomies(), 'attribute_label', 'attribute_name' ); + + wp_cache_set( $cache_key, $taxonomy_labels, 'woocommerce-attributes' ); + + return $taxonomy_labels; } /** @@ -89,24 +157,9 @@ function wc_variation_attribute_name( $attribute_name ) { * @return string Return an empty string if attribute doesn't exist. */ function wc_attribute_taxonomy_name_by_id( $attribute_id ) { - global $wpdb; - - $attribute_name = $wpdb->get_var( - $wpdb->prepare( - " - SELECT attribute_name - FROM {$wpdb->prefix}woocommerce_attribute_taxonomies - WHERE attribute_id = %d - ", - $attribute_id - ) - ); - - if ( $attribute_name && ! is_wp_error( $attribute_name ) ) { - return wc_attribute_taxonomy_name( $attribute_name ); - } - - return ''; + $taxonomy_ids = wc_get_attribute_taxonomy_ids(); + $attribute_name = (string) array_search( $attribute_id, $taxonomy_ids, true ); + return wc_attribute_taxonomy_name( $attribute_name ); } /** @@ -117,10 +170,10 @@ function wc_attribute_taxonomy_name_by_id( $attribute_id ) { * @return int */ function wc_attribute_taxonomy_id_by_name( $name ) { - $name = wc_attribute_taxonomy_slug( $name ); - $taxonomies = wp_list_pluck( wc_get_attribute_taxonomies(), 'attribute_id', 'attribute_name' ); + $name = wc_attribute_taxonomy_slug( $name ); + $taxonomy_ids = wc_get_attribute_taxonomy_ids(); - return isset( $taxonomies[ $name ] ) ? (int) $taxonomies[ $name ] : 0; + return isset( $taxonomy_ids[ $name ] ) ? $taxonomy_ids[ $name ] : 0; } /** @@ -133,7 +186,7 @@ function wc_attribute_taxonomy_id_by_name( $name ) { function wc_attribute_label( $name, $product = '' ) { if ( taxonomy_is_product_attribute( $name ) ) { $name = wc_attribute_taxonomy_slug( $name ); - $all_labels = wp_list_pluck( wc_get_attribute_taxonomies(), 'attribute_label', 'attribute_name' ); + $all_labels = wc_get_attribute_taxonomy_labels(); $label = isset( $all_labels[ $name ] ) ? $all_labels[ $name ] : $name; } elseif ( $product ) { if ( $product->is_type( 'variation' ) ) { @@ -165,17 +218,11 @@ function wc_attribute_label( $name, $product = '' ) { * @return string */ function wc_attribute_orderby( $name ) { - global $wc_product_attributes, $wpdb; + $name = wc_attribute_taxonomy_slug( $name ); + $id = wc_attribute_taxonomy_id_by_name( $name ); + $taxonomies = wc_get_attribute_taxonomies(); - $name = wc_attribute_taxonomy_slug( $name ); - - if ( isset( $wc_product_attributes[ 'pa_' . $name ] ) ) { - $orderby = $wc_product_attributes[ 'pa_' . $name ]->attribute_orderby; - } else { - $orderby = $wpdb->get_var( $wpdb->prepare( "SELECT attribute_orderby FROM {$wpdb->prefix}woocommerce_attribute_taxonomies WHERE attribute_name = %s;", $name ) ); - } - - return apply_filters( 'woocommerce_attribute_orderby', $orderby, $name ); + return apply_filters( 'woocommerce_attribute_orderby', isset( $taxonomies[ 'id:' . $id ] ) ? $taxonomies[ 'id:' . $id ]->attribute_orderby : 'menu_order', $name ); } /** @@ -379,23 +426,13 @@ function wc_array_filter_default_attributes( $attribute ) { * @return stdClass|null */ function wc_get_attribute( $id ) { - global $wpdb; + $attributes = wc_get_attribute_taxonomies(); - $data = $wpdb->get_row( - $wpdb->prepare( - " - SELECT * - FROM {$wpdb->prefix}woocommerce_attribute_taxonomies - WHERE attribute_id = %d - ", - $id - ) - ); - - if ( is_wp_error( $data ) || is_null( $data ) ) { + if ( ! isset( $attributes[ 'id:' . $id ] ) ) { return null; } + $data = $attributes[ 'id:' . $id ]; $attribute = new stdClass(); $attribute->id = (int) $data->attribute_id; $attribute->name = $data->attribute_label; @@ -403,7 +440,6 @@ function wc_get_attribute( $id ) { $attribute->type = $data->attribute_type; $attribute->order_by = $data->attribute_orderby; $attribute->has_archives = (bool) $data->attribute_public; - return $attribute; } @@ -572,6 +608,7 @@ function wc_create_attribute( $args ) { // Clear cache and flush rewrite rules. wp_schedule_single_event( time(), 'woocommerce_flush_rewrite_rules' ); delete_transient( 'wc_attribute_taxonomies' ); + WC_Cache_Helper::incr_cache_prefix( 'woocommerce-attributes' ); return $id; } @@ -661,6 +698,7 @@ function wc_delete_attribute( $id ) { do_action( 'woocommerce_attribute_deleted', $id, $name, $taxonomy ); wp_schedule_single_event( time(), 'woocommerce_flush_rewrite_rules' ); delete_transient( 'wc_attribute_taxonomies' ); + WC_Cache_Helper::incr_cache_prefix( 'woocommerce-attributes' ); return true; } @@ -677,7 +715,8 @@ function wc_delete_attribute( $id ) { * @return string */ function wc_attribute_taxonomy_slug( $attribute_name ) { - $cache_key = 'slug-' . $attribute_name; + $prefix = WC_Cache_Helper::get_cache_prefix( 'woocommerce-attributes' ); + $cache_key = $prefix . 'slug-' . $attribute_name; $cache_value = wp_cache_get( $cache_key, 'woocommerce-attributes' ); if ( $cache_value ) { diff --git a/includes/wc-update-functions.php b/includes/wc-update-functions.php index c5abb6fadc5..1b34a084afe 100644 --- a/includes/wc-update-functions.php +++ b/includes/wc-update-functions.php @@ -672,6 +672,9 @@ function wc_update_220_attributes() { } } } + + delete_transient( 'wc_attribute_taxonomies' ); + WC_Cache_Helper::incr_cache_prefix( 'woocommerce-attributes' ); } /** diff --git a/tests/framework/helpers/class-wc-helper-product.php b/tests/framework/helpers/class-wc-helper-product.php index 9d138400e29..54b3dfe8b03 100644 --- a/tests/framework/helpers/class-wc-helper-product.php +++ b/tests/framework/helpers/class-wc-helper-product.php @@ -169,6 +169,7 @@ class WC_Helper_Product { // Make sure caches are clean. delete_transient( 'wc_attribute_taxonomies' ); + WC_Cache_Helper::incr_cache_prefix( 'woocommerce-attributes' ); // These are exported as labels, so convert the label to a name if possible first. $attribute_labels = wp_list_pluck( wc_get_attribute_taxonomies(), 'attribute_label', 'attribute_name' );