如何基于WooCommerce订单自定义时间元键发送邮件?排查代码错误
问题排查与代码修正
问题描述
我需要根据自定义的订单过期日期(meta_key: _order_expiration_date)触发邮件通知,目前只能按订单状态触发,核心需求是按日期触发。自己写的代码有问题,还发现wp_post表中订单的post_type变成了shop_order_placehold而非shop_order,以下是原代码:
function add_order_expiration_date_field($order) { $expiration_date = get_post_meta($order->get_id(), '_order_expiration_date', true); ?> <div class=""> <h4><?php _e('Expiration date', 'woocommerce'); ?></h4> <p class="form-field form-field-wide"> <label for="order_expiration_date"><?php _e('Expiration date', 'woocommerce'); ?></label> <input type="datetime-local" class="input-text" name="order_expiration_date" id="order_expiration_date" value="<?php echo esc_attr($expiration_date); ?>" /> </p> </div> <?php } add_action('woocommerce_admin_order_data_after_order_details', 'add_order_expiration_date_field'); //Save due date when updating order function save_order_expiration_date($order_id) { $expiration_date = isset($_POST['order_expiration_date']) ? sanitize_text_field($_POST['order_expiration_date']) : ''; update_post_meta($order_id, '_order_expiration_date', $expiration_date); } add_action('woocommerce_process_shop_order_meta', 'save_order_expiration_date'); // Function to handle custom query parameter'_order_expiration_date' function handle_custom_order_expiration_date_query( $query, $query_vars ) { if ( ! empty( $query_vars['_order_expiration_date'] ) ) { $query['meta_query'][] = array( 'key' => '_order_expiration_date', 'value' => esc_attr( $query_vars['_order_expiration_date']) , 'compare' => '=', ); } return $query; } add_filter( 'woocommerce_order_data_store_cpt_get_orders_query', 'handle_custom_order_expiration_date_query', 10, 2 ); // Test function to send an email function test_cron_mail() { // Define the custom query parameter '_order_expiration_date' $current_date_time = current_time( 'mysql' ); $args = array( 'status' => 'wc-completed', 'meta_query' => array( array( 'key' => '_order_expiration_date', 'value' => $current_date_time, 'compare' => '<', 'type' => 'DATETIME', ), ), 'posts_per_page' => -1, ); // Apply filter to handle custom query parameter add_filter( 'woocommerce_order_data_store_cpt_get_orders_query', 'handle_custom_order_expiration_date_query', 10, 2 ); // Perform order query $query = new WC_Order_Query( $args ); echo 'args: ';var_dump ($args) ; $orders = $query->get_orders(array(); echo 'orders: '; var_dump ($orders) ; // Delete the filter after performing the query remove_filter( 'woocommerce_order_data_store_cpt_get_orders_query', 'handle_custom_order_expiration_date_query', 10, 2 ); // Scroll through expired orders and take necessary actions foreach ( $orders as $order ) { $order_id = $order->get_id(); $billing_name = $order->get_billing_first_name(); $billing_email = $order->get_billing_email(); $subject = 'Hosting expired for ' . $billing_name; $message = 'Your hosting is expired. Please, contact us for further information.'; // Make sure the email address isválida antes de enviar el correo if ( is_email( $billing_email ) ) { wp_mail( $billing_email, $subject, $message ); } } } // Add cron task for test function add_action( 'init', 'schedule_test_cron_job' ); function schedule_test_cron_job() { // Set a 5 minute delay for the test cron task to run $timestamp = time() + 1 * 60; // Schedule the test cron task wp_schedule_single_event($timestamp, 'test_cron_job'); } add_action('test_cron_job', 'test_cron_mail');
代码错误分析与修正
1. 语法错误:get_orders()调用参数不完整
原代码中$orders = $query->get_orders(array();缺少闭合括号,且get_orders()无需传空数组,直接调用即可。
2. 日期格式不匹配导致查询失效
前端datetime-local保存的格式是YYYY-MM-DDTHH:MM,而current_time('mysql')返回YYYY-MM-DD HH:MM:SS,两者格式不一致,需要统一:
- 保存时将
datetime-local格式转换为MySQL DATETIME格式; - 或查询时将当前时间转换为
datetime-local的格式进行比较。
3. 不必要的过滤器调用
handle_custom_order_expiration_date_query过滤器是用于处理自定义查询参数的,当前查询已经直接定义了meta_query,无需额外添加该过滤器,反而会干扰逻辑。
4. Cron任务重复调度问题
schedule_test_cron_job挂在init钩子上,每次页面加载都会创建重复任务,需要先检查任务是否已存在再调度。
5. 避免查询到临时占位订单
添加type => 'shop_order'参数,排除shop_order_placehold类型的临时订单。
6. 注释语法错误
原代码中西班牙语注释存在拼写错误,修正为规范中文注释。
修正后的完整代码
// 添加订单过期日期字段到后台订单详情页 function add_order_expiration_date_field($order) { $expiration_date = get_post_meta($order->get_id(), '_order_expiration_date', true); // 转换MySQL格式为datetime-local格式用于回显 if (!empty($expiration_date)) { $expiration_date = date('Y-m-d\TH:i', strtotime($expiration_date)); } ?> <div class=""> <h4><?php _e('Expiration date', 'woocommerce'); ?></h4> <p class="form-field form-field-wide"> <label for="order_expiration_date"><?php _e('Expiration date', 'woocommerce'); ?></label> <input type="datetime-local" class="input-text" name="order_expiration_date" id="order_expiration_date" value="<?php echo esc_attr($expiration_date); ?>" /> </p> </div> <?php } add_action('woocommerce_admin_order_data_after_order_details', 'add_order_expiration_date_field'); // 保存订单过期日期,转换为MySQL DATETIME格式 function save_order_expiration_date($order_id) { if (isset($_POST['order_expiration_date'])) { // 将datetime-local格式转换为MySQL DATETIME格式 $expiration_date = date('Y-m-d H:i:s', strtotime(sanitize_text_field($_POST['order_expiration_date']))); update_post_meta($order_id, '_order_expiration_date', $expiration_date); } } add_action('woocommerce_process_shop_order_meta', 'save_order_expiration_date'); // 发送过期提醒邮件的核心函数 function send_expired_order_emails() { $current_date_time = current_time('mysql'); $args = array( 'status' => 'wc-completed', 'type' => 'shop_order', // 仅查询正式订单,排除占位符 'meta_query' => array( array( 'key' => '_order_expiration_date', 'value' => $current_date_time, 'compare' => '<', 'type' => 'DATETIME', ), ), 'posts_per_page'=> -1, ); $query = new WC_Order_Query($args); $orders = $query->get_orders(); // 遍历过期订单发送邮件 foreach ($orders as $order) { $billing_name = $order->get_billing_first_name(); $billing_email = $order->get_billing_email(); if (!is_email($billing_email)) { continue; } $subject = 'Hosting expired for ' . $billing_name; $message = 'Your hosting is expired. Please contact us for further information.'; wp_mail($billing_email, $subject, $message); } } // 调度Cron任务:仅在任务不存在时创建 function schedule_expiration_cron_job() { if (!wp_next_scheduled('send_expired_order_emails_hook')) { // 每分钟执行一次(测试用,正式环境可改为每天) wp_schedule_event(time(), 'minute', 'send_expired_order_emails_hook'); } } add_action('init', 'schedule_expiration_cron_job'); // 绑定Cron钩子到发送邮件函数 add_action('send_expired_order_emails_hook', 'send_expired_order_emails');
额外说明
- 如果不需要通过自定义查询参数
_order_expiration_date查询订单,可以直接删除原代码中的handle_custom_order_expiration_date_query函数及其过滤器绑定; - 正式环境建议将Cron调度间隔改为
daily(每天),避免频繁执行; - 可以添加日志记录功能,方便排查邮件发送情况。
内容的提问来源于stack exchange,提问作者fakasmile1
相关产品推荐
相关产品推荐

