Search code examples
phpwordpresswoocommercewoocommerce-subscriptions

Updating and Synchronizing Woocommerce Subscriptions to Custom Date


We have a client who is shipping Subscription products (which are actually Composite products with four to five Bundles of products in them) and they offer delivery on a weekly basis. Their delivery date is always Thursdays. Woocommerce Subscriptions allows for synchronization to a specific date, so we've chosen the "Align Subscription Renewal Day" option and, in a given Product, we've set it to go on Thursdays for each option ("every 4th week", "every 3rd week", etc.)

Screenshot of a product synchronization setting

The caveat with our situation is that orders received the day before (Wednesday) or on the Thursday itself can't be fulfilled that week and need to have their start date/delivery date bumped to the following Thursday. To that end, we've written a function for functions.php using the woocommerce_subscriptions_product_first_renewal_payment_time hook:

<?php
function rem_check_renewal_date( $first_renewal_timestamp, $product_id, $from_date_param, $timezone ) {

  if ( date('D') == 'Wed' || date('D') == 'Thu' ) {

    $from_date_param = strtotime('Thursday next week');
    return $from_date_param;

  } else {

    // Nothing needs to be done, because we must be on a Fri thru Tue
    return;

  }

}

add_filter( 'woocommerce_subscriptions_product_first_renewal_payment_time', 'rem_check_renewal_date', 10, 4);
?>

Now that we've done that, we can see some fields on the checkout seem to be updating correctly. For example, under Next Payment date (which we altered to say Next Delivery) it correctly shows the next week and not today (which happens to be a Thursday at time of writing). Screenshot of Cart

But not all fields/columnar values in the Subscriptions dashboard are changed. For instance, the actual Start Date column shows the date the order was received.

Screenshot of Subscriptions overview

You can also see in the confirmation email that Woocommerce sends that the Start Date is listed as the current date though "Next payment" is moved by a week as per our hook.

Email order confirmation screenshot

When we placed test orders on a Wednesday, the Start Date column showed Wednesday. That makes sense if it's real use is as the "Order Received" date, so my question is this:

Which (if any) other columns and/or values need to be updated so that orders received the day before or the day of deliveries are moved to next week? We need to ensure that the subsequent orders stay on the 2-week, 3-week, 4-week schedule and line up with the changed first payment date. But I'm not sure if changing only the first payment date with that hook above is enough and the documentation doesn't go into further detail.


Solution

  • There is a function exposed by the WC_Subscription object called update_dates() which takes an array of date keys matching the values used in the Subscriptions list dashboard (and other areas).

    The function signature is WC_Subscription::update_dates( $dates, $timezone ). I believe an object must be instantiated; I don't think this method can be called statically. Subscriptions function reference here.

    The documented parameters (as keys to be passed in the $dates array) are:

    1. start
    2. trial_end
    3. next_payment
    4. last_payment
    5. end

    The array itself is required, but I don't believe each individual key needs to be populated with a value. For instance, default orders generated by the Subscriptions plugin often have no trial_end or end dates (unless separately configured that way).

    Using an action hook such as woocommerce_checkout_subscription_created (Subscriptions action reference) you could use the $subscription argument, which is an instance of WC_Subscription, and do something like:

    function push_subscriptions_to_next_week($subscription, $order, $recurring_cart) {
        // The new date calculation of +7 days is just an example
        $new_dates = array(
            'start' => date('Y-m-d H:i:s', strtotime('+7 days', time())),
            'next_payment' => date('Y-m-d H:i:s', strtotime('+7 days', time()))
        );
    
        $subscription->update_dates($new_dates, 'site');
    }
    
    add_action( 'woocommerce_checkout_subscription_created', 'push_subscriptions_to_next_week', 10, 3);
    

    The dates are required to be in a MySQL date/time format (Y-m-d H:i:s) so I've updated the code example to reflect that.