WooCommerce后台订单邮件按钮异常及功能优化技术求助
问题与解决方案:WooCommerce订单通知按钮异常及功能优化
一、点击按钮后订单状态变为pending payment的原因与修复
问题根源
- 钩子使用错误:原代码将邮件发送逻辑挂在
woocommerce_admin_order_data_after_order_details钩子上,该钩子仅用于在订单详情页渲染内容,并非处理按钮提交请求。点击按钮时触发了订单页面的默认表单提交逻辑,导致状态意外重置为pending payment。 - 缺少独立的提交处理逻辑:原代码未添加按钮的HTML结构,也没有专门处理按钮点击的POST请求逻辑,操作直接触发了订单页面的默认提交行为。
- 条件判断逻辑错误:原代码中
if($status=='processing' || 'driver-assigned' || 'out-for-delivery')的写法永远为真(非空字符串在PHP中会被解析为true),正确写法需逐个判断状态是否匹配。
修复步骤
- 拆分逻辑:将按钮渲染和提交处理分开,按钮渲染保留原钩子,提交处理使用WordPress的
admin_post_*钩子(专门处理后台POST请求)。 - 添加按钮HTML:在订单详情页插入触发邮件发送的按钮,提交到独立处理地址,避免触发订单默认表单提交。
- 修正状态判断:使用
in_array()精准匹配允许显示按钮的订单状态。
二、按钮显示条件优化
按照需求,仅在订单状态为driver-assigned或out-for-delivery时显示按钮,通过状态数组判断即可实现。
修正后的完整代码
// 1. 在订单详情页渲染通知按钮 add_action( 'woocommerce_admin_order_data_after_order_details', 'render_driver_notification_button' ); function render_driver_notification_button( $order ) { $status = $order->get_status(); // 仅在指定状态下显示按钮 if( in_array( $status, ['driver-assigned', 'out-for-delivery'] ) ) { // 检查邮件是否已发送,避免重复发送 $email_sent = $order->get_meta( 'email_sent', true ); $button_text = $email_sent === 'Yes' ? '通知已发送' : '通知司机自提'; $button_disabled = $email_sent === 'Yes' ? 'disabled' : ''; // 输出按钮HTML,提交到admin post处理 echo '<div style="margin-top:15px;"> <form action="' . admin_url( 'admin-post.php' ) . '" method="post"> <input type="hidden" name="action" value="send_driver_pickup_email"> <input type="hidden" name="order_id" value="' . $order->get_id() . '"> ' . wp_nonce_field( 'send_driver_pickup_nonce_' . $order->get_id(), 'send_driver_pickup_nonce', true, false ) . ' <button type="submit" class="button button-primary" ' . $button_disabled . '>' . $button_text . '</button> </form> </div>'; } } // 2. 处理按钮提交的邮件发送逻辑 add_action( 'admin_post_send_driver_pickup_email', 'send_driver_pickup_email_handler' ); function send_driver_pickup_email_handler() { // 验证权限和nonce if( !current_user_can( 'edit_shop_orders' ) || !isset( $_POST['send_driver_pickup_nonce'] ) || !wp_verify_nonce( $_POST['send_driver_pickup_nonce'], 'send_driver_pickup_nonce_' . $_POST['order_id'] ) ) { wp_die( '权限验证失败' ); } $order_id = absint( $_POST['order_id'] ); $order = wc_get_order( $order_id ); if( !$order ) { wp_die( '无效的订单ID' ); } // 再次验证订单状态(防止前端篡改) $status = $order->get_status(); if( !in_array( $status, ['driver-assigned', 'out-for-delivery'] ) ) { wp_die( '当前订单状态不允许发送通知' ); } // 检查邮件是否已发送 $email_sent = $order->get_meta( 'email_sent', true ); if( $email_sent === 'Yes' ) { wp_die( '通知已发送,无需重复操作' ); } // 获取司机ID $driver_id = $order->get_meta( 'lddfw_driverid', true ); if( empty( $driver_id ) ) { wp_die( '未找到关联的司机ID' ); } $driver = get_userdata( $driver_id ); if( !$driver ) { wp_die( '无效的司机用户ID' ); } // 发送邮件 $subject = '订单编号 ' . $order->get_id() . ' 已准备好自提'; $message = '您好 ' . $driver->display_name . ',<br><br>订单编号 ' . $order->get_id() . ' 现已准备好,请前往自提。'; $headers = array( 'Content-Type: text/html; charset=UTF-8' ); if( wp_mail( $driver->user_email, $subject, $message, $headers ) ) { // 更新邮件发送标记 $order->update_meta_data( 'email_sent', 'Yes' ); $order->save(); // 跳转回订单详情页并提示成功 wp_redirect( add_query_arg( array( 'post' => $order_id, 'action' => 'edit', 'email_sent' => 'success' ), admin_url( 'post.php' ) ) ); exit; } else { wp_die( '邮件发送失败,请稍后重试' ); } } // 3. 添加邮件发送成功提示 add_action( 'admin_notices', 'driver_email_sent_notice' ); function driver_email_sent_notice() { if( isset( $_GET['email_sent'] ) && $_GET['email_sent'] === 'success' ) { echo '<div class="notice notice-success is-dismissible"> <p>司机通知邮件已成功发送!</p> </div>'; } } // 邮件发件人设置 add_filter('wp_mail_from', 'original_mail_address_email'); function original_mail_address_email(){ return 'admin@gmail.com'; } add_filter('wp_mail_from_name', 'email_name_order_ready'); function email_name_order_ready(){ return 'Oven Fresh'; }
关键改进点
- 分离渲染与处理:避免钩子使用错误导致的订单状态异常。
- 权限与安全验证:添加nonce验证和用户权限检查,防止恶意请求。
- 状态校验:前后端双重验证订单状态,确保按钮仅在允许的状态下显示和操作。
- 重复发送防护:通过自定义元数据
email_sent标记邮件是否已发送,避免重复操作。 - 用户反馈:添加邮件发送成功的后台通知,提升操作体验。
内容的提问来源于stack exchange,提问作者Rishikesh Dubey
相关产品推荐
相关产品推荐

