/** * 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; }
/** * 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; }