3

My goal is to send an email to the customer containing custom text if the order status is on-hold and if the order creation time is 48 hours or more old.

  1. order is 48 hours old or more
  2. send email to customer
  3. ask customer to pay
  4. include a link to the order (to my account payment page)

I'm trying to use the code from an answer to one of my previous questions about Automatically cancel order after X days if no payment in WooCommerce.

I have lightly changes the code:

add_action( 'restrict_manage_posts', 'on_hold_payment_reminder' );
function on_hold_payment_reminder() {
    global $pagenow, $post_type;

    if( 'shop_order' === $post_type && 'edit.php' === $pagenow 
        && get_option( 'unpaid_orders_daily_process' ) < time() ) :

    $days_delay = 5;

    $one_day    = 24 * 60 * 60;
    $today      = strtotime( date('Y-m-d') );

    $unpaid_orders = (array) wc_get_orders( array(
        'limit'        => -1,
        'status'       => 'on-hold',
        'date_created' => '<' . ( $today - ($days_delay * $one_day) ),
    ) );

    if ( sizeof($unpaid_orders) > 0 ) {
        $reminder_text = __("Payment reminder email sent to customer $today.", "woocommerce");

        foreach ( $unpaid_orders as $order ) {
            // HERE I want the email to be sent instead  <===  <===  <===  <===  <=== 
        }
    }
    update_option( 'unpaid_orders_daily_process', $today + $one_day );

    endif;
}

This is the email part that I want to sync with the above (read the code comments):

add_action ('woocommerce_email_order_details', 'on_hold_payment_reminder', 5, 4);
function on_hold_payment_reminder( $order, $sent_to_admin, $plain_text, $email ){

    if ( 'customer_on_hold_order' == $email->id ){
        $order_id = $order->get_id();

        echo "<h2>Do not forget about your order..</h2>
        <p>CUSTOM MESSAGE HERE</p>";
    }
}

So how can I send an email notification reminder for "on-hold" orders with a custom text?

LoicTheAztec
  • 229,944
  • 23
  • 356
  • 399

1 Answers1

3

The following code will be triggered once daily and will send an email reminder with a custom message on unpaid orders (for "on-hold" order status):

add_action( 'restrict_manage_posts', 'on_hold_payment_reminder' );
function on_hold_payment_reminder() {
    global $pagenow, $post_type;

    if( 'shop_order' === $post_type && 'edit.php' === $pagenow
        && get_option( 'unpaid_orders_reminder_daily_process' ) < time() ) :

    $days_delay = 2; // 48 hours
    $one_day    = 24 * 60 * 60;
    $today      = strtotime( date('Y-m-d') );

    $unpaid_orders = (array) wc_get_orders( array(
        'limit'        => -1,
        'status'       => 'on-hold',
        'date_created' => '<' . ( $today - ($days_delay * $one_day) ),
    ) );

    if ( sizeof($unpaid_orders) > 0 ) {
        $reminder_text = __("Payment reminder email sent to customer $today.", "woocommerce");

        foreach ( $unpaid_orders as $order ) {
            $order->update_meta_data( '_send_on_hold', true );
            $order->update_status( 'reminder', $reminder_text );

            $wc_emails = WC()->mailer()->get_emails(); // Get all WC_emails objects instances
            $wc_emails['WC_Email_Customer_On_Hold_Order']->trigger( $order->get_id() ); // Send email
        }
    }
    update_option( 'unpaid_orders_reminder_daily_process', $today + $one_day );

    endif;
}


add_action ( 'woocommerce_email_order_details', 'on_hold_payment_reminder_notification', 5, 4 );
function on_hold_payment_reminder_notification( $order, $sent_to_admin, $plain_text, $email ){
    if ( 'customer_on_hold_order' == $email->id && $order->get_meta('_send_on_hold') ){
        $order_id     = $order->get_id();
        $order_link   = wc_get_page_permalink('myaccount').'view-order/'.$order_id.'/';
        $order_number = $order->get_order_number();

        echo '<h2>'.__("Do not forget about your order.").'</h2>
        <p>'.sprintf( __("CUSTOM MESSAGE HERE… %s"), 
            '<a href="'.$order_link.'">'.__("Your My account order #").$order_number.'<a>'
        ) .'</p>';

        $order->delete_meta_data('_send_on_hold');
        $order->save();
    }
}

Code goes in functions.php file of your active child theme (or active theme). Tested and works.

LoicTheAztec
  • 229,944
  • 23
  • 356
  • 399
  • please tell how to format the time if I want to test this. I tried using 1 and 1 * 1 but nothing happens. How do I turn the time into 30 seconds so that I can place a test order, go into the admin and refresh the order page and get the email? –  Apr 23 '19 at 13:38
  • and what is `view-order/1516/` for? Is that how to link to the actual order the email is referring to? –  Apr 23 '19 at 14:28
  • when is the update each day made? Meaning; how do I know when the function runs each day? Also, is there no way to remove that kind of "trigger"? It would be better if it just checks the time of the order creation and if that time is more than the time delay, send out the email. –  Apr 29 '19 at 11:08
  • I am asking since so far nothing is happening on my end. I've changed the calculation to 60 * 60 * 24 (60 seconds per minute and 60 minutes per hour and 24 hours per day). That did not help either. –  Apr 29 '19 at 11:10
  • @KevinAronsson Is better to use the other method based on order status change event… – LoicTheAztec Apr 29 '19 at 11:11
  • I tried that too, but since you removed your comment on how to test I don't know if it works or not. I made two manual orders, both backdated 10 days. Then I changed one of them to complete and no email was sent to the other. –  Apr 29 '19 at 11:18
  • in your database on wp_options table check for meta_key unpaid_orders_reminder_daily_process where a the current timestamp + 1day is set (daily updated)… – LoicTheAztec Apr 29 '19 at 11:35
  • okay. I changed the code a bit and managed to get it working by default. If it becomes heavy we'll just have to find a better solution or get a plugin. I just want the process to be automatic without user input based on time = once the order is "old", the email goes out and once the order is "to old" it gets automatically deleted. –  Apr 29 '19 at 11:42
  • also, this does not work for manual orders. Just thought you wanted to know. When clicking the link in the email you get to the account and it says, "Invalid order". –  Apr 29 '19 at 11:44
  • @KevinAronsson I will re-test everything in upcoming days… – LoicTheAztec Apr 29 '19 at 18:00
  • I ran a "real" test by making a test order using BACS. The order was created with on-hold status (like normal). The only change I made to the code was changing the "update" time to 1 instead of 5 (1 day). The email went out as planned but the order was given "Processing" status, which is not ideal. Any idea why and how to fix that? The idea is to combine this with the "automatic cancel" feature and doing that after the order is placed into processing is not ideal either since a new email is sent out for that status. –  May 03 '19 at 07:16
  • Is it actually necessary to update the order status to `reminder`? – svelandiag Jul 02 '20 at 21:35