/**
  * Returns an array of order IDs for valid orders that grant group
  * membership for the given group to the user related to the order.
  * 
  * @param int $user_id
  * @param int $group_id
  * @return array of int, order IDs
  */
 public static function get_valid_order_ids_granting_group_membership_from_order_items($user_id, $group_id)
 {
     $order_ids = array();
     if (!empty($user_id)) {
         $base_statuses = array('processing', 'completed');
         $statuses = array('completed');
         $options = get_option('groups-woocommerce', array());
         $order_status = isset($options[GROUPS_WS_MEMBERSHIP_ORDER_STATUS]) ? $options[GROUPS_WS_MEMBERSHIP_ORDER_STATUS] : GROUPS_WS_DEFAULT_MEMBERSHIP_ORDER_STATUS;
         if ($order_status == 'processing') {
             $statuses[] = 'processing';
         }
         // DO NOT use groups_ws_order_status( $statuses ) for $statuses or $base_statuses here,
         // $order->status doesn't provide the wc- prefix.
         $groups_product_groups = get_user_meta($user_id, '_groups_product_groups', true);
         if (empty($groups_product_groups)) {
             $groups_product_groups = array();
         }
         foreach ($groups_product_groups as $order_id => $product_ids) {
             if ($order = Groups_WS_Helper::get_order($order_id)) {
                 // If this is a completed/processing order, consider group assignments.
                 // We check the order status for non-subscription products below,
                 // for subscriptions the subscription status is checked.
                 if (in_array($order->status, $base_statuses)) {
                     // Note that for orders placed with versions up to 1.4.1, the following won't give the results we might expect if the product group-related information has changed since the order was placed.
                     // As we don't store that information (WC doesn't store the whole lot of the product when purchased, nor does GW) checking the duration based on the product is the best effort at
                     // finding out about the group membership duration we can make.
                     // Use the order items (only existing order items are taken into account).
                     if ($items = $order->get_items()) {
                         foreach ($items as $item) {
                             if ($product = $order->get_product_from_item($item)) {
                                 // Use the groups that were stored for the product when it was ordered,
                                 // this avoids hickups when the product's groups were changed since.
                                 if (isset($product_ids[$product->id]) && isset($product_ids[$product->id]['groups'])) {
                                     $product_groups = $product_ids[$product->id]['groups'];
                                     if (in_array($group_id, $product_groups)) {
                                         // non-subscriptions
                                         if (!class_exists('WC_Subscriptions_Product') || !WC_Subscriptions_Product::is_subscription($product->id)) {
                                             if (in_array($order->status, $statuses)) {
                                                 if (isset($product_ids[$product->id]) && isset($product_ids[$product->id]['version'])) {
                                                     $has_duration = isset($product_ids[$product->id]['duration']) && $product_ids[$product->id]['duration'] && isset($product_ids[$product->id]['duration_uom']);
                                                 } else {
                                                     $has_duration = Groups_WS_Product::has_duration($product);
                                                 }
                                                 // unlimited membership
                                                 if (!$has_duration) {
                                                     if (!in_array($order_id, $order_ids)) {
                                                         $order_ids[] = $order_id;
                                                     }
                                                 } else {
                                                     if (isset($product_ids[$product->id]) && isset($product_ids[$product->id]['version'])) {
                                                         $duration = Groups_WS_Product::calculate_duration($product_ids[$product->id]['duration'], $product_ids[$product->id]['duration_uom']);
                                                     } else {
                                                         // <= 1.4.1
                                                         $duration = Groups_WS_Product::get_duration($product);
                                                     }
                                                     // time-limited membership
                                                     if ($duration) {
                                                         $start_date = $order->order_date;
                                                         if ($paid_date = get_post_meta($order_id, '_paid_date', true)) {
                                                             $start_date = $paid_date;
                                                         }
                                                         $end = strtotime($start_date) + $duration;
                                                         if (time() < $end) {
                                                             if (!in_array($order_id, $order_ids)) {
                                                                 $order_ids[] = $order_id;
                                                             }
                                                         }
                                                     }
                                                 }
                                             }
                                         } else {
                                             // include active subscriptions ( subscriptions >= 2.x )
                                             if (function_exists('wcs_get_subscriptions_for_order')) {
                                                 if ($subscriptions = wcs_get_subscriptions_for_order($order_id)) {
                                                     if (is_array($subscriptions)) {
                                                         foreach ($subscriptions as $subscription) {
                                                             if ($subscription->has_product($product->id)) {
                                                                 $valid = false;
                                                                 if ($subscription->get_status() == 'active') {
                                                                     $valid = true;
                                                                 } else {
                                                                     if ($subscription->get_status() == 'cancelled') {
                                                                         $hook_args = array('subscription_id' => $subscription->id);
                                                                         $end_timestamp = wp_next_scheduled('scheduled_subscription_end_of_prepaid_term', $hook_args);
                                                                         if ($end_timestamp !== false && $end_timestamp > time()) {
                                                                             $valid = true;
                                                                         }
                                                                     }
                                                                 }
                                                                 if ($valid) {
                                                                     if (!in_array($order_id, $order_ids)) {
                                                                         $order_ids[] = $order_id;
                                                                         break;
                                                                     }
                                                                 }
                                                             }
                                                         }
                                                     }
                                                 }
                                             } else {
                                                 $subscription_key = WC_Subscriptions_Manager::get_subscription_key($order_id, $product->id);
                                                 $subscription = WC_Subscriptions_Manager::get_subscription($subscription_key);
                                                 if (isset($subscription['status'])) {
                                                     $valid = false;
                                                     if ($subscription['status'] == 'active') {
                                                         $valid = true;
                                                     } else {
                                                         if ($subscription['status'] == 'cancelled') {
                                                             $hook_args = array('user_id' => (int) $user_id, 'subscription_key' => $subscription_key);
                                                             $end_timestamp = wp_next_scheduled('scheduled_subscription_end_of_prepaid_term', $hook_args);
                                                             if ($end_timestamp !== false && $end_timestamp > time()) {
                                                                 $valid = true;
                                                             }
                                                         }
                                                     }
                                                     if ($valid) {
                                                         if (!in_array($order_id, $order_ids)) {
                                                             $order_ids[] = $order_id;
                                                         }
                                                     }
                                                 }
                                             }
                                         }
                                     }
                                 }
                             }
                         }
                     }
                 }
             }
         }
     }
     return $order_ids;
 }
