skip to Main Content

I am trying to create CRON jobs that pause a subscription on a set date and restart it the day after, during checkout in WordPress/Woocommerce. To do that, I have a custom field in the checkout called "holiday". This is hidden, but stores date values such as this:

10/14/2021, 11/11/2021, 12/09/2021,

It could also be a single value, like this (always includes the final comma):

10/14/2021,

I’m trying to loop through each date, and create 2 CRON jobs, one on that date, and one for the day after. The CRON needs to include the order ID. I have setup some code that WORKS, but only some of the time. It is stored in the thankyou template page, so executes when the thank you page loads (after an order)

//Get the dates
$holiday_dates = get_post_meta( $order->get_id(), 'holiday', false );

//Get rid of the comma and put it all into an array based on the other comma's. Prob a better way to do this but it does work.
$imploded = implode(', ', $holiday_dates); 
$comma_remove = rtrim($imploded, ', '); 
$dates_array = explode(', ', $comma_remove);

//Get the order ID. Put this in json_decode to try and force it as a number, rather than a string.  Didn't seem to make much difference.
$args =  json_decode($order->get_id());

//Loop through the dates array, and run the single event CRON's.
 foreach ($dates_array as $holiday_date) {
     wp_schedule_single_event( strtotime($holiday_date) , 'pause_the_woo_subscription', array($args) );
     wp_schedule_single_event( strtotime("+1 day",strtotime($holiday_date)), 'start_the_woo_subscription', array($args) );
 }

This code seems to work, but only maybe 1 in 5 times. Every other time, the CRONs just don’t load in. I wondered if it was because it needs the thank you page to LOAD, so I tried adding some JS code to refresh the page on first load, to force it to execute.

window.onload = function() {
    if(!window.location.hash) {
        window.location = window.location + '#confirmed';
        setTimeout(function(){ window.location.href = location.reload(true); history.go(0); }, 1000);
    }
}

This didn’t seem to make much difference. I’ve also tried running this code in functions.php using the woocommerce_checkout_subscription_created function, but it’s still inconsistent.

I can’t work out why it works sometimes, and not others. During testing, I did find that if the date included a 0, such as 12/09/2021, it wouldn’t create that cron unless it was 12/9/2021. Not sure if this was related or not.

Any ideas what I’m doing wrong?

3

Answers


  1. You can Debug it using last parameter of wp_schedule_single_event function add true in 4th parameter of your wp_schedule_single_event function for eg.

         wp_schedule_single_event( strtotime($holiday_date) , 'pause_the_woo_subscription', $args ,true );
         wp_schedule_single_event( strtotime("+1 day",strtotime($holiday_date)), 'start_the_woo_subscription', $args,true );
    

    By this way you can find any errors you have in these functions by Editing wp-config.php add following line before it says /* That's all, stop editing! Happy publishing. */

    define( 'WP_DEBUG', true );
    
    define( 'WP_DEBUG_LOG', true );
    
    define( 'WP_DEBUG_DISPLAY', true );
    

    Now one more thing as you are decoding using json_decode so add true as extra parameter so it will definitely return as array

    $args =  json_decode($order->get_id(),true);
    

    Then run your code

    Login or Signup to reply.
  2. I had the same issue, but in a different context. To execute a cron job manually, I came up with this function combination which now executes the cron definitely:

    delete_transient( 'doing_cron' );
    wp_schedule_single_event( time(), $cron );
    spawn_cron();
    sleep( 1 );
    

    Maybe it helps.

    Login or Signup to reply.
  3. Debugging Cron failures can be very hard, so we should approach this with some defensive programming techniques and good debugging skills.

    To get started, we will break down the process in multiple parts, so we know exactly where something doesn’t go as expected.

    First you must make sure you are hooking at the right event to create the crons. If you want to do this on the thank you template page, that’s fine, as long as it’s consistent with your subscription flow and will always fire.

    Next, you must make sure of two things:

    • The order post has a holiday post meta
    • The holiday post meta can be correctly parsed into timestamps with strtotime

    If I’m going to follow your example strictly, it will fail, as the holiday_dates post meta seems to be a string, and you are trying to implode it: https://3v4l.org/TAPVL#v8.1rc3

    So the next step is to make sure you have valid date timestamps for every order, as this is crutial for the cron to work:

    $holiday_dates = get_post_meta( $order->get_id(), 'holiday', false );
    
    // Early bail: This order does not seem to have the holidays post meta
    if (empty($holiday_dates)) {
        error_log(sprintf('Holiday Cron Setup Debug: Order ID %s does not have holiday dates, cannot setup cron.', $order_id) );
        return;
    }
    
    $dates_array = explode(',', $holiday_dates);
    
    // Remove empty lines
    $dates_array = array_filter($dates_array, function($date) {
        return !empty(trim($date));
    });
    
    // Transform the dates into strtotime
    $dates_array = array_map(function($date) {
        return strtotime(trim($date));
    }, $dates_array);
    
    // Early bail: We don't have valid timestamps
    if (empty($dates_array)) {
        error_log(sprintf('Holiday Cron Setup Debug: Could not parse the holiday dates into timestamps on Order ID %s.', $order_id) );
        return;
    }
    

    Now, we setup the crons:

     foreach ($dates_array as $holiday_timestamp) {
         $pause = wp_schedule_single_event( $holiday_timestamp , 'pause_the_woo_subscription', [ 'order_id' => $order->get_id() ], true );
    
         if ($pause instanceof WP_Error) {
             error_log(sprintf('Holiday Cron Setup Debug: Could not enqueue the pause subscription on holiday date %s Order ID %s. Error: %s.', $holiday_timestamp, $order_id, $pause->get_error_message()));
         }
     
         $resume = wp_schedule_single_event( strtotime("+1 day",$holiday_timestamp), 'start_the_woo_subscription', [ 'order_id' => $order->get_id() ], true );
    
         if ($resume instanceof WP_Error) {
             error_log(sprintf('Holiday Cron Setup Debug: Could not enqueue the resume subscription on holiday date %s Order ID %s. Error: %s.', $holiday_timestamp, $order_id, $resume->get_error_message()));
         }
     }
    

    Make sure the $order_id being passed on wp_schedule_single_event is unique, otherwise the cron event might not be enqueued . From WordPress.org docs:

    Note that scheduling an event to occur within 10 minutes of an existing event with the same action hook will be ignored unless you pass unique $args values for each scheduled event.
    

    At this point, I recommend you install WP CLI or some other tool to debug that the Cron events are being enqueued as expected. Eg: Do a test purchase and run wp cron event list in a terminal, you should see the single event being enqueued consistently. (I don’t recommend installing WP CLI on a Production server unless you are very familiar with it. Test this on your local development machine)

    Now that we asserted that the events are being enqueued correctly, we should focus our attention on the pause_the_woo_subscription and start_the_woo_subscription functions:

    add_action('pause_the_woo_subscription', function($order_id) {
      $debug_cron = defined('DEBUG_SUBSCRIPTION_CRON') && DEBUG_SUBSCRIPTION_CRON;
    
      if ($debug_cron) {
        error_log(sprintf('Holiday Cron Pause Subscription Debug: Started processing the cron to pause subscription on order ID %s.', $order_id));
      }
    
      // Do something to pause subcription, and log it as you go
    });
    

    Do the same for start_the_woo_subcription.

    I believe your cron wasn’t working because of the fatal error on the handler, but either way, now you should have a much better insight if the cron event isn’t working, where, and why.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search