You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WooCommerce:实现虚拟可下载产品动态差异化文件交付的技术问询

解决WooCommerce分发唯一数字码(如Steam码)的方案

这个问题我之前帮客户解决过——WooCommerce默认的可下载产品机制确实只能绑定固定文件,没法直接给每个订单分发唯一的数字码文件。下面给你几个实用的解决方案,从无代码到定制开发都覆盖:

方案1:用专门的数字码管理插件(无代码入门首选)

如果你不想写代码,直接找一款WooCommerce数字密钥/序列号管理插件就行,这类工具专门解决这个场景:

  • 支持批量导入预生成的唯一码(比如Steam码),存储在插件的码库中
  • 订单付款完成后,自动从码库中分配一个未使用的码,标记为已用
  • 可以自动生成包含该码的PDF下载链接,直接添加到订单页面或发送到客户邮箱
  • 还能同步产品库存(码库耗尽时自动下架产品)

这类插件的逻辑都是现成的,不用自己折腾,适合新手或者快速上线的场景。

方案2:自定义代码实现(适合需要高度定制的场景)

如果你有开发能力,完全可以自己写代码实现,核心逻辑是预存码库→订单完成时分配唯一码→生成带码的PDF→添加到订单下载项。

步骤1:给产品添加自定义字段存储可用码库

先在产品编辑页面加一个输入框,让商家批量输入所有可用的数字码(每行一个):

// 添加产品元框用于存储Steam码库
add_action('add_meta_boxes', 'add_steam_keys_meta_box');
function add_steam_keys_meta_box() {
    add_meta_box(
        'steam_keys_box',
        'Steam 数字码库',
        'render_steam_keys_meta_box',
        'product',
        'normal',
        'high'
    );
}

// 渲染元框内容
function render_steam_keys_meta_box($post) {
    $available_keys = get_post_meta($post->ID, '_steam_available_keys', true);
    wp_nonce_field('save_steam_keys_nonce', 'steam_keys_nonce');
    echo '<textarea name="steam_available_keys" rows="12" style="width:100%;">' . esc_textarea($available_keys) . '</textarea>';
    echo '<p style="margin-top:10px; color:#666;">请每行输入一个唯一的Steam码,系统会自动为订单分配未使用的码</p>';
}

// 保存码库到产品元数据
add_action('save_post_product', 'save_steam_keys_meta_data');
function save_steam_keys_meta_data($post_id) {
    // 验证权限和非ce
    if (!isset($_POST['steam_keys_nonce']) || !wp_verify_nonce($_POST['steam_keys_nonce'], 'save_steam_keys_nonce')) return;
    if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;
    if (!current_user_can('edit_product', $post_id)) return;

    // 保存码库
    if (isset($_POST['steam_available_keys'])) {
        update_post_meta($post_id, '_steam_available_keys', sanitize_textarea_field($_POST['steam_available_keys']));
    }
}

步骤2:订单完成时分配码并生成PDF

当订单状态变为「已完成」时,自动分配码、生成带码的PDF,并把PDF添加为订单的可下载项:

// 订单完成时分配Steam码并生成下载PDF
add_action('woocommerce_order_status_completed', 'assign_steam_key_and_generate_pdf', 10, 1);
function assign_steam_key_and_generate_pdf($order_id) {
    $order = wc_get_order($order_id);
    if (!$order) return;

    foreach ($order->get_items() as $item) {
        $product_id = $item->get_product_id();
        $available_keys = get_post_meta($product_id, '_steam_available_keys', true);
        
        // 检查码库是否为空
        if (empty($available_keys)) {
            wc_add_notice('该产品的数字码已耗尽,请补充库存', 'error');
            return;
        }

        // 拆分码库为数组,取出第一个可用码
        $keys_array = array_filter(explode("\n", trim($available_keys)));
        $assigned_key = array_shift($keys_array);
        // 更新剩余码库
        update_post_meta($product_id, '_steam_available_keys', implode("\n", $keys_array));
        // 把分配的码保存到订单元数据
        update_post_meta($order_id, '_assigned_steam_key', $assigned_key);

        // 生成带码的PDF(这里用TCPDF为例,需先安装TCPDF库到wp-content/plugins/)
        require_once(ABSPATH . 'wp-content/plugins/tcpdf/tcpdf.php');
        $pdf = new TCPDF();
        $pdf->AddPage();
        
        // 构造PDF内容
        $pdf_content = '<h1>感谢你的购买!</h1>';
        $pdf_content .= '<p>你的Steam激活码:</p>';
        $pdf_content .= '<p style="font-size:24px; font-weight:bold; color:#2c3e50; margin:20px 0;">' . esc_html($assigned_key) . '</p>';
        $pdf_content .= '<p>请在Steam客户端中输入此码激活游戏</p>';
        
        $pdf->writeHTML($pdf_content, true, false, true, false, '');

        // 保存PDF到上传目录
        $upload_dir = wp_upload_dir();
        $pdf_filename = 'steam-key-' . $order_id . '.pdf';
        $pdf_path = $upload_dir['path'] . '/' . $pdf_filename;
        $pdf->Output($pdf_path, 'F');

        // 添加PDF到订单的可下载项
        $download_url = $upload_dir['url'] . '/' . $pdf_filename;
        $item->add_download(array(
            'name' => '你的Steam激活码PDF',
            'file' => $download_url
        ));
        $item->save();
    }
    $order->save();
}

额外优化:清理过期PDF

为了避免服务器存储过多旧PDF,可以加个定时任务自动删除30天前的PDF:

// 定时删除过期的Steam码PDF
add_action('wp_scheduled_delete_steam_pdfs', 'delete_old_steam_pdfs');
function delete_old_steam_pdfs() {
    $upload_dir = wp_upload_dir();
    $files = glob($upload_dir['path'] . '/steam-key-*.pdf');
    if ($files) {
        foreach ($files as $file) {
            if (filemtime($file) < strtotime('-30 days')) {
                unlink($file);
            }
        }
    }
}
// 激活定时任务
register_activation_hook(__FILE__, 'schedule_steam_pdf_cleanup');
function schedule_steam_pdf_cleanup() {
    if (!wp_next_scheduled('wp_scheduled_delete_steam_pdfs')) {
        wp_schedule_event(time(), 'daily', 'wp_scheduled_delete_steam_pdfs');
    }
}

方案3:直接在订单邮件中发送码(替代PDF下载)

如果不需要生成PDF,也可以直接把唯一码放到订单完成邮件里,这样更简单:

// 在客户完成订单邮件中插入Steam码
add_action('woocommerce_email_order_details', 'add_steam_key_to_completion_email', 20, 4);
function add_steam_key_to_completion_email($order, $sent_to_admin, $plain_text, $email) {
    // 只在客户的完成订单邮件中显示
    if ($email->id !== 'customer_completed_order') return;
    
    $assigned_key = get_post_meta($order->get_id(), '_assigned_steam_key', true);
    if (!empty($assigned_key)) {
        if ($plain_text) {
            echo "\n\n你的Steam激活码:" . $assigned_key . "\n";
        } else {
            echo '<div style="margin:20px 0; padding:15px; background:#f8f9fa; border-radius:4px;">';
            echo '<h3 style="margin-top:0;">你的Steam激活码</h3>';
            echo '<p style="font-size:20px; font-weight:bold; color:#dc3545;">' . esc_html($assigned_key) . '</p>';
            echo '</div>';
        }
    }
}

内容的提问来源于stack exchange,提问作者Khoontay

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 12:27:47