/** * Gets all the active and inactive subscriptions for a user, as specified by $user_id * * @param int $user_id (optional) The id of the user whose subscriptions you want. Defaults to the currently logged in user. * @param array $order_ids (optional) An array of post_ids of WC_Order objects as a way to get only subscriptions for certain orders. Defaults to null, which will return subscriptions for all orders. * @since 1.0 */ public static function get_users_subscriptions($user_id = 0, $order_ids = array()) { _deprecated_function(__METHOD__, '2.0', 'wcs_get_users_subscriptions( $user_id )'); $subscriptions_in_old_format = array(); foreach (wcs_get_users_subscriptions($user_id) as $subscription) { $subscriptions_in_old_format[wcs_get_old_subscription_key($subscription)] = wcs_get_subscription_in_deprecated_structure($subscription); } return apply_filters('woocommerce_users_subscriptions', $subscriptions_in_old_format, $user_id); }
/** * Handles the subscription upgrade/downgrade process. * * @since 1.4 */ public static function subscription_switch_handler() { global $post; // If the current user doesn't own the subscription, remove the query arg from the URL if (isset($_GET['switch-subscription'])) { $subscription = wcs_get_subscription($_GET['switch-subscription']); // Visiting a switch link for someone elses subscription or if the switch link doesn't contain a valid nonce if (!is_object($subscription) || !current_user_can('switch_shop_subscription', $subscription->id) || empty($_GET['_wcsnonce']) || !wp_verify_nonce($_GET['_wcsnonce'], 'wcs_switch_request') || 'no' === get_option(WC_Subscriptions_Admin::$option_prefix . '_allow_switching', 'no')) { wp_redirect(remove_query_arg(array('switch-subscription', 'auto-switch', 'item', '_wcsnonce'))); exit; } else { if (isset($_GET['auto-switch'])) { $switch_message = __('You have a subscription to this product. Choosing a new subscription will replace your existing subscription.', 'woocommerce-subscriptions'); } else { $switch_message = __('Choose a new subscription.', 'woocommerce-subscriptions'); } WC_Subscriptions::add_notice($switch_message, 'notice'); } } elseif ((is_cart() || is_checkout()) && !is_order_received_page() && false !== ($switch_items = self::cart_contains_switches())) { $removed_item_count = 0; foreach ($switch_items as $cart_item_key => $switch_item) { $subscription = wcs_get_subscription($switch_item['subscription_id']); if (!is_object($subscription) || !current_user_can('switch_shop_subscription', $subscription->id) || !wcs_is_product_switchable_type(WC()->cart->cart_contents[$cart_item_key]['data'])) { WC()->cart->remove_cart_item($cart_item_key); $removed_item_count++; } } if ($removed_item_count > 0) { WC_Subscriptions::add_notice(_n('Your cart contained an invalid subscription switch request. It has been removed.', 'Your cart contained invalid subscription switch requests. They have been removed.', $removed_item_count, 'woocommerce-subscriptions'), 'error'); wp_redirect(WC()->cart->get_cart_url()); exit; } } elseif (is_product() && ($product = wc_get_product($post))) { // Automatically initiate the switch process for limited variable subscriptions if (wcs_is_product_switchable_type($product) && 'no' != $product->limit_subscriptions) { // Check if the user has an active subscription for this product, and if so, initiate the switch process $subscriptions = wcs_get_users_subscriptions(); $child_ids = $product->get_children(); foreach ($subscriptions as $subscription) { // If we're on a grouped product's page, we need to check if the subscription has a child of this grouped product that needs to be switched $subscription_product_id = false; if ($product->is_type('grouped')) { foreach ($child_ids as $child_id) { if ($subscription->has_product($child_id)) { $subscription_product_id = $child_id; break; } } } if ($subscription->has_product($product->id) || $subscription_product_id) { // For grouped products, we need to check the child products limitations, not the grouped product's (which will have no limitation) if ($subscription_product_id) { $child_product = wc_get_product($subscription_product_id); $limitation = $child_product->limit_subscriptions; } else { $limitation = $product->limit_subscriptions; } // If the product is limited if ('any' == $limitation || $subscription->has_status($limitation) || 'active' == $limitation && $subscription->has_status('on-hold')) { $subscribed_notice = __('You have already subscribed to this product and it is limited to one per customer. You can not purchase the product again.', 'woocommerce-subscriptions'); // If switching is enabled for this product type, initiate the auto-switch process if (wcs_is_product_switchable_type($product)) { // Don't initiate auto-switching when the subscription requires payment if ($subscription->needs_payment()) { $last_order = $subscription->get_last_order('all'); if ($last_order->needs_payment()) { // translators: 1$: is the "You have already subscribed to this product" notice, 2$-4$: opening/closing link tags, 3$: an order number $subscribed_notice = sprintf(__('%1$s Complete payment on %2$sOrder %3$s%4$s to be able to change your subscription.', 'woocommerce-subscriptions'), $subscribed_notice, sprintf('<a href="%s">', $last_order->get_checkout_payment_url()), $last_order->get_order_number(), '</a>'); } WC_Subscriptions::add_notice($subscribed_notice, 'notice'); break; } else { $product_id = $subscription_product_id ? $subscription_product_id : $product->id; // Get the matching item foreach ($subscription->get_items() as $line_item_id => $line_item) { if ($line_item['product_id'] == $product_id || $line_item['variation_id'] == $product_id) { $item_id = $line_item_id; $item = $line_item; break; } } wp_redirect(add_query_arg('auto-switch', 'true', self::get_switch_url($item_id, $item, $subscription))); exit; } } else { WC_Subscriptions::add_notice($subscribed_notice, 'notice'); break; } } } } } } }
/** * Loads the my-subscriptions.php template on the My Account page. * * @since 1.0 */ public static function get_my_subscriptions_template() { $subscriptions = wcs_get_users_subscriptions(); $user_id = get_current_user_id(); wc_get_template('myaccount/my-subscriptions.php', array('subscriptions' => $subscriptions, 'user_id' => $user_id), '', plugin_dir_path(__FILE__) . 'templates/'); }
/** * Get the subscriptions tied to a user payment token. * * @since 4.3.0 * @param int $user_id the user * @param \SV_WC_Payment_Gateway_Payment_Token the token object * @return array the subscriptions or an empty array */ protected function get_payment_token_subscriptions($user_id, $token) { $subscriptions = wcs_get_users_subscriptions($user_id); $token_key = 'wc_' . $this->get_gateway()->get_id() . '_payment_token'; foreach ($subscriptions as $key => $subscription) { if ((string) $token->get_id() !== (string) $subscription->{$token_key}) { unset($subscriptions[$key]); } } return $subscriptions; }
/** * Compare the user's subscriptions end date with the date * the user was added to the course. If the user was added after * the subscription ended they were manually added and this will return * true. * * Important to note that all subscriptions for the user is compared. * * @since 1.9.0 * * @param $user_id * @param $product_id * @param $course_id * * @return bool */ public static function was_user_added_without_subscription($user_id, $product_id, $course_id) { $course_start_date = ''; $subscription_start_date = ''; $is_a_subscription = ''; $was_user_added_without_subscription = true; // if user is not on the course they were not added if (!Sensei_Utils::user_started_course($course_id, $user_id)) { return false; } // if user doesn't have a subscription and is taking the course // they were added manually if (!wcs_user_has_subscription($user_id, $product_id) && Sensei_Utils::user_started_course($course_id, get_current_user_id())) { return true; } $course_status = Sensei_Utils::user_course_status($course_id, $user_id); // comparing dates setup data $course_start_date = date_create($course_status->comment_date); $subscriptions = wcs_get_users_subscriptions($user_id); // comparing every subscription foreach ($subscriptions as $subscription) { // for the following statuses we know the user was not added // manually $status = $subscription->get_status(); if (in_array($status, array('pending-canceled', 'active', 'on-hold', 'pending'))) { continue; } $current_subscription_start_date = date_create($subscription->modified_date); // is the last updated subscription date newer than course start date if ($current_subscription_start_date > $course_start_date) { return false; } } return $was_user_added_without_subscription; }
/** * When a subscriber's billing or shipping address is successfully updated, check if the subscriber * has also requested to update the addresses on existing subscriptions and if so, go ahead and update * the addresses on the initial order for each subscription. * * @param int $user_id The ID of a user who own's the subscription (and address) * @since 1.3 */ public static function maybe_update_subscription_addresses($user_id, $address_type) { if (!wcs_user_has_subscription($user_id) || wc_notice_count('error') > 0 || empty($_POST['_wcsnonce']) || !wp_verify_nonce($_POST['_wcsnonce'], 'wcs_edit_address')) { return; } $address_type = 'billing' == $address_type || 'shipping' == $address_type ? $address_type : ''; $address_fields = WC()->countries->get_address_fields(esc_attr($_POST[$address_type . '_country']), $address_type . '_'); $address = array(); foreach ($address_fields as $key => $field) { if (isset($_POST[$key])) { $address[str_replace($address_type . '_', '', $key)] = woocommerce_clean($_POST[$key]); } } if (isset($_POST['update_all_subscriptions_addresses'])) { $users_subscriptions = wcs_get_users_subscriptions($user_id); foreach ($users_subscriptions as $subscription) { if ($subscription->has_status(array('active', 'on-hold'))) { $subscription->set_address($address, $address_type); } } } elseif (isset($_POST['update_subscription_address'])) { $subscription = wcs_get_subscription(intval($_POST['update_subscription_address'])); // Update the address only if the user actually owns the subscription if (!empty($subscription)) { $subscription->set_address($address, $address_type); } wp_safe_redirect($subscription->get_view_order_url()); exit; } }
/** * 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; }
/** * Check if a user has a subscription, optionally to a specific product and/or with a certain status. * * @param int (optional) The ID of a user in the store. If left empty, the current user's ID will be used. * @param int (optional) The ID of a product in the store. If left empty, the function will see if the user has any subscription. * @param string (optional) A valid subscription status. If left empty, the function will see if the user has a subscription of any status. * @since 2.0 */ function wcs_user_has_subscription($user_id = 0, $product_id = '', $status = 'any') { $subscriptions = wcs_get_users_subscriptions($user_id); $has_subscription = false; if (empty($product_id)) { // Any subscription if (!empty($status) && 'any' != $status) { // We need to check for a specific status foreach ($subscriptions as $subscription) { if ($subscription->get_status() == $status) { $has_subscription = true; break; } } } elseif (!empty($subscriptions)) { $has_subscription = true; } } else { foreach ($subscriptions as $subscription) { if ($subscription->has_product($product_id) && (empty($status) || 'any' == $status || $subscription->get_status() == $status)) { $has_subscription = true; break; } } } return apply_filters('wcs_user_has_subscription', $has_subscription, $user_id, $product_id, $status); }
/** * Returns a URL including required parameters for an authenticated user to renew a subscription by product ID. * * @param int $product_id The ID of a product post type. * @since 1.2 */ function wcs_get_users_resubscribe_link_for_product($product_id) { $renewal_url = ''; if (is_user_logged_in()) { foreach (wcs_get_users_subscriptions() as $subscription) { foreach ($subscription->get_items() as $line_item) { if (($line_item['product_id'] == $product_id || $line_item['variation_id'] == $product_id) && wcs_can_user_resubscribe_to($subscription)) { $renewal_url = wcs_get_users_resubscribe_link($subscription); break; } } } } return apply_filters('wcs_users_resubscribe_link_for_product', $renewal_url, $product_id); }
/** * Callback for the [subscriptions] shortcode that displays subscription names for a particular user. * * @param array $attributes Shortcode attributes. * @return string */ public static function do_subscriptions_shortcode($attributes) { $attributes = wp_parse_args($attributes, array('user_id' => 0, 'status' => 'active')); $subscriptions = wcs_get_users_subscriptions($attributes['user_id']); if (empty($subscriptions)) { return '<ul class="user-subscriptions no-user-subscriptions"> <li>No subscriptions found.</li> </ul>'; } $list = '<ul class="user-subscriptions">'; foreach ($subscriptions as $subscription) { if ('all' == $attributes['status'] || $subscription->has_status($attributes['status'])) { $list .= sprintf('<li><a href="%s">Subscription %s</a></li>', $subscription->get_view_order_url(), $subscription->get_order_number()); } } $list .= '</ul>'; return $list; }
/** * @param array $data * @return void */ public function jwt_auth_token_before_sign($data = array()) { $subs = wcs_get_users_subscriptions(); $sub_data = array(); if (count($subs)) { foreach ($subs as $sub) { $sub = wcs_get_subscription($sub); $order = wc_get_order($sub->order); if ($sub->get_status() === 'active') { if (count($sub->get_items())) { foreach ($sub->get_items() as $item) { $variation_id = isset($item['variation_id']) ? $item['variation_id'] : ''; $attrs = wc_get_product_variation_attributes($variation_id); if (count($attrs)) { foreach ($attrs as $name => $value) { $term = get_term_by('slug', $value, str_replace('attribute_', '', $name)); $name = str_replace('-', '_', $name); $name = str_replace('attribute_pa_', '', $name); $sub_data[$name] = $term->name; } } $end_date = $sub->get_time('next_payment'); // $end_date = date('Y-m-d', $end_date); $sub_data['end_date'] = isset($sub_data['end_date']) && $end_date <= $sub_data['end_date'] ? $sub_data['end_date'] : $end_date; } } } } } $data['user'] = array_merge($data['user'], $sub_data); return $data; }
/** * Callback for the [subscriptions] shortcode that displays subscription names for a particular user. * * @param array $attributes Shortcode attributes. * @return string */ public static function do_subscriptions_shortcode($attributes) { $attributes = wp_parse_args($attributes, array('user_id' => 0, 'status' => 'active')); $status = $attributes['status']; $subscriptions = wcs_get_users_subscriptions($attributes['user_id']); if (empty($subscriptions)) { return '<ul class="user-subscriptions no-user-subscriptions"> <li>No subscriptions found.</li> </ul>'; } $list = '<ul class="user-subscriptions">'; foreach ($subscriptions as $subscription) { if ($subscription['status'] == $status || 'all' == $status) { $subscription_details = WC_Subscriptions_Order::get_item_name($subscription['order_id'], $subscription['product_id']); $order = new WC_Order($subscription['order_id']); $order_item = WC_Subscriptions_Order::get_item_by_product_id($subscription['order_id'], $subscription['product_id']); $product = $order->get_product_from_item($order_item); if (isset($product->variation_data)) { $subscription_details .= ' <span class="subscription-variation-data">(' . woocommerce_get_formatted_variation($product->variation_data, true) . ')</span>'; } $list .= sprintf('<li>%s</li>', $subscription_details); } } $list .= '</ul>'; return $list; }
/** * Callback for the [subscriptions] shortcode that displays subscription names for a particular user. * * @param array $attributes Shortcode attributes. * @return string */ public static function do_subscriptions_shortcode($attributes) { $attributes = wp_parse_args($attributes, array('user_id' => 0, 'status' => 'active')); $subscriptions = wcs_get_users_subscriptions($attributes['user_id']); if (empty($subscriptions)) { return '<ul class="user-subscriptions no-user-subscriptions"> <li>' . esc_html_x('No subscriptions found.', 'in [subscriptions] shortcode', 'woocommerce-subscriptions') . '</li> </ul>'; } $list = '<ul class="user-subscriptions">'; foreach ($subscriptions as $subscription) { if ('all' == $attributes['status'] || $subscription->has_status($attributes['status'])) { // translators: order number $shortcode_translate = sprintf(esc_html_x('Subscription %s', 'in [subscriptions] shortcode', 'woocommerce-subscriptions'), $subscription->get_order_number()); $list .= sprintf('<li><a href="%s">%s</a></li>', $subscription->get_view_order_url(), $shortcode_translate); } } $list .= '</ul>'; return $list; }