Automattic\WooCommerce\Internal\CLI\Migrator\Core

WooCommerceProductImporter::sync_variationsprivateWC 1.0

Creates or updates product variations with proper mapping and lookup.

Method of the class: WooCommerceProductImporter{}

No Hooks.

Returns

null. Nothing (null).

Usage

// private - for code of main (parent) class only
$result = $this->sync_variations( $product, $variations_data ): void;
$product(WC_Product_Variable) (required)
The parent variable product.
$variations_data(array) (required)
Standardized variation data from mapper.

WooCommerceProductImporter::sync_variations() code WC 10.7.0

private function sync_variations( WC_Product_Variable $product, array $variations_data ): void {
	$parent_product_id       = $product->get_id();
	$parent_original_id      = $product->get_meta( '_original_product_id' );
	$processed_variation_ids = array();

	$variation_count = count( $variations_data );
	wc_get_logger()->debug( "Syncing {$variation_count} variations for product ID {$parent_product_id}", array( 'source' => 'wc-migrator' ) );

	$attribute_taxonomy_map = $this->current_attribute_mapping;

	// Build fallback mapping from product attributes if current mapping is empty.
	if ( empty( $attribute_taxonomy_map ) ) {
		$product_attributes = $product->get_attributes();
		foreach ( $product_attributes as $taxonomy => $attribute_obj ) {
			if ( $attribute_obj->get_variation() ) {
				$attribute_label = wc_attribute_label( $taxonomy, $product );
				// Store mapping with both original case and lowercase for case-insensitive lookup.
				$attribute_taxonomy_map[ $attribute_label ]               = $taxonomy;
				$attribute_taxonomy_map[ strtolower( $attribute_label ) ] = $taxonomy;
			}
		}
	}

	foreach ( $variations_data as $var_data ) {
		$original_variant_id = $var_data['original_id'] ?? null;
		if ( ! $original_variant_id ) {
			wc_get_logger()->warning( 'Skipping variation: Missing original ID.', array( 'source' => 'wc-migrator' ) );
			continue;
		}

		$variation_id = null;
		$variation    = null;

		if ( isset( $this->migration_data['variations_mapping'][ $original_variant_id ] ) ) {
			$_variation_id = $this->migration_data['variations_mapping'][ $original_variant_id ];
			$_variation    = wc_get_product( $_variation_id );
			if ( $_variation instanceof WC_Product_Variation && $_variation->get_parent_id() === $parent_product_id ) {
				$variation    = $_variation;
				$variation_id = $_variation_id;
			} else {
				unset( $this->migration_data['variations_mapping'][ $original_variant_id ] );
			}
		}

		if ( ! $variation ) {
			$query_args = array(
				'post_parent' => $parent_product_id,
				'post_type'   => 'product_variation',
				'numberposts' => 1,
				'post_status' => 'any',
				'meta_key'    => '_original_variant_id', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
				'meta_value'  => $original_variant_id, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value
				'fields'      => 'ids',
			);

			$found_ids = get_posts( $query_args );
			if ( ! empty( $found_ids ) ) {
				$variation_id = $found_ids[0];
				$variation    = wc_get_product( $variation_id );
				if ( ! ( $variation instanceof WC_Product_Variation ) ) {
					wc_get_logger()->warning( "Found post ID {$variation_id} for original variant {$original_variant_id}, but it's not a WC_Product_Variation.", array( 'source' => 'wc-migrator' ) );
					$variation    = null;
					$variation_id = null;
				}
			}
		}

		if ( ! $variation ) {
			$variation = new WC_Product_Variation();
			$variation->set_parent_id( $parent_product_id );
		}

		$variation->set_status( 'publish' );
		$variation->set_menu_order( $var_data['menu_order'] ?? 0 );

		$variation->set_regular_price( $var_data['regular_price'] ?? '' );
		$variation->set_sale_price( $var_data['sale_price'] ?? '' );

		if ( ! empty( $var_data['sku'] ) ) {
			add_filter( 'wc_product_has_unique_sku', '__return_false', 999 );
			$variation->set_sku( $var_data['sku'] );
			remove_filter( 'wc_product_has_unique_sku', '__return_false', 999 );
		}

		$variation->set_manage_stock( $var_data['manage_stock'] ?? false );
		$variation->set_stock_quantity( $var_data['stock_quantity'] ?? null );
		$variation->set_stock_status( $var_data['stock_status'] ?? 'instock' );

		$variation->set_weight( $var_data['weight'] ?? '' );

		if ( ! empty( $var_data['tax_status'] ) ) {
			$variation->set_tax_status( $var_data['tax_status'] );
		}

		$image_original_id = $var_data['image_original_id'] ?? null;
		if ( $image_original_id && isset( $this->migration_data['images_mapping'][ $image_original_id ] ) ) {
			$variation->set_image_id( $this->migration_data['images_mapping'][ $image_original_id ] );
		} else {
			$variation->set_image_id( '' );
		}

		$wc_variation_attributes = array();
		if ( ! empty( $var_data['attributes'] ) && is_array( $var_data['attributes'] ) ) {
			foreach ( $var_data['attributes'] as $attr_name => $attr_value ) {
				if ( isset( $attribute_taxonomy_map[ $attr_name ] ) ) {
					$taxonomy                  = $attribute_taxonomy_map[ $attr_name ];
					$term_slug                 = sanitize_title( $attr_value );
					$normalized_attribute_name = wc_variation_attribute_name( $taxonomy );

					$wc_variation_attributes[ $normalized_attribute_name ] = $term_slug;
				} else {
					wc_get_logger()->warning( "Attribute taxonomy mapping not found for option '{$attr_name}' while processing variation {$original_variant_id}.", array( 'source' => 'wc-migrator' ) );
				}
			}
		}
		$variation->set_attributes( $wc_variation_attributes );

		$variation->update_meta_data( '_original_variant_id', $original_variant_id );
		if ( $parent_original_id ) {
			$variation->update_meta_data( '_original_product_id', $parent_original_id );
		}

		$saved_variation_id = $variation->save();
		if ( $saved_variation_id ) {
			$processed_variation_ids[] = $saved_variation_id;
			$this->migration_data['variations_mapping'][ $original_variant_id ] = $saved_variation_id;
			if ( ! empty( $var_data['cost_of_goods'] ) ) {
				update_post_meta( $saved_variation_id, '_cogs_total_value', (float) $var_data['cost_of_goods'] );
			}
		} else {
			wc_get_logger()->error( "Failed to save variation for original variant {$original_variant_id}", array( 'source' => 'wc-migrator' ) );
		}
	}

	WC_Product_Variable::sync( $parent_product_id );

	$processed_count = count( $processed_variation_ids );
	wc_get_logger()->debug( "Successfully synced {$processed_count}/{$variation_count} variations for product ID {$parent_product_id}", array( 'source' => 'wc-migrator' ) );
}