|
|
@@ -375,26 +375,88 @@ class Studiou_WC_Product_Manage_Product_Import {
|
|
|
$reviews_enabled = isset($data['Povolit zákaznické recenze?']) && $data['Povolit zákaznické recenze?'] === '1';
|
|
|
$product->set_reviews_allowed($reviews_enabled);
|
|
|
|
|
|
- // Handle product attribute
|
|
|
+ // v1.6.3 — Handle product attribute (taxonomy vs. custom).
|
|
|
+ //
|
|
|
+ // Pre-1.6.3 behaviour ignored the `Vlastnost 1 globální` column and
|
|
|
+ // forced every attribute into a global pa_ taxonomy: it called
|
|
|
+ // create_attribute_if_not_exists() unconditionally, set the
|
|
|
+ // attribute name via wc_attribute_taxonomy_name(), and passed raw
|
|
|
+ // name strings to set_options(). Result: custom (product-level)
|
|
|
+ // attributes silently became global taxonomies; for variations,
|
|
|
+ // raw names landed where slugs were required, so the storefront
|
|
|
+ // couldn't match the customer's selection ("No matching variation").
|
|
|
+ //
|
|
|
+ // Branch on the global flag and, for the taxonomy path, resolve
|
|
|
+ // each value to a term (creating it if missing), pass term IDs to
|
|
|
+ // set_options(), remember the slugs so process_variation() can
|
|
|
+ // store the correct value, and link the terms via
|
|
|
+ // wp_set_object_terms after the product save.
|
|
|
+ //
|
|
|
+ // Hand-built CSVs that omit `Vlastnost 1 globální` default to the
|
|
|
+ // custom branch.
|
|
|
+ //
|
|
|
+ // LIVE-TEST GATE: §5.B.0 of review-00-plan-00.md asks for a real
|
|
|
+ // storefront round-trip before deploy. Verify both the taxonomy
|
|
|
+ // and custom paths there.
|
|
|
+ $term_ids_for_link = array();
|
|
|
+ $taxonomy_for_link = '';
|
|
|
if (isset($data['Název 1 vlastnosti']) && !empty($data['Název 1 vlastnosti'])) {
|
|
|
- $attribute_name = $data['Název 1 vlastnosti'];
|
|
|
+ $attribute_name = trim($data['Název 1 vlastnosti']);
|
|
|
$attribute_values = isset($data['Hodnota(y) 1 vlastnosti']) ? $data['Hodnota(y) 1 vlastnosti'] : '';
|
|
|
$is_visible = isset($data['Vlastnost 1 viditelnost']) && $data['Vlastnost 1 viditelnost'] === '1';
|
|
|
$is_variation = isset($data['Vlastnost 1 varianta']) && $data['Vlastnost 1 varianta'] === '1';
|
|
|
-
|
|
|
- // Create attribute taxonomy if it doesn't exist
|
|
|
- $this->db->create_attribute_if_not_exists($attribute_name);
|
|
|
+ $is_global = isset($data['Vlastnost 1 globální']) && $data['Vlastnost 1 globální'] === '1';
|
|
|
+ $values = array_map('trim', explode('|', $attribute_values));
|
|
|
+ $values = array_values(array_filter($values, function($v) { return $v !== ''; }));
|
|
|
|
|
|
$attribute = new WC_Product_Attribute();
|
|
|
- $attribute->set_name(wc_attribute_taxonomy_name($attribute_name));
|
|
|
- $attribute->set_visible($is_visible);
|
|
|
- $attribute->set_variation($is_variation);
|
|
|
|
|
|
- // Set attribute options (terms)
|
|
|
- $values = array_map('trim', explode('|', $attribute_values));
|
|
|
- $attribute->set_options($values);
|
|
|
+ if ($is_global) {
|
|
|
+ // Taxonomy attribute — register, resolve/create terms,
|
|
|
+ // pass term IDs (not names) to set_options.
|
|
|
+ $this->db->create_attribute_if_not_exists($attribute_name);
|
|
|
+ $taxonomy = wc_attribute_taxonomy_name($attribute_name);
|
|
|
+ if (!taxonomy_exists($taxonomy)) {
|
|
|
+ register_taxonomy($taxonomy, 'product');
|
|
|
+ }
|
|
|
|
|
|
- $product->set_attributes(array($attribute));
|
|
|
+ $term_ids = array();
|
|
|
+ foreach ($values as $value) {
|
|
|
+ $term = get_term_by('name', $value, $taxonomy);
|
|
|
+ if (!$term) {
|
|
|
+ $inserted = wp_insert_term($value, $taxonomy);
|
|
|
+ if (is_wp_error($inserted)) {
|
|
|
+ error_log('STUDIOU WC IMPORT: failed to insert term "' . $value . '" into ' . $taxonomy . ': ' . $inserted->get_error_message());
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ $term = get_term($inserted['term_id'], $taxonomy);
|
|
|
+ }
|
|
|
+ if ($term && !is_wp_error($term)) {
|
|
|
+ $term_ids[] = (int) $term->term_id;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ $attribute->set_id(wc_attribute_taxonomy_id_by_name($attribute_name));
|
|
|
+ $attribute->set_name($taxonomy);
|
|
|
+ $attribute->set_options($term_ids);
|
|
|
+ $attribute->set_visible($is_visible);
|
|
|
+ $attribute->set_variation($is_variation);
|
|
|
+ $product->set_attributes(array($attribute));
|
|
|
+
|
|
|
+ // Defer term-relationship linkage until after save() so we
|
|
|
+ // have a real product ID.
|
|
|
+ $term_ids_for_link = $term_ids;
|
|
|
+ $taxonomy_for_link = $taxonomy;
|
|
|
+ } else {
|
|
|
+ // Custom (product-level) attribute — no taxonomy, store
|
|
|
+ // the raw display name and the raw values.
|
|
|
+ $attribute->set_id(0);
|
|
|
+ $attribute->set_name($attribute_name);
|
|
|
+ $attribute->set_options($values);
|
|
|
+ $attribute->set_visible($is_visible);
|
|
|
+ $attribute->set_variation($is_variation);
|
|
|
+ $product->set_attributes(array($attribute));
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
// Handle minimum/maximum quantity
|
|
|
@@ -408,6 +470,14 @@ class Studiou_WC_Product_Manage_Product_Import {
|
|
|
// Save product
|
|
|
$saved_id = $product->save();
|
|
|
|
|
|
+ // Belt-and-braces: link the attribute terms to the freshly-saved
|
|
|
+ // product. Modern WC CRUD typically does this on save() when
|
|
|
+ // set_options() receives term IDs, but the link is cheap and
|
|
|
+ // makes the import robust against WC internals changes.
|
|
|
+ if (!empty($term_ids_for_link) && $taxonomy_for_link !== '' && $saved_id) {
|
|
|
+ wp_set_object_terms($saved_id, $term_ids_for_link, $taxonomy_for_link, false);
|
|
|
+ }
|
|
|
+
|
|
|
$message = $product_id == 0 ?
|
|
|
sprintf(__('Created variable product: %s', 'studiou-wc-product-cat-manage'), $product->get_name()) :
|
|
|
sprintf(__('Updated variable product: %s', 'studiou-wc-product-cat-manage'), $product->get_name());
|
|
|
@@ -495,16 +565,44 @@ class Studiou_WC_Product_Manage_Product_Import {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // Set variation attributes
|
|
|
+ // v1.6.3 — Variation attribute (taxonomy vs. custom).
|
|
|
+ //
|
|
|
+ // Pre-1.6.3 stored the raw value (e.g. "Red") under the taxonomy
|
|
|
+ // meta key (e.g. attribute_pa_color). WC matches variations by
|
|
|
+ // term slug ("red"), so the variation was unreachable on the
|
|
|
+ // storefront. Now: for taxonomy attributes resolve the value to
|
|
|
+ // its term slug; for custom attributes store the literal value
|
|
|
+ // under attribute_<sanitized name>.
|
|
|
if (isset($data['Název 1 vlastnosti']) && !empty($data['Název 1 vlastnosti']) &&
|
|
|
isset($data['Hodnota(y) 1 vlastnosti']) && !empty($data['Hodnota(y) 1 vlastnosti'])) {
|
|
|
|
|
|
- $attribute_name = wc_attribute_taxonomy_name($data['Název 1 vlastnosti']);
|
|
|
- $attribute_value = $data['Hodnota(y) 1 vlastnosti'];
|
|
|
-
|
|
|
- $variation->set_attributes(array(
|
|
|
- $attribute_name => $attribute_value
|
|
|
- ));
|
|
|
+ $attribute_name = trim($data['Název 1 vlastnosti']);
|
|
|
+ $attribute_value = trim($data['Hodnota(y) 1 vlastnosti']);
|
|
|
+ $is_global = isset($data['Vlastnost 1 globální']) && $data['Vlastnost 1 globální'] === '1';
|
|
|
+
|
|
|
+ if ($is_global) {
|
|
|
+ $taxonomy = wc_attribute_taxonomy_name($attribute_name);
|
|
|
+ $term = get_term_by('name', $attribute_value, $taxonomy);
|
|
|
+ if (!$term) {
|
|
|
+ // The variation row may arrive before its parent's
|
|
|
+ // taxonomy terms exist (rare but possible on hand-built
|
|
|
+ // CSVs). Create it so the variation is selectable.
|
|
|
+ if (!taxonomy_exists($taxonomy)) {
|
|
|
+ $this->db->create_attribute_if_not_exists($attribute_name);
|
|
|
+ register_taxonomy($taxonomy, 'product');
|
|
|
+ }
|
|
|
+ $inserted = wp_insert_term($attribute_value, $taxonomy);
|
|
|
+ if (!is_wp_error($inserted)) {
|
|
|
+ $term = get_term($inserted['term_id'], $taxonomy);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ $slug = ($term && !is_wp_error($term)) ? $term->slug : sanitize_title($attribute_value);
|
|
|
+ $variation->set_attributes(array($taxonomy => $slug));
|
|
|
+ } else {
|
|
|
+ $variation->set_attributes(array(
|
|
|
+ sanitize_title($attribute_name) => $attribute_value,
|
|
|
+ ));
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
// Handle minimum/maximum quantity
|