Search

How To Create Custom status for WooCommerce Subscription Plugin

    Karthik Thayyil
Listen to this article

In today’s article, I will show you how to extend WooCommerce Subscription plugin to create custom statuses. I will be creating a new WooCommerce Subscription status called `Like On Hold` which works similarly like `On Hold`.

Let’s begin!

#1 First step it to register new status in subscription using the woocommerce_subscriptions_registered_statuses action as shown below:

add_filter('woocommerce_subscriptions_registered_statuses','register_new_post_status', 100, 1);
 
function register_new_post_status($registered_statuses) {
 $registered_statuses['wc-like-on-hold'] = _nx_noop('Like On Hold <span class="count">(%s)</span>', 'Like On Hold <span class="count">(%s)</span>', 'post status label including post count', 'custom-wcs-status-texts');
 return $registered_statuses;
}

#2 In order to make this status visible in the status drop-down on the subscription page, you need to add it to the subscription statuses list using the ‘wcs_subscription_statuses’ filter as shown below:

add_filter('wcs_subscription_statuses', 'add_new_subscription_statuses', 100, 1);
 
function add_new_subscription_statuses($subscription_statuses) {
 $subscription_statuses['wc-like-on-hold'] = _x('Like On Hold', 'Subscription status', 'custom-wcs-status-texts');
 return $subscription_statuses;
}

For the visibility of the new status in the drop-down you need to specify if the subscription with a particular status can be updated to the new status or not. This can be done using the ‘woocommerce_subscription_status_updated’.  

add_filter('woocommerce_can_subscription_be_updated_to', 'extends_can_be_updated', 100, 3);
 
function extends_can_be_updated($can_be_updated, $new_status, $subscription) {
 if ($new_status=='like-on-hold') {
  if ($subscription->payment_method_supports('subscription_suspension') && $subscription->has_status(array('active', 'pending', 'on-hold'))) {
   $can_be_updated = true;
  } else {
   $can_be_updated = false;
  }
 }
 return $can_be_updated;
}

[space]

#3 Now, in order to perform an action when admin selects `Like On Hold` from the drop-down and updates the subscription we have to extend update_status function using ‘woocommerce_subscription_status_updated’ action. Here we will just copy paste the same code as on-hold status.

 
add_action('woocommerce_subscription_status_updated', 'extends_update_status', 100, 3);
 
function extends_update_status($subscription, $new_status, $old_status) {
 if ($new_status == 'like-on-hold') {
  $subscription->update_suspension_count($subscription->suspension_count + 1);
  wcs_maybe_make_user_inactive($subscription->customer_user);
 }
}
 

Here ends the basic code to set up a new status called `Like On Hold` in WooCommerce subscription.

Now, let us handle some more things like, showing a particular status in the drop-down of a subscription whose current status is `Like On Hold`, and adding the new status to bulk action on the list page and to handle it.

 
add_filter('woocommerce_can_subscription_be_updated_to_active', 'enable_active_in_new_statuses', 100, 2);
 
add_filter('woocommerce_can_subscription_be_updated_to_on-hold', 'enable_on_hold_in_new_statuses', 100, 2);
 
function enable_active_in_new_statuses($can_be_updated, $subscription) {
 if ($subscription->payment_method_supports('subscription_reactivation') && $subscription->has_status(array('on-hold', 'like-on-hold'))) {
  $can_be_updated = true;
 } elseif ($subscription->has_status('pending')) {
  $can_be_updated = true;
 } else {
  $can_be_updated = false;
 }
 return $can_be_updated;
}
 
function enable_on_hold_in_new_statuses($can_be_updated, $subscription) {
 if ($subscription->payment_method_supports('subscription_suspension') && $subscription->has_status(array('active', 'pending', 'like-on-hold'))) {
  $can_be_updated = true;
 } else {
  $can_be_updated = false;
 }
 return $can_be_updated;
}

[space]

#4 Adding the new status to bulk action drop-down on the subscription list page using ‘woocommerce_subscription_bulk_actions’ filter.

add_filter('woocommerce_subscription_bulk_actions', 'add_new_status_bulk_actions', 100, 1);
 
function add_new_status_bulk_actions($bulk_actions) {
 $bulk_actions['like-on-hold'] = _x('Mark Like On Hold', 'an action on a subscription', 'custom-wcs-status-texts');
 return $bulk_actions;
}

[space]

#5 The following code deals with handling bulk actions. The style is similar to what WooCommerce is doing. Extensions will have to define their own logic by copying the concept behind the method written in woocommerce subscription plugin. The function is hooked to wordpress core’s ‘load-edit.php’ action.

 
add_action('load-edit.php', 'parse_bulk_actions');
 
