WooCommerce: Update attribute options of existing characteristic

WooCommerce: Update attribute options of existing characteristic

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

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *