Search code examples
phpwordpresswoocommerceordersemail-notifications

Send an email notification for orders with pending payments


I use the following code to send an admin email when the order status changes from pending to cancelled.

add_action('woocommerce_order_status_pending_to_cancelled', 'cancelled_send_an_email_notification', 10, 2 );
function cancelled_send_an_email_notification( $order_id, $order ){
    // Getting all WC_emails objects
    $email_notifications = WC()->mailer()->get_emails();

    // Sending the email
    $email_notifications['WC_Email_Cancelled_Order']->trigger( $order_id );
}

Now I am looking to achieve the same whenever orders are stuck with the status "pending payment".

enter image description here

Does anyone have a solution to this?


Solution

  • As each created order get an initial pending status, to avoid being notified for all orders, you can use the following approach, that will send a daily custom email notification to the admin, with the linked list of pending orders (if any):

    add_action('woocommerce_order_status_changed', 'pending_orders_daily_notification', 10, 4 );
    function pending_orders_daily_notification( $order_id, $from, $to, $order ){
        // Check daily for pending orders
        if ( get_option('wc_daily_check_for_pending_orders', date("Y-m-d") ) >= date("Y-m-d") ) {
            // Get pending orders
            $_orders = wc_get_orders( array(
                'limit'         => -1,
                'status'        => 'pending',
                'date_created'  => '<' . date('Y-m-d H:i:s', strtotime("-1 day") ), // 1 day older at least
            ) );
    
            $email_subject = __( 'List of remaining pending orders' );
    
            $message_body  = '<html>
            <head></head>
            <body>
                <h1>'. __( 'Pending Orders List' ) .'</h1>';
    
            $count = 0; // Initialize counter
    
            // Loop through WC_Order objects
            foreach ( $_orders as $_order ) {
                if ( ! $_order->get_meta('_pending_notification') ) {
                    $message_body .= sprintf(
                        '<p><a href="%s">' . __('Order number #%s created on %s') . '</a></p>', 
                        admin_url('admin.php?page=wc-orders&action=edit&id=' . $_order->get_id() ),  $_order->get_id(), 
                        $_order->get_date_created()->format('Y-m-d') 
                    );
                    $_order->update_meta_data('_pending_notification', '1'); // Tag the order as notified
                    $count++;
                }
            }
            $message_body .= '</body></html>';
    
            if ( $count > 0 ) {
                $mailer    = WC()->mailer(); // load the mailer class.
                $recipient = $mailer->get_emails()['WC_Email_New_Order']->recipient; // Get admin recipient
                $message   = $mailer->wrap_message( $email_subject, $message_body ); 
    
                $mailer->send( $recipient, $email_subject, $message ); // Sending email notification
            }
            // Add one day to the initial check
            update_option('wc_daily_check_for_pending_orders', date("Y-m-d", strtotime("+1 day") ) );
        }
    }
    

    Untested, it could work.

    Note: Listed orders are at least 1 day old, to avoid listing orders that are being processed by WooCommerce. You can adjust fine tune that by changing "-1 day" to "-3 hours" for example.

    Here, the links for each order are going to the admin edit order for High Performance order Storage enabled. If it's not the case you will have to adjust the string inside admin_url() function.