) && '' === $item['value'], ARRAY_FILTER_USE_BOTH );
$attributes_not_for_variations =
$is_variation || $is_variable_product ?
array_keys( array_filter( $temp, fn( $item ) => 0 === $item['is_variation'] ) ) :
array_keys( $temp );
// * Obtain the terms used for each attribute.
// Output: $terms_used_per_attribute =
// [
// 'pa_...' => [
// [
// 'term_id' => ,
// 'attribute' => 'pa_...'
// 'slug' =>
// ],...
// ],...
// ]
$sql = $wpdb->prepare(
"select tt.term_id, tt.taxonomy as attribute, t.slug from {$wpdb->prefix}term_relationships tr
join {$wpdb->term_taxonomy} tt on tt.term_taxonomy_id = tr.term_taxonomy_id
join {$wpdb->terms} t on t.term_id=tt.term_id
where tr.object_id=%d and taxonomy like %s;",
$main_product_id,
'pa_%'
);
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
$terms_used_per_attribute = $wpdb->get_results( $sql, ARRAY_A );
foreach ( $terms_used_per_attribute as &$term ) {
$term['attribute'] = strtolower( rawurlencode( $term['attribute'] ) );
}
$terms_used_per_attribute = ArrayUtil::group_by_column( $terms_used_per_attribute, 'attribute' );
// * Obtain the actual variations defined (only if variations exist).
// Output: $variations_defined =
// [
// => [
// [
// 'variation_id' => ,
// 'attribute' => 'pa_...'
// 'slug' =>
// ],...
// ],...
// ]
//
// Note that this does NOT include "any..." attributes!
if ( ! $is_variation && ( ! $is_variable_product || empty( $variation_ids ) ) ) {
$variations_defined = array();
} else {
$sql = $wpdb->prepare(
"select post_id as variation_id, substr(meta_key,11) as attribute, meta_value as slug from {$wpdb->postmeta}
where post_id in (select ID from {$wpdb->posts} where (id=%d or post_parent=%d) and post_type = 'product_variation')
and meta_key like %s
and meta_value != ''",
$product_id,
$product_id,
'attribute_pa_%'
);
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
$variations_defined = $wpdb->get_results( $sql, ARRAY_A );
$variations_defined = ArrayUtil::group_by_column( $variations_defined, 'variation_id' );
}
// Now we'll fill an array with all the data rows to be inserted in the lookup table.
$insert_data = array();
// * Insert data for the main product
if ( ! $is_variation ) {
foreach ( $attributes_not_for_variations as $attribute_name ) {
foreach ( ( $terms_used_per_attribute[ $attribute_name ] ?? array() ) as $attribute_data ) {
$insert_data[] = array( $product_id, $main_product_id, $attribute_name, $attribute_data['term_id'], 0, $product_ids_with_stock_status[ $product_id ] );
}
}
}
// * Insert data for the variations defined
// Remove the non-variation attributes data first.
$terms_used_per_attribute = array_diff_key( $terms_used_per_attribute, array_flip( $attributes_not_for_variations ) );
$used_attributes_per_variation = array();
foreach ( $variations_defined as $variation_id => $variation_data ) {
$used_attributes_per_variation[ $variation_id ] = array();
foreach ( $variation_data as $variation_attribute_data ) {
$attribute_name = $variation_attribute_data['attribute'];
$used_attributes_per_variation[ $variation_id ][] = $attribute_name;
$term_id = current( array_filter( ( $terms_used_per_attribute[ $attribute_name ] ?? array() ), fn( $item ) => $item['slug'] === $variation_attribute_data['slug'] ) )['term_id'] ?? null;
if ( is_null( $term_id ) ) {
continue;
}
$insert_data[] = array( $variation_id, $main_product_id, $attribute_name, $term_id, 1, $product_ids_with_stock_status[ $variation_id ] ?? false );
}
}
// * Insert data for variations that have "any..." attributes and at least one defined attribute
foreach ( $used_attributes_per_variation as $variation_id => $attributes_list ) {
$any_attributes = array_diff_key( $terms_used_per_attribute, array_flip( $attributes_list ) );
foreach ( $any_attributes as $attributes_data ) {
foreach ( $attributes_data as $attribute_data ) {
$insert_data[] = array( $variation_id, $main_product_id, $attribute_data['attribute'], $attribute_data['term_id'], 1, $product_ids_with_stock_status[ $variation_id ] ?? false );
}
}
}
// * Insert data for variations that have all their attributes defined as "any..."
$variations_with_all_any = array_keys( array_diff_key( array_flip( $variation_ids ), $used_attributes_per_variation ) );
foreach ( $variations_with_all_any as $variation_id ) {
foreach ( $terms_used_per_attribute as $attribute_name => $attribute_terms ) {
foreach ( $attribute_terms as $attribute_term ) {
$insert_data[] = array( $variation_id, $main_product_id, $attribute_name, $attribute_term['term_id'], 1, $product_ids_with_stock_status[ $variation_id ] ?? false );
}
}
}
// * We have all the data to insert, let's go and insert it.
$insert_data_chunks = array_chunk( $insert_data, 100 );
foreach ( $insert_data_chunks as $insert_data_chunk ) {
$sql = 'INSERT INTO ' . $this->lookup_table_name . ' (
product_id,
product_or_parent_id,
taxonomy,
term_id,
is_variation_attribute,
in_stock)
VALUES (';
$values_strings = array();
foreach ( $insert_data_chunk as $dataset ) {
$attribute_name = esc_sql( $dataset[2] );
$values_strings[] = "{$dataset[0]},{$dataset[1]},'{$attribute_name}',{$dataset[3]},{$dataset[4]},{$dataset[5]}";
}
$sql .= implode( '),(', $values_strings ) . ')';
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
$result = $wpdb->query( $sql );
if ( false === $result ) {
throw new \WC_Data_Exception(
0,
'INSERT statement failed',
0,
array(
'db_error' => esc_html( $wpdb->last_error ),
'db_query' => esc_html( $wpdb->last_query ),
)
);
}
}
}
}