如何在 WooCommerce 订单中通过 HTML 表单上传图片作为元数据

梦辰大大_2837

梦辰大大_2837

2026-06-19

685人浏览

原创

本文详细讲解如何扩展现有 woocommerce 订单费用提交表单,支持用户上传多张凭证图片(如发票、收据),安全地保存至指定上传目录,并关联到对应订单元数据。

本文详细讲解如何扩展现有 woocommerce 订单费用提交表单,支持用户上传多张凭证图片(如发票、收据),安全地保存至指定上传目录,并关联到对应订单元数据。

在原有仅支持文本字段(订单号、金额、理由)的表单基础上,添加图像上传功能需协同改造三部分:HTML 表单结构、前端 AJAX 文件提交逻辑,以及后端安全的文件处理与存储机制。以下为完整、可直接集成的实现方案。

✅ 1. 更新 HTML 表单:支持多图上传

在原

中插入带 multiple 属性的 字段,并限定仅接受常见图片格式:
<label for="proof_images">凭证图片(支持 JPG/PNG/GIF,最多 5 张):</label>
<input type="file" id="proof_images" name="proof_images[]" accept="image/jpeg,image/png,image/gif" multiple data-max-files="5">

⚠️ 注意:name="proof_images[]" 的方括号语法是 PHP 接收多文件数组的关键;accept 属性提升用户体验,但不能替代后端校验。

html-deploy
html-deploy

使用 htmlcode.fun 将 HTML 内容或文件部署到网页,适用于用户要求“部署到网页”“托管此 HTML”“生成此前端...的实时链接”等场景。

下载

✅ 2. 前端 JavaScript:使用 FormData 提交文件

原 AJAX 请求需改用 FormData 对象封装全部字段(含文件),并禁用 processData 和 contentType —— 否则 jQuery 会错误地序列化二进制文件:

jQuery(document).ready(function($) {
    $('#expense_form').on('submit', function(e) {
        e.preventDefault();

        // 验证文件数量(客户端轻量级校验)
        const fileInput = $('#proof_images')[0];
        if (fileInput && fileInput.files.length > 5) {
            alert('最多只能上传 5 张图片!');
            return;
        }

        // 构建 FormData(自动包含所有表单字段 + 文件)
        const formData = new FormData(this);
        formData.append('action', 'update_custom_field_order_expense_php');
        formData.append('orderid', $('#exp_order_no').val());
        formData.append('expense', $('#expense_amt').val());
        formData.append('expense_reason', $('#expense_reason').val());

        $.ajax({
            url: '<?php echo admin_url("admin-ajax.php"); ?>',
            type: 'POST',
            data: formData,
            processData: false, // 必须设为 false
            contentType: false, // 必须设为 false
            beforeSend: function() {
                $('#exp_but').prop('disabled', true).val('上传中...');
            },
            success: function(response) {
                if (response.success) {
                    alert('✅ 费用及凭证已成功提交!');
                    location.reload();
                } else {
                    throw new Error(response.data?.message || '未知错误');
                }
            },
            error: function(xhr, status, err) {
                const msg = xhr.responseJSON?.data?.message || '提交失败,请检查网络或联系管理员';
                alert('❌ ' + msg);
            },
            complete: function() {
                $('#exp_but').prop('disabled', false).val('提交');
            }
        });
    });
});

✅ 3. 后端 PHP:安全存储图片并关联订单

更新 update_custom_field_order_expense_php() 函数,加入文件校验、路径创建、唯一命名与元数据绑定逻辑:

function update_custom_field_order_expense_php() {
    // 1. 基础权限与订单校验(保留原有逻辑)
    if (!is_user_logged_in()) {
        wp_die('请先登录', '', ['response' => 401]);
    }
    $current_user = wp_get_current_user();
    $order_id = absint($_POST['orderid'] ?? 0);
    $order = wc_get_order($order_id);
    if (!$order) {
        wp_die('无效订单号', '', ['response' => 400]);
    }

    $driver_id = (int) get_post_meta($order_id, 'lddfw_driverid', true);
    if ($current_user->ID !== $driver_id) {
        wp_die('无权操作此订单', '', ['response' => 403]);
    }

    // 2. 处理图片上传(新增核心逻辑)
    $uploaded_files = [];
    $allowed_types = ['image/jpeg', 'image/png', 'image/gif'];
    $max_size = 5 * 1024 * 1024; // 5MB
    $target_subdir = '2023/Expense_images';

    if (!empty($_FILES['proof_images']['name'][0])) {
        $file_count = count($_FILES['proof_images']['name']);
        for ($i = 0; $i  400]);
            }
            if ($size > $max_size) {
                wp_die("第 " . ($i+1) . " 张图片超过 5MB 限制", '', ['response' => 400]);
            }

            // 构建安全保存路径
            $upload_dir = wp_upload_dir();
            $target_dir = trailingslashit($upload_dir['basedir']) . $target_subdir;
            wp_mkdir_p($target_dir); // 自动创建目录

            $unique_filename = wp_unique_filename($target_dir, $name);
            $target_path = $target_dir . $unique_filename;

            // 移动并验证
            if (!move_uploaded_file($tmp_name, $target_path)) {
                wp_die("第 " . ($i+1) . " 张图片保存失败", '', ['response' => 500]);
            }

            // 生成可访问的 URL(用于前端展示或管理后台查看)
            $file_url = trailingslashit($upload_dir['baseurl']) . $target_subdir . '/' . $unique_filename;
            $uploaded_files[] = [
                'path' => $target_path,
                'url'  => $file_url,
                'name' => $name
            ];
        }
    }

    // 3. 保存元数据(文本 + 图片信息)
    $order->update_meta_data('Driver Expense', sanitize_text_field($_POST['expense']));
    $order->update_meta_data('Driver Expense Reason', sanitize_textarea_field($_POST['expense_reason']));

    // 存储图片 URL 列表(推荐方式:便于前端渲染)
    if (!empty($uploaded_files)) {
        $order->update_meta_data('Driver Expense Proof Images', array_map(fn($f) => $f['url'], $uploaded_files));
        // 可选:同时保存原始文件名用于审计
        $order->update_meta_data('Driver Expense Proof Filenames', array_map(fn($f) => $f['name'], $uploaded_files));
    }
    $order->save();

    wp_send_json_success([
        'message' => '费用与凭证图片已成功保存',
        'images'  => array_column($uploaded_files, 'url')
    ]);
}
add_action('wp_ajax_update_custom_field_order_expense_php', 'update_custom_field_order_expense_php');
add_action('wp_ajax_nopriv_update_custom_field_order_expense_php', 'update_custom_field_order_expense_php');

? 关键安全提醒(务必执行!)

  • 永远校验 $_FILES 的 type 和 size:浏览器 accept 可被绕过;
  • 使用 wp_unique_filename() 防止覆盖与路径遍历;
  • 调用 is_uploaded_file() 防止恶意文件伪造;
  • *对用户输入(如 $_POST['expense'])始终使用 `sanitize_` 函数过滤**;
  • 生产环境建议增加图片压缩(GD/ImageMagick)与病毒扫描(ClamAV 集成)。

? 总结

本方案将图片上传无缝集成到现有 WooCommerce 订单元数据流程中:前端用 FormData 提交,后端通过 wp_upload_dir() 安全落盘,并以结构化数组形式存入订单元数据。既满足业务对凭证存档的需求,又遵循 WordPress 最佳实践与安全规范。后续可在订单管理页或客户邮件中通过 get_post_meta($order_id, 'Driver Expense Proof Images') 渲染缩略图,实现闭环验证。

前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!

HTML速学教程(入门课程)
HTML速学教程(入门课程)

HTML怎么学习?HTML怎么入门?HTML在哪学?HTML怎么学才快?不用担心,这里为大家提供了HTML速学教程(入门课程),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

html

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
js获取数组长度的方法
js获取数组长度的方法

