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

如何为WooCommerce订单表单添加费用凭证图片上传功能?

费用凭证图片上传功能实现方案

我已搭建完成支持Order ID、费用金额及原因提交的表单,提交后数据会存入对应订单的metadata。现需拓展1张/多张费用凭证图片上传功能,针对以下问题给出实现方案:

  1. 如何在现有表单中启用图片上传功能?
  2. 如何将上传图片存储至指定目录/wp-content/uploads/2023/Expense_images并关联对应Order ID?

一、前端表单与AJAX修改(实现图片上传交互)

1. 表单修改

需添加文件上传控件,并设置表单enctype属性为multipart/form-data以支持文件传输:

<form id="expense_form" class="expense_form" action="" method="post" enctype="multipart/form-data">
    <label for="order-id">Order ID:</label>
    <input class="exp_order_no" id="exp_order_no" type="text" pattern="[0-9]*" placeholder="Enter the Order Number" required>
    
    <label for="expense">Expense:</label>
    <input class="expense_amt" id="expense_amt" type="text"  pattern="[0-9]*" placeholder="Enter the expense amount" required>
    
    <label for="reason">Reason for Expense:</label>
    <textarea class="expense_reason" id="expense_reason" name="reason" rows="4" placeholder="Enter Message" required></textarea>

    <!-- 新增多文件上传控件,限制图片格式 -->
    <label for="expense_images">Expense Receipts:</label>
    <input type="file" id="expense_images" name="expense_images[]" multiple accept="image/jpeg,image/png,image/gif" required>

    <input type="submit" class="exp_but" id="exp_but" value="Submit">
</form> 

2. AJAX提交逻辑修改

改用FormData封装表单数据(包含文件),并禁用jQuery默认的表单数据处理:

jQuery(document).ready(function($) {
    $('#expense_form').on('submit', function(e) {
        e.preventDefault();
        
        // 用FormData封装所有表单数据(含文件)
        var formData = new FormData(this);
        formData.append('action', 'update_custom_field_order_expense_php');

        $.ajax({
            url: '<?php echo admin_url('admin-ajax.php'); ?>',
            type: 'POST',
            data: formData,
            contentType: false, // 让浏览器自动处理文件传输的编码类型
            processData: false, // 禁止jQuery解析FormData,避免文件损坏
            success: function( response ) {
                console.log( 'Custom field updated successfully.' );
                alert('Expense Submitted Successfully !!');
                location.reload();
            },
            error: function( response ) {
                console.log( 'Failed to Submit Expense.' );
                alert('Failed to Submit Expense. Contact Online Team.');
                location.reload();
            }
        });
    });
});         

二、后端PHP处理(文件存储与订单关联)

修改原有的AJAX处理函数,实现文件上传到指定目录,并将图片URL存入订单metadata:

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');

function update_custom_field_order_expense_php() {
    // 验证用户登录状态
    if ( !is_user_logged_in()) {
        http_response_code(401); 
        wp_send_json(array('error' => 'Authentication required'));
        exit;
    }

    $order_id = $_POST['orderid'];
    $order_expense = $_POST['expense'];
    $order_expense_reason = $_POST['expense_reason'];
    $order = wc_get_order( $order_id );

    // 验证订单是否存在
    if ( !$order ) {
        http_response_code(404);
        wp_send_json(array('error' => 'Order not found'));
        exit;
    }

    $current_user = wp_get_current_user();
    $current_user_id = $current_user->ID;
    $driver_id = get_post_meta($order_id, 'lddfw_driverid', true);

    // 检查是否已存在费用记录
    $expense_exist = false;
    foreach ( $order->get_meta_data() as $meta ) {
        if ( $meta->key === 'Driver Expense') {
            $expense_exist = true;
            break;
        }
    }

    // 权限验证:仅对应司机可提交,且不能重复提交
    if ($current_user_id != $driver_id || $expense_exist) {
        http_response_code(403);
        wp_send_json(array('error' => 'Access denied'));
        exit;
    }

    // 处理图片上传逻辑
    $upload_dir = wp_upload_dir();
    // 构建目标目录:在指定路径下创建以Order ID命名的子目录
    $target_dir = $upload_dir['basedir'] . '/2023/Expense_images/' . $order_id . '/';
    $target_url = $upload_dir['baseurl'] . '/2023/Expense_images/' . $order_id . '/';
    $uploaded_image_urls = array();

    // 安全创建目标目录(不存在则自动递归创建)
    if (!file_exists($target_dir)) {
        wp_mkdir_p($target_dir);
    }

    // 遍历上传的文件
    if (isset($_FILES['expense_images'])) {
        $files = $_FILES['expense_images'];
        for ($i = 0; $i < count($files['name']); $i++) {
            $file_name = sanitize_file_name($files['name'][$i]);
            $file_tmp = $files['tmp_name'][$i];
            $file_error = $files['error'][$i];

            // 仅处理上传成功的文件
            if ($file_error === UPLOAD_ERR_OK) {
                $target_file = $target_dir . $file_name;
                // 文件名重复时添加时间戳避免覆盖
                if (file_exists($target_file)) {
                    $file_parts = pathinfo($file_name);
                    $target_file = $target_dir . $file_parts['filename'] . '_' . time() . '.' . $file_parts['extension'];
                }

                // 移动文件到目标目录
                if (move_uploaded_file($file_tmp, $target_file)) {
                    $image_url = $target_url . basename($target_file);
                    $uploaded_image_urls[] = $image_url;
                }
            }
        }
    }

    // 更新订单metadata
    $order->update_meta_data('Driver Expense', $order_expense);
    $order->update_meta_data('Driver Expense Reason', $order_expense_reason);
    // 存储图片URL数组
    if (!empty($uploaded_image_urls)) {
        $order->update_meta_data('Driver Expense Receipts', $uploaded_image_urls);
    }
    $order->save();

    wp_send_json_success();
    exit;
}

关键说明

  • 前端:表单必须设置enctype="multipart/form-data"才能传输文件;AJAX使用FormData并禁用contentType和processData的默认处理。
  • 后端:利用wp_upload_dir()获取WordPress标准上传路径,创建以Order ID命名的子目录实现图片与订单的关联;用wp_mkdir_p()安全创建目录,避免权限问题。
  • 防重复:保留原有的司机权限验证和重复提交限制逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 02:52:36