/**
 * Returns the order status key for the $status given.
 * 
 * @param string|array $status order status or statuses
 * @return string|array WooCommerce order status key or keys, null or an empty array if no valid statuses were provided
 */
function groups_ws_order_status($status)
{
    $return_array = is_array($status);
    $statuses = $status;
    if (!is_array($status)) {
        $statuses = array($status);
    }
    $wc_statuses = array();
    foreach ($statuses as $status) {
        $wc_status = Groups_WS_Helper::get_order_status($status);
        if ($wc_status !== null) {
            $wc_statuses[] = $wc_status;
        }
    }
    $result = $wc_statuses;
    if (!$return_array) {
        $result = array_shift($wc_statuses);
    }
    return $result;
}
 /**
  * Renders a table with subscription information.
  * @param array $options
  * @param int $n will be set to the number of subscriptions found
  */
 public static function render($options, &$n)
 {
     global $wpdb;
     $output = '';
     if (isset($options['user_id'])) {
         $user = new WP_User($options['user_id']);
     } else {
         return $output;
     }
     $statuses = array('active');
     $show_all = false;
     if (isset($options['status'])) {
         $status = $options['status'];
         if (is_string($status)) {
             if (trim($status) === '*') {
                 $statuses = array('active', 'on-hold', 'cancelled', 'trash', 'deleted', 'switched');
             } else {
                 $statuses = array();
                 $_statuses = explode(',', $status);
                 foreach ($_statuses as $status) {
                     $status = strtolower(trim($status));
                     switch ($status) {
                         case 'active':
                         case 'on-hold':
                         case 'cancelled':
                         case 'trash':
                         case 'deleted':
                         case 'switched':
                             $statuses[] = $status;
                             break;
                     }
                 }
             }
         }
     }
     $exclude_cancelled_after_end_of_prepaid_term = isset($options['exclude_cancelled_after_end_of_prepaid_term']) && ($options['exclude_cancelled_after_end_of_prepaid_term'] === true || $options['exclude_cancelled_after_end_of_prepaid_term'] == 'true' || $options['exclude_cancelled_after_end_of_prepaid_term'] == 'yes');
     $include_cancelled_orders = isset($options['include_cancelled_orders']) && ($options['include_cancelled_orders'] === true || $options['include_cancelled_orders'] == 'true' || $options['include_cancelled_orders'] == 'yes');
     $include_refunded_orders = isset($options['include_refunded_orders']) && ($options['include_refunded_orders'] === true || $options['include_refunded_orders'] == 'true' || $options['include_refunded_orders'] == 'yes');
     if (function_exists('wcs_get_users_subscriptions')) {
         $results = array();
         foreach (wcs_get_users_subscriptions($user->ID) as $subscription) {
             $results[wcs_get_old_subscription_key($subscription)] = wcs_get_subscription_in_deprecated_structure($subscription);
         }
     } else {
         $results = WC_Subscriptions_Manager::get_users_subscriptions($user->ID);
     }
     // pre-filter by status
     $_results = array();
     foreach ($results as $result_key => $result) {
         $valid = false;
         if (in_array($result['status'], $statuses)) {
             $valid = true;
         }
         // exclude subscriptions from cancelled or refunded orders
         if (isset($result['order_id'])) {
             if ($order = Groups_WS_Helper::get_order($result['order_id'])) {
                 switch ($order->status) {
                     case 'cancelled':
                         if (!$include_cancelled_orders) {
                             $valid = false;
                         }
                         break;
                     case 'refunded':
                         if (!$include_refunded_orders) {
                             $valid = false;
                         }
                         break;
                 }
             }
         }
         if ($exclude_cancelled_after_end_of_prepaid_term && $result['status'] == 'cancelled') {
             $hook_args = array('user_id' => (int) $user->ID, 'subscription_key' => $result_key);
             $end_timestamp = wp_next_scheduled('scheduled_subscription_end_of_prepaid_term', $hook_args);
             if ($end_timestamp === false || $end_timestamp <= time()) {
                 $valid = false;
             }
         }
         if ($valid) {
             $_results[$result_key] = $result;
         }
     }
     $results = $_results;
     $n = count($results);
     if ($n > 0) {
         $column_display_names = array('status' => __('Status', GROUPS_WS_PLUGIN_DOMAIN), 'title' => __('Subscription', GROUPS_WS_PLUGIN_DOMAIN), 'start_date' => __('Start Date', GROUPS_WS_PLUGIN_DOMAIN), 'expiry_date' => __('Expiration', GROUPS_WS_PLUGIN_DOMAIN), 'end_date' => __('End Date', GROUPS_WS_PLUGIN_DOMAIN), 'trial_expiry_date' => __('Trial Expiration', GROUPS_WS_PLUGIN_DOMAIN), 'groups' => __('Groups', GROUPS_WS_PLUGIN_DOMAIN), 'order_id' => __('Order', GROUPS_WS_PLUGIN_DOMAIN));
         if (isset($options['columns']) && $options['columns'] !== null) {
             if (is_string($options['columns'])) {
                 $columns = explode(',', $options['columns']);
                 $_columns = array();
                 foreach ($columns as $column) {
                     $_columns[] = trim($column);
                 }
                 $options['columns'] = $_columns;
             }
             $new_columns = array();
             foreach ($options['columns'] as $key) {
                 if (key_exists($key, $column_display_names)) {
                     $new_columns[$key] = $column_display_names[$key];
                 }
             }
             $column_display_names = $new_columns;
         }
         if (count($column_display_names) > 0) {
             $output .= '<table class="subscriptions">';
             $output .= '<thead>';
             $output .= '<tr>';
             foreach ($column_display_names as $key => $column_display_name) {
                 $output .= "<th scope='col' class='{$key}'>{$column_display_name}</th>";
             }
             $output .= '</tr>';
             $output .= '</thead>';
             $output .= '<tbody>';
             $i = 0;
             foreach ($results as $result_key => $result) {
                 $order = Groups_WS_Helper::get_order($result['order_id']);
                 if ($order) {
                     $order_item = WC_Subscriptions_Order::get_item_by_product_id($order, $result['product_id']);
                     $product = $order->get_product_from_item($order_item);
                     $output .= '<tr class="' . ($i % 2 == 0 ? 'even' : 'odd') . '">';
                     foreach ($column_display_names as $column_key => $column_title) {
                         $output .= sprintf('<td class="%s">', $column_key);
                         switch ($column_key) {
                             case 'status':
                                 $output .= WC_Subscriptions_Manager::get_status_to_display($result['status'], $result_key, $user->ID);
                                 break;
                             case 'title':
                                 $output .= WC_Subscriptions_Order::get_item_name($result['order_id'], $result['product_id']);
                                 if (isset($product->variation_data)) {
                                     $column_content .= '<br />';
                                     if (function_exists('wc_get_formatted_variation')) {
                                         $column_content .= wc_get_formatted_variation($product->variation_data, true);
                                     } else {
                                         $column_content .= woocommerce_get_formatted_variation($product->variation_data, true);
                                     }
                                 }
                                 break;
                             case 'start_date':
                             case 'expiry_date':
                             case 'end_date':
                                 if ($column_key == 'expiry_date' && $result[$column_key] == 0) {
                                     $output .= __('Never', GROUPS_WS_PLUGIN_DOMAIN);
                                 } else {
                                     if ($column_key == 'end_date' && $result[$column_key] == 0) {
                                         $output .= __('Not yet ended', GROUPS_WS_PLUGIN_DOMAIN);
                                     } else {
                                         $user_timestamp = strtotime($result[$column_key]) + get_option('gmt_offset') * 3600;
                                         $output .= sprintf('<time title="%s">%s</time>', esc_attr($user_timestamp), date_i18n(get_option('date_format'), $user_timestamp));
                                     }
                                 }
                                 break;
                             case 'trial_expiry_date':
                                 $trial_expiration = WC_Subscriptions_Manager::get_trial_expiration_date($result_key, $user->ID, 'timestamp');
                                 if (empty($trial_expiration)) {
                                     $output .= '-';
                                 } else {
                                     $trial_expiration = $trial_expiration + get_option('gmt_offset') * 3600;
                                     $output .= sprintf('<time title="%s">%s</time>', esc_attr($trial_expiration), date_i18n(get_option('date_format'), $trial_expiration));
                                 }
                                 break;
                             case 'groups':
                                 if ($product_groups = get_post_meta($result['product_id'], '_groups_groups', false)) {
                                     if (count($product_groups) > 0) {
                                         $output .= '<ul>';
                                         foreach ($product_groups as $group_id) {
                                             if ($group = Groups_Group::read($group_id)) {
                                                 $output .= '<li>' . wp_filter_nohtml_kses($group->name) . '</li>';
                                             }
                                         }
                                         $output .= '</ul>';
                                     }
                                 }
                                 break;
                             case 'order_id':
                                 $output .= sprintf(__('Order %d', GROUPS_WS_PLUGIN_DOMAIN), $result['order_id']);
                                 break;
                         }
                         $output .= '</td>';
                     }
                     $output .= '</tr>';
                     $i++;
                 }
             }
             $output .= '</tbody>';
             $output .= '</table>';
         }
     }
     return $output;
 }