function parse_bulk_actions() {
 
 
 // We only want to deal with shop_subscriptions. In case any other CPTs have an 'active' action
 if (!isset($_REQUEST['post_type']) || 'shop_subscription' !== $_REQUEST['post_type'] || !isset($_REQUEST['post'])) {
  return;
 }
 
 $action = '';
 
 if (isset($_REQUEST['action']) && -1 != $_REQUEST['action']) {
  $action = $_REQUEST['action'];
 } elseif (isset($_REQUEST['action2']) && -1 != $_REQUEST['action2']) {
  $action = $_REQUEST['action2'];
 }
 
 switch ($action) {
  case 'active':
  case 'on-hold':
  case 'cancelled':
  case 'like-on-hold':
   $new_status = $action;
   break;
  default:
   return;
 }
 
 $report_action = 'marked_' . $new_status;
 
 $changed = 0;
 
 $subscription_ids = array_map('absint', (array) $_REQUEST['post']);
 
 $sendback_args = array(
  'post_type' => 'shop_subscription',
  $report_action => true,
  'ids' => join(',', $subscription_ids),
  'error_count' => 0,
  );
 
 foreach ($subscription_ids as $subscription_id) {
  $subscription = wcs_get_subscription($subscription_id);
  $order_note = _x('Subscription status changed by bulk edit:', 'Used in order note. Reason why status changed.', 'woocommerce-subscriptions');
 
  try {
   if ('cancelled' == $action) {
    $subscription->cancel_order($order_note);
   } else {
    $subscription->update_status($new_status, $order_note, true);
   }
 
   // Fire the action hooks
   switch ($action) {
    case 'active':
    case 'on-hold':
    case 'cancelled':
    case 'like-on-hold':
    case 'trash':
     do_action('woocommerce_admin_changed_subscription_to_' . $action, $subscription_id);
     break;
   }
 
   $changed++;
  } catch (Exception $e) {
   $sendback_args['error'] = urlencode($e->getMessage());
   $sendback_args['error_count']++;
  }
 }
 
 $sendback_args['changed'] = $changed;
 $sendback = add_query_arg($sendback_args, wp_get_referer() ? wp_get_referer() : '');
 wp_safe_redirect(esc_url_raw($sendback));
 
 exit();
}

We have handled most of the major functionalities at WooCommerce subscription end. Now, what if we want the same status in WooCommerce order? And in case the status of the order is “update to new status”, how do we mark all the subscription in it with the new status (if possible)? 

Then, here’s how we should proceed.

1) Register new status in WooCommerce.

Here we are going to register the same status as of WooCommerce subscription.

add_action('init', 'register_like_on_hold_order_statuses');
 
function register_like_on_hold_order_statuses() {
 register_post_status('wc-like-on-hold', array(
  'label' => _x('Like On Hold', 'Order status', 'custom-wcs-status-texts'),
  'public' => true,
  'exclude_from_search' => false,
  'show_in_admin_all_list' => true,
  'show_in_admin_status_list' => true,
  'label_count' => _n_noop('Like On Hold <span class="count">(%s)</span>', 'Like On Hold<span class="count">(%s)</span>', 'woocommerce'),
 ));
}

[space]

2) Add this new status to the order statuses list using the ‘wc_order_statuses’ filter

add_filter('wc_order_statuses', 'like_on_hold_wc_order_statuses', 100, 1);
function like_on_hold_wc_order_statuses($order_statuses) {
 $order_statuses['wc-like-on-hold'] = _x('Like On Hold', 'Order status', 'custom-wcs-status-texts');
 return $order_statuses;
}

[space]

3) Once the order status is changed to the new status we want the status of all the subscription within the order to be changed to the new status. We can do this using the ‘woocommerce_order_status_’. $new_status action as shown below.

add_action('woocommerce_order_status_like-on-hold', array($this, 'put_subscription_on_like_on_hold_for_order'), 100);
 
function put_subscription_on_like_on_hold_for_order($order) {
 
 $subscriptions = wcs_get_subscriptions_for_order($order, array('order_type' => 'parent'));
 
 if (!empty($subscriptions)) {
  foreach ($subscriptions as $subscription) {
   try {
    if (!$subscription->has_status(wcs_get_subscription_ended_statuses())) {
     $subscription->update_status('like-on-hold');
    }
   } catch (Exception $e) {
    // translators: $1: order number, $2: error message
    $subscription->add_order_note(sprintf(__('Failed to update subscription status after order #%1$s was put to like-on-hold: %2$s', 'woocommerce-subscriptions'), is_object($order) ? $order->get_order_number() : $order, $e->getMessage()));
   }
  }
  // Added a new action the same way subscription plugin has added for on-hold
  do_action('subscriptions_put_to_like_on_hold_for_order', $order);
 }
}

Implementation of this code with a more detailed explanation of each and every function can be found in our git repository custom-woocommerce-subscription-status

That’s it!. If you have any queries, just shoot a comment and I will get back to you.

Till then, happy coding. 🙂

 

 

Picture of Karthik Thayyil

Karthik Thayyil

6 Responses

  1. Cool! that it solves your problem. You can also check the git for the demo plugin (link at the end of the article). I have mentioned a few more useful hooks in the git version. Hope that helps even more.

    1. Hi Karthik !
      That’s awesome.
      Can you please help me in 1 thing ?
      I just want to add some code when we reactivate the Subscription manually. Please tell me which hook i need to use ?

  2. I want to add some code when we reactivate the subscription manually from the Subscription list.
    Can you please tell me the hook ?

  3. Your code is working great…However once the original status is reverted after first billing cycle, renewal orders not created for any further cycles.
    Just confirming that if the order status changes and subscription cycles from Custom status to Active status, renewal order will be generated for the next cycle?

  4. Hi, I tried the code and works really well, thanks! I was wondering if there’s a way to make this custom status work as an active, so the user can edit the subscription and add products to it but orders are suspended.

Leave a Reply

Your email address will not be published. Required fields are marked *

Get The Latest Updates

Subscribe to our Newsletter

A key to unlock the world of open-source. We promise not to spam your inbox.

Suggested Reads

Join our 55,000+ Subscribers

    The Wisdm Digest delivers all the latest news, and resources from the world of open-source businesses to your inbox.

    Suggested Reads