WC_Product_Data_Store_CPT::find_matching_product_variation
Find a matching (enabled) variation within a variable product.
Method of the class: WC_Product_Data_Store_CPT{}
No Hooks.
Returns
Int. Matching variation ID or 0.
Usage
$WC_Product_Data_Store_CPT = new WC_Product_Data_Store_CPT(); $WC_Product_Data_Store_CPT->find_matching_product_variation( $product, $match_attributes );
- $product(WC_Product) (required)
- Variable product.
- $match_attributes(array)
- Array of attributes we want to try to match.
Default: array()
Changelog
| Since 3.0.0 | Introduced. |
WC_Product_Data_Store_CPT::find_matching_product_variation() WC Product Data Store CPT::find matching product variation code WC 10.3.6
public function find_matching_product_variation( $product, $match_attributes = array() ) {
if ( ProductType::VARIATION === $product->get_type() ) {
// Can't get a variation of a variation.
return 0;
}
global $wpdb;
$meta_attribute_names = array();
// Get attributes to match in meta.
foreach ( $product->get_attributes() as $attribute ) {
if ( ! $attribute->get_variation() ) {
continue;
}
$meta_attribute_names[] = 'attribute_' . sanitize_title( $attribute->get_name() );
}
// Get the attributes of the variations.
$query = $wpdb->prepare(
"
SELECT postmeta.post_id, postmeta.meta_key, postmeta.meta_value, posts.menu_order FROM {$wpdb->postmeta} as postmeta
LEFT JOIN {$wpdb->posts} as posts ON postmeta.post_id=posts.ID
WHERE postmeta.post_id IN (
SELECT ID FROM {$wpdb->posts}
WHERE {$wpdb->posts}.post_parent = %d
AND {$wpdb->posts}.post_status = 'publish'
AND {$wpdb->posts}.post_type = 'product_variation'
)
",
$product->get_id()
);
$query .= " AND postmeta.meta_key IN ( '" . implode( "','", array_map( 'esc_sql', $meta_attribute_names ) ) . "' )";
$query .= ' ORDER BY posts.menu_order ASC, postmeta.post_id ASC;';
$attributes = $wpdb->get_results( $query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
if ( ! $attributes ) {
return 0;
}
$sorted_meta = array();
foreach ( $attributes as $m ) {
$sorted_meta[ $m->post_id ][ $m->meta_key ] = $m->meta_value; // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
}
/**
* 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 existence.
*/
foreach ( $sorted_meta as $variation_id => $variation ) {
$match = true;
// Loop over the variation meta keys and values i.e. what is saved to the products. Note: $attribute_value is empty when 'any' is in use.
foreach ( $variation as $attribute_key => $attribute_value ) {
$match_any_value = '' === $attribute_value;
if ( ! $match_any_value && ! array_key_exists( $attribute_key, $match_attributes ) ) {
$match = false; // Requires a selection but no value was provide.
}
if ( array_key_exists( $attribute_key, $match_attributes ) ) { // Value to match was provided.
if ( ! $match_any_value && $match_attributes[ $attribute_key ] !== $attribute_value ) {
$match = false; // Provided value does not match variation.
}
}
}
if ( true === $match ) {
return $variation_id;
}
}
if ( 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;
}