文章目录[隐藏]
实操指南:创建商品批量导入接口的6个高效步骤
引言:为什么需要商品批量导入接口
在电子商务网站运营中,商品管理是核心工作之一。对于拥有成百上千个商品的WordPress WooCommerce商店,手动逐个添加或更新商品不仅耗时耗力,而且容易出错。商品批量导入接口能够显著提高运营效率,实现数据同步自动化,特别适合以下场景:
- 从供应商系统同步最新商品信息
- 季节性商品批量上架
- 价格策略调整需要批量更新
- 多平台商品数据同步
- 库存管理系统集成
本文将基于WordPress开源系统,详细讲解创建商品批量导入接口的六个高效步骤,帮助行业新人和程序员快速掌握这一实用技能。
第一步:环境准备与需求分析
1.1 开发环境搭建
在开始开发之前,确保你的开发环境已准备就绪:
// 检查WordPress和WooCommerce版本
add_action('admin_init', function() {
if (!class_exists('WooCommerce')) {
add_action('admin_notices', function() {
echo '<div class="notice notice-error"><p>WooCommerce插件未激活,商品导入功能需要WooCommerce支持。</p></div>';
});
}
// 检查PHP版本
if (version_compare(PHP_VERSION, '7.4.0') < 0) {
echo '<div class="notice notice-warning"><p>推荐使用PHP 7.4或更高版本以获得最佳性能。</p></div>';
}
});
1.2 明确接口需求
在编码之前,明确接口需要支持的功能:
- 数据格式支持:CSV、JSON、XML
- 商品字段映射:标题、描述、价格、库存、分类、属性等
- 导入模式:新增、更新、新增或更新
- 错误处理:数据验证、错误日志、部分成功处理
- 性能优化:批量处理、内存管理、超时处理
- 安全机制:身份验证、数据验证、防注入攻击
1.3 创建插件基础结构
/*
Plugin Name: WooCommerce批量商品导入接口
Plugin URI: https://yourwebsite.com/
Description: 为WooCommerce提供高效的商品批量导入功能
Version: 1.0.0
Author: 你的名字
License: GPL v2 or later
Text Domain: wc-bulk-import
*/
// 防止直接访问
if (!defined('ABSPATH')) {
exit;
}
// 定义插件常量
define('WC_BULK_IMPORT_VERSION', '1.0.0');
define('WC_BULK_IMPORT_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('WC_BULK_IMPORT_PLUGIN_URL', plugin_dir_url(__FILE__));
第二步:设计REST API接口
2.1 注册自定义REST API路由
WordPress提供了完善的REST API框架,我们可以利用它创建安全的导入接口:
class WC_Bulk_Import_API {
private $namespace = 'wc-bulk-import/v1';
public function __construct() {
add_action('rest_api_init', [$this, 'register_routes']);
}
public function register_routes() {
// 商品批量导入接口
register_rest_route($this->namespace, '/import/products', [
[
'methods' => WP_REST_Server::CREATABLE,
'callback' => [$this, 'import_products'],
'permission_callback' => [$this, 'check_permissions'],
'args' => $this->get_import_args(),
],
]);
// 导入状态查询接口
register_rest_route($this->namespace, '/import/status/(?P<id>[a-f0-9-]+)', [
[
'methods' => WP_REST_Server::READABLE,
'callback' => [$this, 'get_import_status'],
'permission_callback' => [$this, 'check_permissions'],
],
]);
}
private function get_import_args() {
return [
'data' => [
'required' => true,
'description' => '商品数据,支持JSON格式',
'type' => 'string',
'validate_callback' => function($param) {
json_decode($param);
return json_last_error() === JSON_ERROR_NONE;
}
],
'import_mode' => [
'required' => false,
'default' => 'create_or_update',
'description' => '导入模式:create, update, create_or_update',
'type' => 'string',
'enum' => ['create', 'update', 'create_or_update'],
],
'batch_size' => [
'required' => false,
'default' => 50,
'description' => '每批处理数量',
'type' => 'integer',
'minimum' => 1,
'maximum' => 200,
],
];
}
}
2.2 实现权限验证
安全是API设计的首要考虑因素:
public function check_permissions(WP_REST_Request $request) {
// 方法1:使用WordPress非ce验证
$nonce = $request->get_header('X-WP-Nonce');
if ($nonce && wp_verify_nonce($nonce, 'wp_rest')) {
return current_user_can('manage_woocommerce');
}
// 方法2:使用API密钥验证(适合系统间调用)
$api_key = $request->get_header('X-API-Key');
if ($api_key) {
return $this->validate_api_key($api_key);
}
// 方法3:JWT令牌验证
$auth_header = $request->get_header('Authorization');
if ($auth_header && preg_match('/Bearers+(.+)/', $auth_header, $matches)) {
return $this->validate_jwt_token($matches[1]);
}
return false;
}
private function validate_api_key($api_key) {
$valid_keys = get_option('wc_bulk_import_api_keys', []);
// 使用哈希比较防止时序攻击
foreach ($valid_keys as $key_data) {
if (hash_equals($key_data['hash'], hash('sha256', $api_key))) {
// 检查密钥是否过期
if (isset($key_data['expires']) && $key_data['expires'] < time()) {
return false;
}
return true;
}
}
return false;
}
第三步:设计数据处理器
3.1 创建数据验证器
class WC_Product_Data_Validator {
private $errors = [];
private $warnings = [];
public function validate_product_data($product_data, $import_mode = 'create_or_update') {
$this->errors = [];
$this->warnings = [];
// 基本字段验证
$this->validate_required_fields($product_data, $import_mode);
// 数据类型验证
$this->validate_data_types($product_data);
// 业务逻辑验证
$this->validate_business_rules($product_data);
return [
'is_valid' => empty($this->errors),
'errors' => $this->errors,
'warnings' => $this->warnings,
];
}
private function validate_required_fields($data, $import_mode) {
$required_fields = ['name', 'type', 'regular_price'];
// 更新模式不需要所有必填字段
if ($import_mode === 'update') {
$required_fields = ['id']; // 更新只需要ID
}
foreach ($required_fields as $field) {
if (empty($data[$field])) {
$this->errors[] = sprintf('必填字段 "%s" 为空', $field);
}
}
// 简单商品需要价格
if (isset($data['type']) && $data['type'] === 'simple' && empty($data['regular_price'])) {
$this->errors[] = '简单商品必须设置价格';
}
}
private function validate_data_types($data) {
// 验证价格
if (isset($data['regular_price']) && !is_numeric($data['regular_price'])) {
$this->errors[] = '价格必须是数字';
}
// 验证库存
if (isset($data['stock_quantity']) && !is_int($data['stock_quantity'])) {
$this->errors[] = '库存必须是整数';
}
// 验证SKU唯一性(仅创建时)
if (isset($data['sku']) && $data['sku']) {
$existing_id = wc_get_product_id_by_sku($data['sku']);
if ($existing_id && (!isset($data['id']) || $existing_id != $data['id'])) {
$this->errors[] = sprintf('SKU "%s" 已存在', $data['sku']);
}
}
}
private function validate_business_rules($data) {
// 价格不能为负数
if (isset($data['regular_price']) && $data['regular_price'] < 0) {
$this->errors[] = '价格不能为负数';
}
// 促销价不能高于原价
if (isset($data['sale_price'], $data['regular_price']) &&
$data['sale_price'] >= $data['regular_price']) {
$this->warnings[] = '促销价不应高于或等于原价';
}
}
}
3.2 实现批量处理引擎
class WC_Batch_Product_Processor {
private $batch_size = 50;
private $import_mode = 'create_or_update';
private $results = [];
private $current_batch = 0;
public function __construct($batch_size = 50, $import_mode = 'create_or_update') {
$this->batch_size = max(1, min(200, $batch_size));
$this->import_mode = $import_mode;
}
public function process_batch($products_data) {
$total_products = count($products_data);
$batches = array_chunk($products_data, $this->batch_size);
$this->results = [
'total' => $total_products,
'processed' => 0,
'succeeded' => 0,
'failed' => 0,
'skipped' => 0,
'details' => [],
];
foreach ($batches as $batch_index => $batch) {
$this->current_batch = $batch_index + 1;
$this->process_single_batch($batch);
// 每批处理后清理内存
$this->cleanup_memory();
// 添加延迟防止服务器过载
if ($batch_index < count($batches) - 1) {
usleep(100000); // 0.1秒延迟
}
}
return $this->results;
}
private function process_single_batch($batch) {
$validator = new WC_Product_Data_Validator();
foreach ($batch as $index => $product_data) {
$product_number = $this->results['processed'] + 1;
// 验证数据
$validation_result = $validator->validate_product_data($product_data, $this->import_mode);
if (!$validation_result['is_valid']) {
$this->results['failed']++;
$this->results['details'][] = [
'index' => $product_number,
'status' => 'failed',
'errors' => $validation_result['errors'],
'data' => $product_data,
];
$this->results['processed']++;
continue;
}
// 处理商品
try {
$result = $this->process_single_product($product_data);
if ($result['status'] === 'success') {
$this->results['succeeded']++;
} elseif ($result['status'] === 'skipped') {
$this->results['skipped']++;
} else {
$this->results['failed']++;
}
$this->results['details'][] = array_merge(
['index' => $product_number],
$result
);
} catch (Exception $e) {
$this->results['failed']++;
$this->results['details'][] = [
'index' => $product_number,
'status' => 'failed',
'errors' => [$e->getMessage()],
'data' => $product_data,
];
}
$this->results['processed']++;
}
}
private function process_single_product($product_data) {
$product_id = 0;
// 根据导入模式确定操作
if ($this->import_mode === 'create' ||
($this->import_mode === 'create_or_update' && empty($product_data['id']))) {
// 创建新商品
$product_id = $this->create_product($product_data);
$action = 'created';
} else {
// 更新现有商品
$product_id = $this->update_product($product_data);
$action = 'updated';
}
if (is_wp_error($product_id)) {
return [
'status' => 'failed',
'errors' => [$product_id->get_error_message()],
'product_id' => 0,
];
}
if (!$product_id) {
return [
'status' => 'skipped',
'message' => '商品未创建或更新',
'product_id' => 0,
];
}
return [
'status' => 'success',
'message' => sprintf('商品%s成功', $action),
'product_id' => $product_id,
'action' => $action,
];
}
private function create_product($data) {
$product = new WC_Product();
// 设置基本属性
$this->set_product_properties($product, $data);
// 保存商品
return $product->save();
}
private function update_product($data) {
$product_id = $data['id'];
$product = wc_get_product($product_id);
if (!$product) {
return new WP_Error('product_not_found', sprintf('商品ID %s 不存在', $product_id));
}
// 更新商品属性
$this->set_product_properties($product, $data);
// 保存更改
return $product->save();
}
private function set_product_properties($product, $data) {
// 设置基本字段
$field_mapping = [
'name' => 'set_name',
'description' => 'set_description',
'short_description' => 'set_short_description',
'regular_price' => 'set_regular_price',
'sale_price' => 'set_sale_price',
'sku' => 'set_sku',
'manage_stock' => 'set_manage_stock',
'stock_quantity' => 'set_stock_quantity',
'stock_status' => 'set_stock_status',
'weight' => 'set_weight',
'length' => 'set_length',
'width' => 'set_width',
'height' => 'set_height',
];
foreach ($field_mapping as $data_key => $method) {
if (isset($data[$data_key])) {
$product->$method($data[$data_key]);
}
}
// 设置商品类型
if (isset($data['type'])) {
$product->set_product_type($data['type']);
}
// 设置分类
if (isset($data['categories']) && is_array($data['categories'])) {
$this->set_product_categories($product, $data['categories']);
}
// 设置标签
if (isset($data['tags']) && is_array($data['tags'])) {
$this->set_product_tags($product, $data['tags']);
}
// 设置属性
if (isset($data['attributes']) && is_array($data['attributes'])) {
$this->set_product_attributes($product, $data['attributes']);
}
// 设置图片
if (isset($data['images']) && is_array($data['images'])) {
$this->set_product_images($product, $data['images']);
}
}
private function cleanup_memory() {
// 清理WordPress对象缓存
wp_cache_flush();
// 强制垃圾回收
if (function_exists('gc_collect_cycles')) {
gc_collect_cycles();
}
}
}
第四步:实现异步处理与队列系统
4.1 创建后台任务处理器
对于大量商品导入,使用异步处理可以避免HTTP超时:
class WC_Async_Import_Processor {
private static $instance = null;
private $background_process = null;
public static function get_instance() {
if (is_null(self::$instance)) {
self::$instance = new self();
}
return self::$instance;
}
private function __construct() {
// 使用Action Scheduler或WP Background Processing库
if (class_exists('WP_Background_Process')) {
require_once WC_BULK_IMPORT_PLUGIN_DIR . 'includes/class-wc-import-background-process.php';
$this->background_process = new WC_Import_Background_Process();
}
add_action('wc_bulk_import_process_queue', [$this, 'process_queue'], 10, 2);
}
public function dispatch_import($data, $import_mode = 'create_or_update') {
$import_id = wp_generate_uuid4();
// 存储导入任务数据
$task_data = [
'import_id' => $import_id,
data' => $data,
'import_mode' => $import_mode,
'status' => 'pending',
'created_at' => current_time('mysql'),
'total_items' => count($data),
'processed' => 0,
'succeeded' => 0,
'failed' => 0,
];
// 保存到选项表或自定义表
$this->save_import_task($task_data);
// 如果支持后台处理
if ($this->background_process) {
// 分批添加到队列
$batches = array_chunk($data, 50);
foreach ($batches as $batch) {
$this->background_process->push_to_queue([
'import_id' => $import_id,
'batch_data' => $batch,
'import_mode' => $import_mode,
]);
}
$this->background_process->save()->dispatch();
} else {
// 使用WordPress计划任务
wp_schedule_single_event(time() + 1, 'wc_bulk_import_process_queue', [$import_id, $import_mode]);
}
return $import_id;
}
public function process_queue($import_id, $import_mode) {
$task = $this->get_import_task($import_id);
if (!$task || $task['status'] === 'completed') {
return;
}
// 更新状态为处理中
$task['status'] = 'processing';
$task['started_at'] = current_time('mysql');
$this->save_import_task($task);
// 处理数据
$processor = new WC_Batch_Product_Processor(50, $import_mode);
$results = $processor->process_batch($task['data']);
// 更新任务状态
$task['status'] = 'completed';
$task['completed_at'] = current_time('mysql');
$task['processed'] = $results['processed'];
$task['succeeded'] = $results['succeeded'];
$task['failed'] = $results['failed'];
$task['results'] = $results['details'];
$this->save_import_task($task);
// 发送完成通知
$this->send_completion_notification($task);
}
private function save_import_task($task_data) {
$tasks = get_option('wc_bulk_import_tasks', []);
$tasks[$task_data['import_id']] = $task_data;
update_option('wc_bulk_import_tasks', $tasks, false);
}
private function get_import_task($import_id) {
$tasks = get_option('wc_bulk_import_tasks', []);
return $tasks[$import_id] ?? null;
}
private function send_completion_notification($task) {
$admin_email = get_option('admin_email');
$subject = sprintf('商品批量导入完成 - %s', get_bloginfo('name'));
$message = sprintf(
"商品批量导入任务已完成!nn" .
"任务ID: %sn" .
"总商品数: %dn" .
"成功: %dn" .
"失败: %dn" .
"开始时间: %sn" .
"完成时间: %snn" .
"查看详情: %s",
$task['import_id'],
$task['total_items'],
$task['succeeded'],
$task['failed'],
$task['started_at'],
$task['completed_at'],
admin_url('admin.php?page=wc-bulk-import&task=' . $task['import_id'])
);
wp_mail($admin_email, $subject, $message);
}
}
### 4.2 实现状态查询接口
public function get_import_status(WP_REST_Request $request) {
$import_id = $request->get_param('id');
if (!$import_id) {
return new WP_Error('missing_id', '缺少导入任务ID', ['status' => 400]);
}
$async_processor = WC_Async_Import_Processor::get_instance();
$task = $async_processor->get_import_task($import_id);
if (!$task) {
return new WP_Error('task_not_found', '导入任务不存在', ['status' => 404]);
}
// 计算进度百分比
$progress = 0;
if ($task['total_items'] > 0) {
$progress = min(100, round(($task['processed'] / $task['total_items']) * 100, 2));
}
$response_data = [
'import_id' => $task['import_id'],
'status' => $task['status'],
'progress' => $progress,
'total_items' => $task['total_items'],
'processed' => $task['processed'],
'succeeded' => $task['succeeded'],
'failed' => $task['failed'],
'created_at' => $task['created_at'],
'started_at' => $task['started_at'] ?? null,
'completed_at' => $task['completed_at'] ?? null,
];
// 如果任务完成,包含详细结果
if ($task['status'] === 'completed' && isset($task['results'])) {
$response_data['results'] = array_slice($task['results'], 0, 50); // 只返回前50条结果
$response_data['has_more'] = count($task['results']) > 50;
}
return rest_ensure_response($response_data);
}
## 第五步:实现完整的导入接口
### 5.1 完善主导入方法
public function import_products(WP_REST_Request $request) {
// 解析请求数据
$data = json_decode($request->get_param('data'), true);
$import_mode = $request->get_param('import_mode');
$batch_size = $request->get_param('batch_size');
if (!is_array($data) || empty($data)) {
return new WP_Error('invalid_data', '商品数据格式错误或为空', ['status' => 400]);
}
// 验证数据量
$total_items = count($data);
if ($total_items > 10000) {
return new WP_Error('too_many_items', '单次导入商品数量不能超过10000个', ['status' => 400]);
}
// 记录开始时间
$start_time = microtime(true);
// 根据数据量选择处理方式
if ($total_items <= 100) {
// 小批量数据同步处理
$processor = new WC_Batch_Product_Processor($batch_size, $import_mode);
$results = $processor->process_batch($data);
$execution_time = round(microtime(true) - $start_time, 2);
$response = [
'status' => 'completed',
'message' => '商品导入完成',
'total_items' => $total_items,
'succeeded' => $results['succeeded'],
'failed' => $results['failed'],
'skipped' => $results['skipped'],
'execution_time' => $execution_time,
'details' => array_slice($results['details'], 0, 20), // 只返回前20条详情
];
} else {
// 大批量数据异步处理
$async_processor = WC_Async_Import_Processor::get_instance();
$import_id = $async_processor->dispatch_import($data, $import_mode);
$response = [
'status' => 'processing',
'message' => '商品导入任务已开始后台处理',
'import_id' => $import_id,
'total_items' => $total_items,
'check_status_url' => rest_url($this->namespace . '/import/status/' . $import_id),
];
}
// 记录导入日志
$this->log_import_activity($request, $response);
return rest_ensure_response($response);
}
private function log_import_activity($request, $response) {
$log_entry = [
'timestamp' => current_time('mysql'),
'user_id' => get_current_user_id(),
'user_agent' => $request->get_header('User-Agent'),
'ip_address' => $this->get_client_ip(),
'total_items' => $response['total_items'] ?? 0,
'succeeded' => $response['succeeded'] ?? 0,
'failed' => $response['failed'] ?? 0,
'status' => $response['status'],
'import_id' => $response['import_id'] ?? null,
];
$logs = get_option('wc_bulk_import_logs', []);
array_unshift($logs, $log_entry);
// 只保留最近1000条日志
if (count($logs) > 1000) {
$logs = array_slice($logs, 0, 1000);
}
update_option('wc_bulk_import_logs', $logs, false);
}
private function get_client_ip() {
$ip_keys = [
'HTTP_CLIENT_IP',
'HTTP_X_FORWARDED_FOR',
'HTTP_X_FORWARDED',
'HTTP_X_CLUSTER_CLIENT_IP',
'HTTP_FORWARDED_FOR',
'HTTP_FORWARDED',
'REMOTE_ADDR',
];
foreach ($ip_keys as $key) {
if (isset($_SERVER[$key]) && !empty($_SERVER[$key])) {
$ip_list = explode(',', $_SERVER[$key]);
foreach ($ip_list as $ip) {
$ip = trim($ip);
if (filter_var($ip, FILTER_VALIDATE_IP)) {
return $ip;
}
}
}
}
return '0.0.0.0';
}
### 5.2 添加分类和属性处理方法
private function set_product_categories($product, $categories) {
$category_ids = [];
foreach ($categories as $category) {
if (is_numeric($category)) {
// 已经是分类ID
if (term_exists($category, 'product_cat')) {
$category_ids[] = (int)$category;
}
} else {
// 分类名称或路径
$category_data = $this->find_or_create_category($category);
if ($category_data) {
$category_ids[] = $category_data['id'];
}
}
}
if (!empty($category_ids)) {
$product->set_category_ids($category_ids);
}
}
private function find_or_create_category($category_path) {
// 支持层级分类,如 "服装/男装/衬衫"
$categories = explode('/', $category_path);
$parent_id = 0;
foreach ($categories as $category_name) {
$category_name = trim($category_name);
if (empty($category_name)) {
continue;
}
// 检查分类是否存在
$term = term_exists($category_name, 'product_cat', $parent_id);
if (!$term) {
// 创建新分类
$term = wp_insert_term(
$category_name,
'product_cat',
['parent' => $parent_id]
);
if (is_wp_error($term)) {
error_log('创建分类失败: ' . $term->get_error_message());
return null;
}
}
$parent_id = is_array($term) ? $term['term_id'] : $term;
}
return ['id' => $parent_id, 'name' => end($categories)];
}
private function set_product_attributes($product, $attributes) {
$product_attributes = [];
foreach ($attributes as $attribute) {
if (empty($attribute['name']) || empty($attribute['options'])) {
continue;
}
$attribute_name = sanitize_title($attribute['name']);
$attribute_label = sanitize_text_field($attribute['name']);
// 检查是否为预定义属性
$attribute_id = wc_attribute_taxonomy_id_by_name($attribute_name);
if ($attribute_id) {
// 使用预定义属性
$taxonomy_name = wc_attribute_taxonomy_name($attribute_name);
$term_ids = [];
foreach ((array)$attribute['options'] as $option) {
$term = term_exists($option, $taxonomy_name);
if (!$term) {
$term = wp_insert_term($option, $taxonomy_name);
}
if (!is_wp_error($term)) {
$term_id = is_array($term) ? $term['term_id'] : $term;
$term_ids[] = $term_id;
}
}
$product_attributes[$taxonomy_name] = [
'name' => $taxonomy_name,
'value' => implode(' | ', $attribute['options']),
'position' => $attribute['position'] ?? 0,
'is_visible' => $attribute['visible'] ?? true,
'is_variation' => $attribute['variation'] ?? false,
'is_taxonomy' => true,
];
$product->set_attributes($product_attributes);
wp_set_object_terms($product->get_id(), $term_ids, $taxonomy_name);
} else {
// 使用自定义属性
$product_attributes[$attribute_name] = [
'name' => $attribute_label,
'value' => implode(' | ', (array)$attribute['options']),
'position' => $attribute['position'] ?? 0,
'is_visible' => $attribute['visible'] ?? true,
'is_variation' => $attribute['variation'] ?? false,
'is_taxonomy' => false,
];
}
}
if (!empty($product_attributes)) {
$product->set_attributes($product_attributes);
}
}
private function set_product_images($product, $images) {
$image_ids = [];
foreach ($images as $index => $image) {
if (empty($image['src'])) {
continue;
}
$image_id = $this->upload_image_from_url($image['src']);
if ($image_id && !is_wp_error($image_id)) {
if ($index === 0) {
// 第一张图设为主图
$product->set_image_id($image_id);
} else {
// 其他图为图库
$image_ids[] = $image_id;
}
}
}
if (!empty($image_ids)) {
$product->set_gallery_image_ids($image_ids);
}
}
private function upload_image_from_url($image_url) {
// 检查URL是否有效
if (!filter_var($image_url, FILTER_VALIDATE_URL)) {
return new WP_Error('invalid_url', '图片URL无效');
}
// 检查是否已存在相同图片
$existing_id = $this->find_existing_attachment($image_url);
if ($existing_id) {
return $existing_id;
}
// 下载图片
$tmp_file = download_url($image_url, 300);
if (is_wp_error($tmp_file)) {
return $tmp_file;
}
// 准备文件数据
$file_array = [
'name' => basename($image_url),
'tmp_name' => $tmp_file,
];
// 上传到媒体库
$attachment_id = media_handle_sideload($file_array, 0);
// 清理临时文件
@unlink($tmp_file);
if (is_wp_error($attachment_id)) {
return $attachment_id;
}
// 保存原始URL到附件元数据
update_post_meta($attachment_id, '_wc_import_image_url', $image_url);
return $attachment_id;
}
private function find_existing_attachment($image_url) {
global $wpdb;
$query = $wpdb->prepare(
"SELECT post_id FROM $wpdb->postmeta WHERE meta_key = '_wc_import_image_url' AND meta_value = %s LIMIT 1",
$image_url
);
$attachment_id = $wpdb->get_var($query);
return $attachment_id ? (int)$attachment_id : null;
}
## 第六步:创建管理界面与优化
### 6.1 添加管理页面
class WC_Bulk_Import_Admin {
public function __construct() {
add_action('admin_menu', [$this, 'add_admin_menu']);
add_action('admin_enqueue_scripts', [$this, 'enqueue_admin_scripts']);
add_action('wp_ajax_wc_bulk_import_upload', [$this, 'handle_file_upload']);
add_action('wp_ajax_wc_bulk_import_preview', [$this, 'handle_preview_request']);
}
public function add_admin_menu() {
add_submenu_page(
'woocommerce',
'批量商品导入',
'批量导入',
'manage_woocommerce',
'wc-bulk-import',
[$this, 'render_admin_page']
);
}
public function render_admin_page() {
?>
<div class="wrap wc-bulk-import">
<h1><?php echo esc_html__('批量商品导入', 'wc-bulk-import'); ?></h1>
<div class="notice notice-info">
<p><?php echo esc_html__('支持CSV、JSON格式文件导入,最大文件大小:', 'wc-bulk-import'); ?> <?php echo size_format(wp_max_upload_size()); ?></p>
</div>
<div class="import-container">
<div class="import-section">
<h2><?php echo esc_html__('第一步:上传文件', 'wc-bulk-import'); ?></h
