如何在WooCommerce中通过代码创建已完成订单且不向客户发送邮件
Hey there! I get what you're trying to do—create a completed WooCommerce order without triggering that automatic email to the customer, and you don't want to disable emails globally in the admin. Let's walk through a couple of reliable ways to handle this:
This approach temporarily disables the specific hook that triggers the completed order email, runs your order creation code, then re-enables the hook so future orders work normally.
Here's your modified code:
// Temporarily remove the completed order email hook remove_action('woocommerce_order_status_completed_notification', array(WC()->mailer(), 'send_transactional_email'), 10); // Your original order creation logic $order = wc_create_order(); $order->set_customer_id($userId); foreach($_POST['basket'] as $prod){ $order->add_product(wc_get_product($prod['id']), $prod['count']); // Note: get_product() is deprecated, use wc_get_product() instead } $order->set_address($address, 'billing'); $order->calculate_totals(); $order->update_status("completed", 'TEST', TRUE); // Restore the email hook for future orders add_action('woocommerce_order_status_completed_notification', array(WC()->mailer(), 'send_transactional_email'), 10);
Quick note: I swapped get_product() for wc_get_product()—the former is an outdated WooCommerce function, so using the new one keeps your code compatible with recent versions.
If you need granular control (like only blocking emails for your test orders), use the woocommerce_email_enabled filter to target specific orders.
First, add this filter to your theme's functions.php file or a custom plugin:
add_filter('woocommerce_email_enabled_completed_order', 'disable_completed_email_for_test_orders', 10, 2); function disable_completed_email_for_test_orders($enabled, $order) { // Check if the order has our test note if ($order->get_status_notes() && str_contains($order->get_status_notes(), 'TEST')) { return false; } // Alternatively, use a custom meta field for clearer targeting: // if ($order->get_meta('_is_test_order') === 'yes') { // return false; // } return $enabled; }
Then update your order creation code to mark the test order (if using the custom meta field approach):
$order = wc_create_order(); $order->set_customer_id($userId); foreach($_POST['basket'] as $prod){ $order->add_product(wc_get_product($prod['id']), $prod['count']); } $order->set_address($address, 'billing'); $order->calculate_totals(); // Add custom meta to mark as test order (if using the meta field filter) $order->update_meta_data('_is_test_order', 'yes'); $order->save_meta_data(); $order->update_status("completed", 'TEST', TRUE);
This method ensures only your test orders skip the email, leaving normal order notifications fully functional.
One extra tip: You might notice the third parameter in update_status() is set to TRUE—that's the "notify" flag. Setting it to FALSE can sometimes prevent emails, but third-party plugins or custom code might override this. The two methods above are more reliable for consistent results.
内容的提问来源于stack exchange,提问作者Parsa Nikoo

