phpwordpresswoocommercehook-woocommercecron-task

Use WooCommerce WC_Order object with wp_schedule_event


I am creating a Cron to trigger cloning an order using wp_schedule_event. It works when I create a function to send email tests every minute. However, when I switch the function to the clone function, nothing happens. What could go wrong?

PS: This Cron is supposed to run for weekly, but for testing purposes, I use everyminute

/* create a scheduled event: every minute */
function cron_add_minute( $schedules ) {
    // Adds once every minute to the existing schedules.
    $schedules['everyminute'] = array(
        'interval' => 60,
        'display' => __( 'Once Every Minute' )
    );
    return $schedules;
}
add_filter( 'cron_schedules', 'cron_add_minute' );

function cronstarter_activation_weekly() {
    if( !wp_next_scheduled( 'clone_order_weekly' ) ) {  
        wp_schedule_event(time(), 'everyminute', 'clone_order_weekly' );  
    }
}
add_action('woocommerce_order_action_clone_order_weekly', 'cronstarter_activation_weekly');

// unscheduled event upon plugin deactivation
function cronstarter_deactivate_weekly() {  
    // find out when the last event was scheduled
    $timestamp = wp_next_scheduled('clone_order_weekly');
    // unschedule previous event if any
    wp_unschedule_event($timestamp, 'clone_order_weekly');
} 
add_action('woocommerce_order_action_clone_order_stop', 'cronstarter_deactivate_weekly');

function my_repeat_function() { 
    // components for our email
    $recepients = 'xxx@yyy.zzz';
    $subject = 'Hello from your Cron Job';
    $message = 'This is a test mail sent by WordPress automatically as per your schedule.';
    
    // Send email test
    mail($recepients, $subject, $message);
}

/*
* This function works well. I got an email every minute
*/
add_action ('clone_order_weekly', 'my_repeat_function');

So with the above code, the cronjob seems to be working just fine.. however when I call the cloning function like so:

/**
 * Trigger Clone action from  Order page
 *
 * @param $order
 */
function m_trigger_action_clone_order( $order ) {
    $order_id = $order->get_id();
    mutiara_woocommerce_order_clone($order_id);
}

add_action ('clone_order_weekly', 'm_trigger_action_clone_order', 20, 1); 

Nothing really happens.. no order is being triggered... I know that m_trigger_action_clone_order works because I attached it to a normal clone button and when I click and trigger the function, a new clone is created:

add_action( 'woocommerce_order_action_clone_order', 'm_trigger_action_clone_order', 20, 1 );

What am I missing?


Solution

  • You forgot to pass $order (the WC_Order object) hook argument to the hooked function, when using 'woocommerce_order_action_' . sanitize_title( $action ) composite hook.

    Then you will be able to pass it to wp_schedule_event() and wp_unschedule_event() functions as an argument.
    Then it should be available in m_trigger_action_clone_order() function.

    Try the following:

    add_filter( 'cron_schedules', 'cron_add_minute' );
    function cron_add_minute( $schedules ) {
        $schedules['everyminute'] = array(
            'interval' => 60,
            'display' => __( 'Once Every Minute' )
        );
        return $schedules;
    }
    
    
    add_action('woocommerce_order_action_clone_order_weekly', 'cronstarter_activation_weekly');
    function cronstarter_activation_weekly( $order ) {
        if ( ! is_a($order, 'WC_Order') ) {
            return;
        }
    
        $args  = array( $order );
    
        if( ! wp_next_scheduled( 'clone_order_weekly', $args ) ) {  
            wp_schedule_event(time(), 'everyminute', 'clone_order_weekly', $args );  
        }
    }
    
    
    add_action('woocommerce_order_action_clone_order_stop', 'cronstarter_deactivate_weekly');
    function cronstarter_deactivate_weekly( $order ) {  
        if ( ! is_a($order, 'WC_Order') ) {
            return;
        }
    
        $args  = array( $order );
    
        // find out when the last event was scheduled
        $timestamp = wp_next_scheduled('clone_order_weekly', $args );
        // unschedule previous event if any
        wp_unschedule_event($timestamp, 'clone_order_weekly', $args );
    } 
    
    add_action ('clone_order_weekly', 'trigger_action_clone_order');
    function trigger_action_clone_order( $order ) {  
        if ( ! is_a($order, 'WC_Order') ) {
            return;
        }
    
        // For testing (Send email with the order ID)
        $recipients = 'thename@domain.tld';
        $subject = 'Scheduled Cron Job from Order number #'.$order->get_order_number();
        $message = 'This is a test mail from a scheduled Cron Job on Order number #'.$order->get_order_number();
        wp_mail($recipients, $subject, $message);
    
        // Your function to be triggered
        mutiara_woocommerce_order_clone( $order->get_id() );
    }
    

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


    For other readers: We need this to start/stop the cron job from WooCommerce "Order Action" metabox:

    add_filter( 'woocommerce_order_actions', 'filter_woocommerce_order_actions', 20, 1 );
    function filter_woocommerce_order_actions( $actions ) {
        $actions['clone_order_weekly'] = __( 'Clone order weekly', 'woocommerce' );
        $actions['clone_order_stop'] = __( 'Clone order stop', 'woocommerce' );
    
        return $actions;
    }
    

    Then you will replace mutiara_woocommerce_order_clone( $order->get_id() ); function with your own…