Update class-wc-product-data-store-cpt.php

Updating find_matching_product_variation() function to be faster
This commit is contained in:
Matthew Rochow 2018-07-26 08:00:40 +10:00 committed by Mike Jolley
parent a7463c5535
commit 01d7eaf92f
1 changed files with 50 additions and 47 deletions

View File

@ -1052,61 +1052,64 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
* @return int Matching variation ID or 0. * @return int Matching variation ID or 0.
*/ */
public function find_matching_product_variation( $product, $match_attributes = array() ) { public function find_matching_product_variation( $product, $match_attributes = array() ) {
$query_args = array( global $wpdb;
'post_parent' => $product->get_id(),
'post_type' => 'product_variation',
'orderby' => 'menu_order',
'order' => 'ASC',
'fields' => 'ids',
'post_status' => 'publish',
'numberposts' => 1,
'meta_query' => array(), // phpcs:ignore WordPress.VIP.SlowDBQuery.slow_db_query_meta_query
);
// Allow large queries in case user has many variations or attributes. $matched_variation = 0;
$GLOBALS['wpdb']->query( 'SET SESSION SQL_BIG_SELECTS=1' ); $sorted_meta = array();
foreach ( $product->get_attributes() as $attribute ) { // Get any variations of the main product
if ( ! $attribute->get_variation() ) { $variation_ids = $wpdb->get_results("
continue; SELECT ID
FROM {$wpdb->prefix}posts
WHERE {$wpdb->prefix}posts.post_parent = " . $product->get_id() . "
AND {$wpdb->prefix}posts.post_status = 'publish'
AND {$wpdb->prefix}posts.post_type = 'product_variation'
", ARRAY_A);
if( $variation_ids ) {
foreach( $variation_ids as $ids ) {
$variations_string .= $ids['ID'] . ',';
} }
$attribute_field_name = 'attribute_' . sanitize_title( $attribute->get_name() ); $variations_string = rtrim( $variations_string, ',' );
if ( ! isset( $match_attributes[ $attribute_field_name ] ) ) { // Get the attributes of the variations
return 0; $attributes = $wpdb->get_results("
SELECT * FROM {$wpdb->prefix}postmeta
WHERE post_id
IN($variations_string)
AND meta_key LIKE 'attribute%'
",
ARRAY_A);
if( $attributes ) {
// Sort them into a nice easy array for us to filter
foreach( $attributes as $m ) {
$sorted_meta[ $m['post_id'] ][ $m['meta_key'] ] = $m['meta_value'];
}
// Check each variation to find the one that matches the $match_attributes
// Note: Not all meta fields will be set which is why we check existance
foreach( $sorted_meta as $post_id => $variation ) {
$match = true;
foreach( $match_attributes as $k => $v ) {
if( array_key_exists( $k, $variation ) ) {
if( $variation[ $k ] != $v && !empty( $variation[ $k ] ) ) {
$match = false;
}
}
}
// Bingo
if( true == $match ) {
$matched_variation = $post_id;
}
}
} }
// Note not wc_clean here to prevent removal of entities.
$value = $match_attributes[ $attribute_field_name ];
$query_args['meta_query'][] = array(
'relation' => 'OR',
array(
'key' => $attribute_field_name,
'value' => array( '', $value ),
'compare' => 'IN',
),
array(
'key' => $attribute_field_name,
'compare' => 'NOT EXISTS',
),
);
} }
$variations = get_posts( $query_args ); return $matched_variation;
if ( $variations && ! is_wp_error( $variations ) ) {
return current( $variations );
} elseif ( version_compare( get_post_meta( $product->get_id(), '_product_version', true ), '2.4.0', '<' ) ) {
/**
* Pre 2.4 handling where 'slugs' were saved instead of the full text attribute.
* Fallback is here because there are cases where data will be 'synced' but the product version will remain the same.
*/
return ( array_map( 'sanitize_title', $match_attributes ) === $match_attributes ) ? 0 : $this->find_matching_product_variation( $product, array_map( 'sanitize_title', $match_attributes ) );
}
return 0;
} }
/** /**