WC_Product_Data_Store_CPT::find_matching_product_variation( WC_Product $product, array $match_attributes = array() )

Find a matching (enabled) variation within a variable product.


Description Description


Parameters Parameters

$product

(Required) Variable product.

$match_attributes

(Optional) Array of attributes we want to try to match.

Default value: array()


Top ↑

Return Return

(int) Matching variation ID or 0.


Top ↑

Source Source

File: includes/data-stores/class-wc-product-data-store-cpt.php

	public function find_matching_product_variation( $product, $match_attributes = array() ) {
		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 existance.
		 */
		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;
	}

Top ↑

Changelog Changelog

Changelog
Version Description
3.0.0 Introduced.


Top ↑

User Contributed Notes User Contributed Notes

You must log in before being able to contribute a note or feedback.