How to update “options” in an existing feature? Here my code:
public function create_product_attributes($product, $variations)
{
if (!$product) {
return false;
}
$product_id = $product->get_id();
$existing_attributes = $product->get_attributes();
error_log(print_r(['variations' => $variations], true));
error_log(print_r(['existing_attributes_raw' => $existing_attributes], true));
// Map existing attributes by taxonomy
$existing_attr_map = [];
foreach ($existing_attributes as $attribute) {
$existing_attr_map[$attribute->get_name()] = $attribute;
}
error_log(print_r(['existing_attributes' => $existing_attr_map], true));
foreach ($variations as $variation) {
$code = sanitize_title($variation['code']);
$name = $variation['name'];
$taxonomy = lavenka_ensure_attribute($code); // pastikan taxonomy ada
// Pastikan term ada di global taxonomy
// 🔁 FIX: pastikan kita tidak secara keliru membuat term bernama angka.
// Jika $name numeric: coba treat sebagai ID. Jika non-numeric: cari by name, jika tidak ada baru buat.
$term_id = 0;
if (is_numeric($name)) {
// kemungkinan $name sudah berupa term ID (terjadi di runs sebelumnya)
$maybe = get_term(intval($name), $taxonomy);
if ($maybe && !is_wp_error($maybe)) {
$term_id = intval($maybe->term_id);
} else {
// kalau tidak ada term dengan ID itu, coba cari nama (fallback)
$maybe_by_name = get_term_by('name', (string) $name, $taxonomy);
if ($maybe_by_name && !is_wp_error($maybe_by_name)) {
$term_id = intval($maybe_by_name->term_id);
} else {
// jangan wp_insert_term dengan angka sebagai nama; treat as string fallback
$inserted = wp_insert_term((string) $name, $taxonomy);
if (!is_wp_error($inserted) && isset($inserted['term_id'])) {
$term_id = intval($inserted['term_id']);
}
}
}
} else {
// normal case: nama string
$maybe = get_term_by('name', $name, $taxonomy);
if ($maybe && !is_wp_error($maybe)) {
$term_id = intval($maybe->term_id);
} else {
$inserted = wp_insert_term($name, $taxonomy);
if (!is_wp_error($inserted) && isset($inserted['term_id'])) {
$term_id = intval($inserted['term_id']);
}
}
}
error_log(print_r(['term_to_add' => $term_id, 'orig_name' => $name], true));
// Kaitkan produk ke term (supaya muncul di filter / editor)
$set_terms = wp_set_object_terms($product_id, [$term_id], $taxonomy, true);
if (is_wp_error($set_terms)) {
error_log("Ada error saat set term to object");
}
if (isset($existing_attr_map[$taxonomy])) {
// Update attribute yang sudah ada
$attribute = $existing_attr_map[$taxonomy];
// 🔧 FIX: konversi per-option agar string term name ("Merah") dikonversi ke term_id.
// jangan langsung intval() semua karena itu mengubah "Merah" -> 0.
$raw_options = $attribute->get_options();
$options = [];
foreach ($raw_options as $opt) {
if (is_numeric($opt)) {
// opt mungkin sudah berupa id; pastikan ada
$term_obj = get_term(intval($opt), $taxonomy);
if ($term_obj && !is_wp_error($term_obj)) {
$options[] = intval($term_obj->term_id);
}
} else {
// opt disimpan sebagai nama (misal "Merah") — cari term id berdasarkan name
$term_by_name = get_term_by('name', (string) $opt, $taxonomy);
if ($term_by_name && !is_wp_error($term_by_name)) {
$options[] = intval($term_by_name->term_id);
} else {
// kalau namanya belum ada di taxonomy, buat baru dan ambil id (aman)
$ins = wp_insert_term((string) $opt, $taxonomy);
if (!is_wp_error($ins) && isset($ins['term_id'])) {
$options[] = intval($ins['term_id']);
}
}
}
}
// bersihkan & unikkan
$options = array_values(array_unique(array_filter($options, fn($v) => $v > 0)));
if (!in_array($term_id, $options, true)) {
$options[] = $term_id;
}
// sinkronkan relasi produk → gunakan daftar term IDs final ($options)
if (!empty($options)) {
// GANTI relasi product ke seluruh options yang valid (replace)
wp_set_object_terms($product_id, $options, $taxonomy, false);
}
$options = array_map('intval', $options);
error_log(print_r(['new_options_existing_attributes_' . $taxonomy => $options], true));
$attribute->set_options($options);
// 🔑 Tambahan penting → jaga flag tetap benar
$attribute->set_position(0);
$attribute->set_visible(true);
$attribute->set_variation(true);
$existing_attributes[$taxonomy] = $attribute;
error_log(print_r(['existing_attributes_after_add_opt' => $existing_attributes[$taxonomy]], true));
} else {
// Buat attribute baru di produk
$attribute = new WC_Product_Attribute();
$attribute->set_id(0);
$attribute->set_name($taxonomy);
$attribute->set_options([$term_id]);
$attribute->set_position(0);
$attribute->set_visible(true);
$attribute->set_variation(true);
$existing_attributes[$taxonomy] = $attribute;
error_log(print_r(['existing_attributes_after_update_opt' => $existing_attributes[$taxonomy]], true));
}
}
$product->set_attributes($existing_attributes);
$product->save();
wc_delete_product_transients($product->get_id());
return true;
}
Above is the function to check or update the characteristic on the basis of input, when this function makes the first characteristic (say attribute color/pa_color with value red) it is successfully made with the variation, but when I use the second time (to update attribute value:
Extra function/helper function I made
function lavenka_ensure_attribute($attr_label) {
global $wpdb;
$attr_name = wc_sanitize_taxonomy_name($attr_label); // ex: color
$taxonomy = wc_attribute_taxonomy_name($attr_name); // ex: pa_color
// cek apakah attribute sudah ada di db
$attribute = $wpdb->get_var(
$wpdb->prepare("SELECT attribute_id FROM {$wpdb->prefix}woocommerce_attribute_taxonomies WHERE attribute_name = %s", $attr_name)
);
if (!$attribute) {
// belum ada -> buat attribute global
wc_create_attribute([
'slug' => $attr_name,
'name' => ucfirst($attr_label),
'type' => 'select',
'order_by'=> 'menu_order',
]);
// flush cache agar WooCommerce daftar ulang taxonomy
delete_transient('wc_attribute_taxonomies');
}
// pastikan taxonomy ter-register di request ini
if (!taxonomy_exists($taxonomy)) {
register_taxonomy($taxonomy, 'product', [
'hierarchical' => true,
'label' => ucfirst($attr_label),
'query_var' => true,
'rewrite' => false,
'public' => false,
]);
}
return $taxonomy;
}
public function create_and_generate_variations($product, $variations, $payload)
{
// ambil semua ID anak dari produk variable
$existing_children = $product->get_children();
$existing_attrs = [];
foreach ($existing_children as $child_id) {
$child = wc_get_product($child_id);
if ($child && $child->is_type('variation')) {
$existing_attrs[] = $child->get_attributes(); // simpan kombinasi attributes
}
}
foreach ($variations as $variation) {
$attr_name = sanitize_title($variation['code']);
$taxonomy = 'pa_' . $attr_name;
// cek apakah kombinasi ini sudah ada
$duplicate = false;
foreach ($existing_attrs as $attrs) {
if (isset($attrs[$taxonomy]) && $attrs[$taxonomy] === $variation['name']) {
$duplicate = true;
break;
}
}
if ($duplicate) {
continue; // skip jika sudah ada
}
// buat variation baru
$variation_obj = new WC_Product_Variation();
$variation_obj->set_parent_id($product->get_id());
// set attribute
$variation_obj->set_attributes([
$taxonomy => $variation['name']
]);
// set harga / stok
$variation_obj->set_regular_price($variation['1st_price'] ?? $payload['price']);
$variation_obj->set_manage_stock(true);
$variation_obj->set_stock_quantity($payload['stock']);
$variation_obj->set_stock_status($payload['stock'] > 0 ? 'instock' : 'outofstock');
// meta Odoo pakai $variation['tmpl_id']
if (!empty($variation['tmpl_id'])) {
$variation_obj->update_meta_data('odoo_variant_id', $variation['id']);
}
// TODO: placeholder upload gambar kalau ada $variation['image']
$variation_obj->save();
}
return true;
}
#WooCommerce #Update #attribute #options #existing #characteristic

