如何为WooCommerce订单表单添加费用凭证图片上传功能?
费用凭证图片上传功能实现方案
我已搭建完成支持Order ID、费用金额及原因提交的表单,提交后数据会存入对应订单的metadata。现需拓展1张/多张费用凭证图片上传功能,针对以下问题给出实现方案:
- 如何在现有表单中启用图片上传功能?
- 如何将上传图片存储至指定目录
/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
相关产品推荐
相关产品推荐

