首页 / 跨境电商轻量软件 / 实操指南:创建商品批量导入接口的6个高效步骤

实操指南:创建商品批量导入接口的6个高效步骤

实操指南:创建商品批量导入接口的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 明确接口需求

在编码之前,明确接口需要支持的功能:

  1. 数据格式支持:CSV、JSON、XML
  2. 商品字段映射:标题、描述、价格、库存、分类、属性等
  3. 导入模式:新增、更新、新增或更新
  4. 错误处理:数据验证、错误日志、部分成功处理
  5. 性能优化:批量处理、内存管理、超时处理
  6. 安全机制:身份验证、数据验证、防注入攻击

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
本文来自网络,不代表柔性供应链服务中心立场,转载请注明出处:https://mall.org.cn/240.html

EXCHANGES®作者

上一篇
下一篇

为您推荐

联系我们

联系我们

18559313275

在线咨询: QQ交谈

邮箱: vip@exchanges.center

工作时间:周一至周五,9:00-17:30,节假日休息
返回顶部