在js中,可以利用array对象的length属性来获取数组长度,该属性可设置或返回数组中元素的数目,只需要使用“array.length”语句即可返回表示数组对象的元素个数的数值,也就是长度值。php中文网还提供JavaScript数组的相关下载、相关课程等内容,供大家免费下载使用。

2023.06.20

4426

5

js刷新当前页面
js刷新当前页面

js刷新当前页面的方法:1、reload方法,该方法强迫浏览器刷新当前页面,语法为“location.reload([bForceGet]) ”;2、replace方法,该方法通过指定URL替换当前缓存在历史里(客户端)的项目,因此当使用replace方法之后,不能通过“前进”和“后退”来访问已经被替换的URL,语法为“location.replace(URL) ”。php中文网为大家带来了js刷新当前页面的相关知识、以及相关文章等内容

2023.07.04

1109

3

js四舍五入
js四舍五入

js四舍五入的方法:1、tofixed方法,可把 Number 四舍五入为指定小数位数的数字;2、round() 方法,可把一个数字舍入为最接近的整数。php中文网为大家带来了js四舍五入的相关知识、以及相关文章等内容

2023.07.04

4344

6

js删除节点的方法
js删除节点的方法

js删除节点的方法有:1、removeChild()方法,用于从父节点中移除指定的子节点,它需要两个参数,第一个参数是要删除的子节点,第二个参数是父节点;2、parentNode.removeChild()方法,可以直接通过父节点调用来删除子节点;3、remove()方法,可以直接删除节点,而无需指定父节点;4、innerHTML属性,用于删除节点的内容。

2023.09.01

880

4

JavaScript转义字符
JavaScript转义字符

JavaScript中的转义字符是反斜杠和引号,可以在字符串中表示特殊字符或改变字符的含义。本专题为大家提供转义字符相关的文章、下载、课程内容,供大家免费下载体验。

2023.09.04

1776

5

js生成随机数的方法
js生成随机数的方法

js生成随机数的方法有:1、使用random函数生成0-1之间的随机数;2、使用random函数和特定范围来生成随机整数;3、使用random函数和round函数生成0-99之间的随机整数;4、使用random函数和其他函数生成更复杂的随机数;5、使用random函数和其他函数生成范围内的随机小数;6、使用random函数和其他函数生成范围内的随机整数或小数。

2023.09.04

3185

4

如何启用JavaScript
如何启用JavaScript

JavaScript启用方法有内联脚本、内部脚本、外部脚本和异步加载。详细介绍:1、内联脚本是将JavaScript代码直接嵌入到HTML标签中;2、内部脚本是将JavaScript代码放置在HTML文件的`<script>`标签中;3、外部脚本是将JavaScript代码放置在一个独立的文件;4、外部脚本是将JavaScript代码放置在一个独立的文件。

2023.09.12

4153

6

Js中Symbol类详解
Js中Symbol类详解

javascript中的Symbol数据类型是一种基本数据类型,用于表示独一无二的值。Symbol的特点:1、独一无二,每个Symbol值都是唯一的,不会与其他任何值相等;2、不可变性,Symbol值一旦创建,就不能修改或者重新赋值;3、隐藏性,Symbol值不会被隐式转换为其他类型;4、无法枚举,Symbol值作为对象的属性名时,默认是不可枚举的。

2023.09.20

2680

5

java访问控制修饰符介绍
java访问控制修饰符介绍

java访问控制修饰符有四种,分别是public、protected、private、默认访问修饰符。详细介绍:1、public,public是最宽松的访问控制修饰符,被修饰的类、方法和变量可以被任何其他类访问,当一个类、方法或变量被声明为public时,它们可以在任何地方被访问,无论是同一个包中的类还是不同包中的类;2、protected修饰符等等。

2023.09.20

868

7

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
GDB 17.2 官方文档集合
GDB 17.2 官方文档集合

共0课时 | 0人学习

Bootstrap 入门安装配置
Bootstrap 入门安装配置

共0课时 | 0人学习

38+ PhpStorm 提示和技巧
38+ PhpStorm 提示和技巧

共1课时 | 219人学习