-
-
Save damiencarbery/dfc45a9ceb52fa336749b363a6e7dd51 to your computer and use it in GitHub Desktop.
<?php | |
/* | |
Plugin Name: Defer WooCommerce emails for a few minutes (use Action Scheduler) | |
Plugin URI: https://www.damiencarbery.com/2020/04/defer-woocommerce-emails-for-a-few-minutes/ | |
Description: Defer WooCommerce emails for a specified time after the normal delivery time. Use Action Scheduler instead of WP Cron. Call do_action() instead of remove_action() and calling trigger. | |
Author: Damien Carbery | |
Author URI: https://www.damiencarbery.com | |
Version: 0.8 | |
*/ | |
class DeferSendingWooCommerceEmails { | |
private static $instance; | |
private $default_defer_time; | |
// An associative array to match $email_id with email class, to allow for the deferring of different emails. | |
private $email_id_to_defer; | |
// Returns an instance of this class. | |
public static function get_instance() { | |
if ( null == self::$instance ) { | |
self::$instance = new DeferSendingWooCommerceEmails(); | |
} | |
return self::$instance; | |
} | |
// Initialize the plugin variables. | |
public function __construct() { | |
$this->default_defer_time = 600; // Defer for 600 seconds (10 minutes). | |
// Can add other email IDs and their defer times. | |
// You can uncomment the add_action() with 'order_status_changed' function to find out the before and after status. | |
// This is also the list of emails that will be deferred. | |
$this->email_id_to_defer = array( | |
'woocommerce_new_customer_note' => $this->default_defer_time, | |
'woocommerce_order_status_completed' => $this->default_defer_time, | |
// Probably don't want to defer these emails but they are shown | |
// here as a demo of a different defer time. | |
//'woocommerce_order_status_pending_to_on-hold' => $this->default_defer_time, // New order | |
//'woocommerce_order_status_pending_to_processing' => $this->default_defer_time, | |
// Additional transitition-to-email class info from @djm56 | |
//'woocommerce_order_status_on-hold' => $this->default_defer_time, // Order on hold. | |
//'woocommerce_order_status_pending_to_on-hold' => $this->default_defer_time, // Order on hold. | |
//'woocommerce_order_status_cancelled_to_on-hold' => $this->default_defer_time, // Order on hold. | |
//'woocommerce_order_status_pending_to_on-hold' => $this->default_defer_time, // Order on hold. | |
); | |
$this->init(); | |
} | |
// Set up WordPress specfic actions. | |
public function init() { | |
// Set all WooCommerce emails to be deferred. | |
add_filter( 'woocommerce_defer_transactional_emails', '__return_true' ); | |
// Allow most emails to be sent as normal but prevent emails listed in $this->email_id_to_defer. Schedule them for a time in the future. | |
add_filter( 'woocommerce_allow_send_queued_transactional_email', array( $this, 'whether_send_queued_wc_email' ), 10, 3 ); | |
// This is the scheduled function that will send the email. | |
add_action( 'send_deferred_woocommerce_email', array( $this, 'send_deferred_woocommerce_email' ), 10, 2 ); | |
// DEBUG: Add the order modification time and current time to prove that the email was intentionally delayed. | |
add_action( 'woocommerce_email_order_details', array( $this, 'add_defer_length_info_to_order_email' ), 5, 4 ); | |
// Uncomment this to log the before and after statuses so you know what ones | |
// to add to the $this->email_id_to_defer array. | |
//add_action('woocommerce_order_status_changed', array( $this, 'order_status_changed' ), 10, 4); | |
} | |
// Log the before and after status to discover which one to add to $this->email_id_to_defer array. | |
public function order_status_changed( $id, $from, $to, $order ) { | |
error_log( 'Order ID: ' . $id ); | |
error_log( 'Status from: ' . $from ); | |
error_log( 'Status to: ' . $to ); | |
} | |
private function get_email_defer_time( $filter ) { | |
if ( array_key_exists( $filter, $this->email_id_to_defer ) ) { | |
return $this->email_id_to_defer[ $filter ]; | |
} | |
return $this->default_defer_time; | |
} | |
public function whether_send_queued_wc_email( $true, $filter, $args ) { | |
//error_log( 'woocommerce_allow_send_queued_transactional_email $filter: ' . var_export( $filter, true ) ); | |
//error_log( 'woocommerce_allow_send_queued_transactional_email order_number: ' . var_export( $args[ 0 ], true ) ); | |
if ( array_key_exists( $filter, $this->email_id_to_defer ) ) { | |
// TODO: Consider verifying that $args[0] is a valid order number. | |
//$order = wc_get_order( $args[ 0 ] ); | |
//$action_args = array( 'filter' => $filter, 'args' => $args ); | |
// Call Action Scheduler instead of WP Cron. Args will be filter and $args. | |
$event_id = as_schedule_single_action( time() + $this->get_email_defer_time( $filter ), 'send_deferred_woocommerce_email', array( $filter, $args ) ); | |
//$order_num = $args[ 0 ]; | |
//error_log( sprintf( 'woocommerce_allow_send_queued_transactional_email: Defer a %s email for order: %s for %d seconds (event ID: %d).', $filter, $order_num, $this->get_email_defer_time( $filter ), $event_id ) ); | |
return false; | |
} | |
//error_log( 'woocommerce_allow_send_queued_transactional_email: Ok to send email.' ); | |
return $true; | |
} | |
// Send the deferred email for order $order_id. | |
public function send_deferred_woocommerce_email( $filter, $args = array() ) { | |
//error_log( 'send_deferred_woocommerce_email for order: ' . $order_id ); | |
// Use same code as WC_Emails::send_queued_transactional_email() in woocommerce/includes/class-wc-emails.php | |
WC_Emails::instance(); | |
// Ensure gateways are loaded in case they need to insert data into the emails. | |
WC()->payment_gateways(); | |
WC()->shipping(); | |
do_action_ref_array( $filter . '_notification', $args ); | |
} | |
// This is an experimental function to add the date/time the order was modified and | |
// the date/time the email was sent into email - to demonstrate that the deferring code worked. | |
public function add_defer_length_info_to_order_email( $order, $sent_to_admin, $plain_text, $email ) { | |
if ( 'customer_completed_order' == $email->id ) { | |
if ( $plain_text ) { | |
printf( '%sThe order was modified at %s and email sent at %s.', "\n", $order->get_date_modified(), current_time( 'mysql' ) ); | |
} | |
else { | |
printf( '<p>The order was modified at <strong>%s</strong> and email sent at <strong>%s</strong>.</p>', $order->get_date_modified(), current_time( 'mysql' ) ); | |
} | |
} | |
} | |
} | |
$DeferSendingWooCommerceEmails = new DeferSendingWooCommerceEmails(); |
Will this work for registration notification?
If that plugin uses the WooCommerce email system then it could be defer those emails by adding the email ID to the$this->email_id_to_defer
array.
Where could I download that plugin to experiment?
I have solved mine the problem! I commented out the hooks for debugging, because these actions are missing in the desired email. Message ID is"woocommerce_created_customer".
I have solved mine the problem! I commented out the hooks for debugging, because these actions are missing in the desired email. Message ID is"woocommerce_created_customer".
Did you add 'woocommerce_created_customer
' to the$this->email_id_to_defer
array?
Where should this code be placed?
Where should this code be placed?
@esachs4 : The code is a standalone plugin. You can download the raw file and upload it to wp-content/plugins and then activate it. I made a demo video at: https://www.damiencarbery.com/2018/10/how-to-use-my-code-snippets/
Will this work for registration notification?