set_name($data['name'] ?? ''); $product->set_sku($data['sku']); $product->set_regular_price($data['price'] ?? 0); $product->set_stock_quantity($data['stock'] ?? 0); $product->set_manage_stock(true); if (!empty($data['description'])) { $product->set_description(wp_kses_post($data['description'])); } if (!empty($data['short_description'])) { $product->set_short_description(wp_kses_post($data['short_description'])); } return $product->save(); } protected static function attach_images(int $product_id, array $urls) { require_once ABSPATH . 'wp-admin/includes/file.php'; require_once ABSPATH . 'wp-admin/includes/media.php'; require_once ABSPATH . 'wp-admin/includes/image.php'; $gallery_ids = []; foreach ($urls as $index => $url) { if (!filter_var($url, FILTER_VALIDATE_URL)) { continue; } $attachment_id = media_sideload_image($url, $product_id, null, 'id'); if (is_wp_error($attachment_id)) { continue; } if ($index === 0) { set_post_thumbnail($product_id, $attachment_id); } else { $gallery_ids[] = $attachment_id; } } if ($gallery_ids) { update_post_meta( $product_id, '_product_image_gallery', implode(',', $gallery_ids) ); } } public static function upsert_from_api(array $data) { if (empty($data['sku'])) return; $product_id = self::upsert($data); if (!$product_id) return; if (!empty($data['brand'])) { self::sync_brand($product_id, $data['brand']); } if (!empty($data['categories'])) { self::sync_categories($product_id, $data['categories']); } if (!empty($data['images'])) { self::sync_images($product_id, $data['images']); } return $product_id; } protected static function sync_categories(int $product_id, array $categories) { if (empty($categories)) return; $term_ids = []; foreach ($categories as $cat_id) { // chỉ nhận số if (is_numeric($cat_id)) { $term_ids[] = (int) $cat_id; } } if (!$term_ids) return; // gán trực tiếp, KHÔNG tạo mới wp_set_object_terms( $product_id, array_unique($term_ids), 'product_cat' ); } protected static function sync_images(int $product_id, array $images) { if (empty($images)) return; $urls = array_filter(array_map('trim', $images)); if (!$urls) return; self::attach_images($product_id, $urls); } protected static function sync_brand(int $product_id, string $brand) { $brand = trim($brand); if (!$brand) return; $taxonomy = 'product_brand'; // Kiểm tra taxonomy tồn tại if (!taxonomy_exists($taxonomy)) { return; } // Check brand đã tồn tại chưa $term = term_exists($brand, $taxonomy); // Chưa có → tạo mới if (!$term) { $term = wp_insert_term($brand, $taxonomy); } if (is_wp_error($term)) { return; } $term_id = (int) $term['term_id']; // Gán brand cho product wp_set_object_terms($product_id, [$term_id], $taxonomy); // Đảm bảo attribute xuất hiện trong product $product = wc_get_product($product_id); if (!$product) return; $attributes = $product->get_attributes(); if (!isset($attributes[$taxonomy])) { $attr = new WC_Product_Attribute(); $attr->set_name($taxonomy); $attr->set_options([$brand]); $attr->set_visible(true); $attr->set_variation(false); $attributes[$taxonomy] = $attr; $product->set_attributes($attributes); $product->save(); } } protected static function create_wp_categories_from_tree( array $categories, int $parent_id = 0, string $taxonomy = 'category' ) { foreach ($categories as $item) { if (empty($item['name']) || empty($item['id'])) { continue; } $name = $item['name']; $slug = sanitize_title($name); $description = (string) $item['id']; // 👈 external ID // Check if term exists under same parent $existing = term_exists($slug, $taxonomy, $parent_id); if ($existing) { $term_id = is_array($existing) ? $existing['term_id'] : $existing; // Update description if changed wp_update_term($term_id, $taxonomy, [ 'description' => $description, ]); } else { $result = wp_insert_term($name, $taxonomy, [ 'slug' => $slug, 'parent' => $parent_id, 'description' => $description, ]); if (is_wp_error($result)) { error_log('[CATEGORY_SYNC] ' . $result->get_error_message()); continue; } $term_id = $result['term_id']; } // Recurse children if (!empty($item['children']) && is_array($item['children'])) { self::create_wp_categories_from_tree( $item['children'], $term_id, $taxonomy ); } } } }