/**
  * Process the change payment form.
  *
  * Based on the @see woocommerce_pay_action() function.
  *
  * @access public
  * @return void
  * @since 1.4
  */
 public static function change_payment_method_via_pay_shortcode()
 {
     global $woocommerce;
     if (isset($_POST['woocommerce_change_payment']) && wp_verify_nonce($_POST['_wpnonce'], 'woocommerce-change_payment')) {
         $subscription_key = $_POST['woocommerce_change_payment'];
         // Pay for existing order
         $order_key = isset($_GET['key']) ? $_GET['key'] : $_GET['order'];
         $order_id = absint($_GET['order_id']);
         $order = new WC_Order($order_id);
         do_action('woocommerce_subscriptions_change_payment_method_via_pay_shortcode', $subscription_key, $order);
         ob_start();
         if ($order->id == $order_id && $order->order_key == $order_key) {
             // Set customer location to order location
             if ($order->billing_country) {
                 $woocommerce->customer->set_country($order->billing_country);
             }
             if ($order->billing_state) {
                 $woocommerce->customer->set_state($order->billing_state);
             }
             if ($order->billing_postcode) {
                 $woocommerce->customer->set_postcode($order->billing_postcode);
             }
             if ($order->billing_city) {
                 $woocommerce->customer->set_city($order->billing_city);
             }
             // Update payment method
             $new_payment_method = woocommerce_clean($_POST['payment_method']);
             self::update_recurring_payment_method($subscription_key, $order, $new_payment_method);
             $available_gateways = $woocommerce->payment_gateways->get_available_payment_gateways();
             // Validate
             $available_gateways[$new_payment_method]->validate_fields();
             // Process payment for the new method (with a $0 order total)
             if (function_exists('wc_notice_count')) {
                 // WC 2.1
                 if (wc_notice_count('error') == 0) {
                     $result = $available_gateways[$new_payment_method]->process_payment($order_id);
                     // Redirect to success/confirmation/payment page
                     if ($result['result'] == 'success') {
                         WC_Subscriptions::add_notice(__('Payment method updated.', 'woocommerce-subscriptions'), 'success');
                         wp_redirect($result['redirect']);
                         exit;
                     }
                 }
             } else {
                 if ($woocommerce->error_count() == 0) {
                     $result = $available_gateways[$new_payment_method]->process_payment($order_id);
                     // Redirect to success/confirmation/payment page
                     if ($result['result'] == 'success') {
                         WC_Subscriptions::add_notice(__('Payment method updated.', 'woocommerce-subscriptions'), 'success');
                         wp_redirect($result['redirect']);
                         exit;
                     }
                 }
             }
         }
     }
 }
 /**
  * When a product is added to the cart, check if it is being added to switch a subscription and if so,
  * make sure it's valid (i.e. not the same subscription).
  *
  * @since 1.4
  */
 public static function validate_switch_request($is_valid, $product_id, $quantity, $variation_id = '')
 {
     global $woocommerce;
     if (!isset($_GET['switch-subscription'])) {
         return $is_valid;
     }
     $subscription = WC_Subscriptions_Manager::get_subscription($_GET['switch-subscription']);
     if ($product_id == $subscription['product_id'] && (empty($variation_id) || $variation_id == $subscription['variation_id'])) {
         WC_Subscriptions::add_notice(__('You can not switch to the same subscription.', 'woocommerce-subscriptions'), 'error');
         $is_valid = false;
     }
     return $is_valid;
 }
 /**
  * Process the change payment form.
  *
  * Based on the @see woocommerce_pay_action() function.
  *
  * @access public
  * @return void
  * @since 1.4
  */
 public static function change_payment_method_via_pay_shortcode()
 {
     if (isset($_POST['_wcsnonce']) && wp_verify_nonce($_POST['_wcsnonce'], 'wcs_change_payment_method')) {
         $subscription = wcs_get_subscription(absint($_POST['woocommerce_change_payment']));
         do_action('woocommerce_subscription_change_payment_method_via_pay_shortcode', $subscription);
         ob_start();
         if ($subscription->order_key == $_GET['key']) {
             // Set customer location to order location
             if ($subscription->billing_country) {
                 WC()->customer->set_country($subscription->billing_country);
             }
             if ($subscription->billing_state) {
                 WC()->customer->set_state($subscription->billing_state);
             }
             if ($subscription->billing_postcode) {
                 WC()->customer->set_postcode($subscription->billing_postcode);
             }
             if ($subscription->billing_city) {
                 WC()->customer->set_city($subscription->billing_city);
             }
             // Update payment method
             $new_payment_method = woocommerce_clean($_POST['payment_method']);
             // Allow some payment gateways which can't process the payment immediately, like PayPal, to do it later after the payment/sign-up is confirmed
             if (apply_filters('woocommerce_subscriptions_update_payment_via_pay_shortcode', true, $new_payment_method, $subscription)) {
                 self::update_payment_method($subscription, $new_payment_method);
             }
             $available_gateways = WC()->payment_gateways->get_available_payment_gateways();
             // Validate
             $available_gateways[$new_payment_method]->validate_fields();
             // Process payment for the new method (with a $0 order total)
             if (wc_notice_count('error') == 0) {
                 $result = $available_gateways[$new_payment_method]->process_payment($subscription->id);
                 $result = apply_filters('woocommerce_subscriptions_process_payment_for_change_method_via_pay_shortcode', $result, $subscription);
                 // Redirect to success/confirmation/payment page
                 if ('success' == $result['result']) {
                     WC_Subscriptions::add_notice(__('Payment method updated.', 'woocommerce-subscriptions'), 'success');
                     wp_redirect($result['redirect']);
                     exit;
                 }
             }
         }
     }
 }
 /**
  * Checks if the current request is by a user to change the status of their subscription, and if it is
  * validate the subscription cancellation request and maybe processes the cancellation. 
  *
  * @since 1.0
  */
 public static function maybe_change_users_subscription()
 {
     global $woocommerce;
     if (isset($_GET['change_subscription_to']) && isset($_GET['subscription_key']) && isset($_GET['_wpnonce'])) {
         $user_id = get_current_user_id();
         $subscription = self::get_subscription($_GET['subscription_key']);
         if (wp_verify_nonce($_GET['_wpnonce'], $_GET['subscription_key']) === false) {
             WC_Subscriptions::add_notice(sprintf(__('That subscription can not be changed to %s. Please contact us if you need assistance.', 'woocommerce-subscriptions'), $_GET['change_subscription_to']), 'error');
         } elseif (empty($subscription)) {
             WC_Subscriptions::add_notice(__('That doesn\'t appear to be one of your subscriptions.', 'woocommerce-subscriptions'), 'error');
         } elseif (!WC_Subscriptions_Manager::can_subscription_be_changed_to($_GET['change_subscription_to'], $_GET['subscription_key'], $user_id)) {
             WC_Subscriptions::add_notice(sprintf(__('That subscription can not be changed to %s. Please contact us if you need assistance.', 'woocommerce-subscriptions'), $_GET['change_subscription_to']), 'error');
         } elseif (!in_array($_GET['change_subscription_to'], array('active', 'on-hold', 'cancelled'))) {
             WC_Subscriptions::add_notice(sprintf(__('Unknown subscription status: "%s". Please contact us if you need assistance.', 'woocommerce-subscriptions'), $_GET['change_subscription_to']), 'error');
         } else {
             switch ($_GET['change_subscription_to']) {
                 case 'active':
                     if (WC_Subscriptions_Manager::subscription_requires_payment($_GET['subscription_key'], $user_id)) {
                         WC_Subscriptions::add_notice(sprintf(__('You can not reactive that subscription until paying to renew it. Please contact us if you need assistance.', 'woocommerce-subscriptions'), $_GET['change_subscription_to']), 'error');
                     } else {
                         self::reactivate_subscription($user_id, $_GET['subscription_key']);
                         $status_message = __('reactivated', 'woocommerce-subscriptions');
                     }
                     break;
                 case 'on-hold':
                     if (self::current_user_can_suspend_subscription($_GET['subscription_key'])) {
                         self::put_subscription_on_hold($user_id, $_GET['subscription_key']);
                         $status_message = __('suspended', 'woocommerce-subscriptions');
                     } else {
                         WC_Subscriptions::add_notice(sprintf(__('You can not suspend that subscription - the suspension limit has been reached. Please contact us if you need assistance.', 'woocommerce-subscriptions'), $_GET['change_subscription_to']), 'error');
                     }
                     break;
                 case 'cancelled':
                     self::cancel_subscription($user_id, $_GET['subscription_key']);
                     $status_message = __('cancelled', 'woocommerce-subscriptions');
                     break;
             }
             if (isset($status_message)) {
                 $order = new WC_Order($subscription['order_id']);
                 $order->add_order_note(sprintf(__('The status of subscription %s was changed to %s by the subscriber from their account page.', 'woocommerce-subscriptions'), $_GET['subscription_key'], $_GET['change_subscription_to']));
                 WC_Subscriptions::add_notice(sprintf(__('Your subscription has been %s.', 'woocommerce-subscriptions'), $status_message), 'success');
             }
         }
         wp_safe_redirect(get_permalink(woocommerce_get_page_id('myaccount')));
         exit;
     }
 }
 /**
  * When a subscription switch is added to the cart, store a record of pertinent meta about the switch.
  *
  * @since 1.4
  */
 public static function set_switch_details_in_cart($cart_item_data, $product_id, $variation_id)
 {
     try {
         if (!isset($_GET['switch-subscription'])) {
             return $cart_item_data;
         }
         $subscription = wcs_get_subscription($_GET['switch-subscription']);
         // Requesting a switch for someone elses subscription
         if (!current_user_can('switch_shop_subscription', $subscription->id)) {
             WC_Subscriptions::add_notice(__('You can not switch this subscription. It appears you do not own the subscription.', 'woocommerce-subscriptions'), 'error');
             WC()->cart->empty_cart(true);
             wp_redirect(get_permalink($subscription['product_id']));
             exit;
         }
         $item = wcs_get_order_item(absint($_GET['item']), $subscription);
         // Else it's a valid switch
         $product = wc_get_product($item['product_id']);
         $child_products = 0 !== $product->post->post_parent ? wc_get_product($product->post->post_parent)->get_children() : array();
         if ($product_id != $item['product_id'] && !in_array($item['product_id'], $child_products)) {
             return $cart_item_data;
         }
         $next_payment_timestamp = $subscription->get_time('next_payment');
         // If there are no more payments due on the subscription, because we're in the last billing period, we need to use the subscription's expiration date, not next payment date
         if (false == $next_payment_timestamp) {
             $next_payment_timestamp = $subscription->get_time('end');
         }
         $cart_item_data['subscription_switch'] = array('subscription_id' => $subscription->id, 'item_id' => absint($_GET['item']), 'next_payment_timestamp' => $next_payment_timestamp, 'upgraded_or_downgraded' => '');
         return $cart_item_data;
     } catch (Exception $e) {
         WC_Subscriptions::add_notice(__('There was an error locating the switch details.', 'woocommerce-subscriptions'), 'error');
         WC()->cart->empty_cart(true);
         wp_redirect(get_permalink(wc_get_page_id('cart')));
         exit;
     }
 }
 /**
  * Checks if the user's current request to change the status of their subscription is valid.
  *
  * @since 2.0
  */
 public static function validate_request($user_id, $subscription, $new_status, $wpnonce = '')
 {
     $subscription = !is_object($subscription) ? wcs_get_subscription($subscription) : $subscription;
     if (!wcs_is_subscription($subscription)) {
         WC_Subscriptions::add_notice(__('That subscription does not exist. Please contact us if you need assistance.', 'woocommerce-subscriptions'), 'error');
         return false;
     } elseif (!empty($wpnonce) && wp_verify_nonce($wpnonce, $subscription->id . $subscription->get_status()) === false) {
         WC_Subscriptions::add_notice(__('Security error. Please contact us if you need assistance.', 'woocommerce-subscriptions'), 'error');
         return false;
     } elseif (!user_can($user_id, 'edit_shop_subscription_status', $subscription->id)) {
         WC_Subscriptions::add_notice(__('That doesn\'t appear to be one of your subscriptions.', 'woocommerce-subscriptions'), 'error');
         return false;
     } elseif (!$subscription->can_be_updated_to($new_status)) {
         // translators: placeholder is subscription's new status, translated
         WC_Subscriptions::add_notice(sprintf(__('That subscription can not be changed to %s. Please contact us if you need assistance.', 'woocommerce-subscriptions'), wcs_get_subscription_status_name($new_status)), 'error');
         return false;
     }
     return true;
 }
 /**
  * When a subscription switch is added to the cart, store a record of pertinent meta about the switch.
  *
  * @since 1.4
  */
 public static function set_switch_details_in_cart($cart_item_data, $product_id, $variation_id)
 {
     global $woocommerce;
     if (!isset($_GET['switch-subscription'])) {
         return $cart_item_data;
     }
     $subscription = WC_Subscriptions_Manager::get_subscription($_GET['switch-subscription']);
     // Requesting a switch for someone elses subscription
     if (!WC_Subscriptions_Manager::user_owns_subscription($_GET['switch-subscription'])) {
         WC_Subscriptions::add_notice(__('You can not switch this subscription. It appears you do not own the subscription.', 'woocommerce-subscriptions'), 'error');
         $woocommerce->cart->empty_cart(true);
         wp_redirect(get_permalink($subscription['product_id']));
         exit;
     }
     // Else it's a valid switch
     $product = get_product($subscription['product_id']);
     $child_products = 0 !== $product->post->post_parent ? get_product($product->post->post_parent)->get_children() : array();
     if ($product_id != $subscription['product_id'] && !in_array($subscription['product_id'], $child_products)) {
         return $cart_item_data;
     }
     $next_payment_timestamp = WC_Subscriptions_Manager::get_next_payment_date($_GET['switch-subscription'], get_current_user_id(), 'timestamp');
     // If there are no more payments due on the subscription, because we're in the last billing period, we need to use the subscription's expiration date, not next payment date
     if (false == $next_payment_timestamp && WC_Subscriptions_Manager::get_subscriptions_completed_payment_count($_GET['switch-subscription']) >= WC_Subscriptions_Order::get_subscription_length($subscription['order_id'], $subscription['product_id'])) {
         $next_payment_timestamp = WC_Subscriptions_Manager::get_subscription_expiration_date($_GET['switch-subscription'], get_current_user_id(), 'timestamp');
     }
     $cart_item_data['subscription_switch'] = array('subscription_key' => $_GET['switch-subscription'], 'next_payment_timestamp' => $next_payment_timestamp, 'upgraded_or_downgraded' => '');
     return $cart_item_data;
 }
 /**
  * Check if a payment is being made on a failed renewal order from 'My Account'. If so,
  * redirect the order into a cart/checkout payment flow.
  *
  * @since 1.3
  */
 public static function before_woocommerce_pay()
 {
     global $woocommerce, $wp;
     if (isset($_GET['pay_for_order']) && (isset($_GET['order']) && isset($_GET['order_id']) || isset($_GET['key']) && isset($wp->query_vars['order-pay']))) {
         // Pay for existing order
         $order_key = isset($_GET['key']) ? $_GET['key'] : $_GET['order'];
         // WC 2.1 compatibility
         $order_id = isset($wp->query_vars['order-pay']) ? $wp->query_vars['order-pay'] : absint($_GET['order_id']);
         $order = new WC_Order($order_id);
         $failed_order_replaced_by = get_post_meta($order_id, '_failed_order_replaced_by', true);
         if (is_numeric($failed_order_replaced_by)) {
             WC_Subscriptions::add_notice(sprintf(__('Sorry, this failed order has already been paid. See order %s.', 'woocommerce-subscriptions'), $failed_order_replaced_by), 'error');
             wp_safe_redirect(get_permalink(woocommerce_get_page_id('myaccount')));
             exit;
         }
         if ($order->id == $order_id && $order->order_key == $order_key && in_array($order->status, array('pending', 'failed')) && WC_Subscriptions_Renewal_Order::is_renewal($order)) {
             // If order being paid is a parent order, get the original order, else query parent_order
             if (WC_Subscriptions_Renewal_Order::is_renewal($order_id, array('order_role' => 'parent'))) {
                 $role = 'parent';
                 $original_order = new WC_Order(WC_Subscriptions_Order::get_meta($order, 'original_order', false));
             } elseif (WC_Subscriptions_Renewal_Order::is_renewal($order_id, array('order_role' => 'child'))) {
                 $role = 'child';
                 $original_order = WC_Subscriptions_Renewal_Order::get_parent_order($order_id);
             }
             $order_items = WC_Subscriptions_Order::get_recurring_items($original_order);
             $first_order_item = reset($order_items);
             $product_id = WC_Subscriptions_Order::get_items_product_id($first_order_item);
             $product = get_product($product_id);
             $variation_id = '';
             $variation_data = array();
             // Display error message for deleted products
             if (false === $product) {
                 WC_Subscriptions::add_notice(self::$product_deleted_error_message, 'error');
                 // Make sure we don't actually need the variation ID
             } elseif ($product->is_type(array('variable-subscription'))) {
                 $item = WC_Subscriptions_Order::get_item_by_product_id($original_order, $product_id);
                 $variation_id = $item['variation_id'];
                 $variation = get_product($variation_id);
                 // Display error message for deleted product variations
                 if (false === $variation) {
                     WC_Subscriptions::add_notice(self::$product_deleted_error_message, 'error');
                     $variation_data = array();
                 } else {
                     $variation_data = $variation->get_variation_attributes();
                 }
             } elseif ($product->is_type(array('subscription_variation'))) {
                 // Handle existing renewal orders incorrectly using variation_id as the product_id
                 $product_id = $product->id;
                 $variation_id = $product->get_variation_id();
                 $variation_data = $product->get_variation_attributes();
             }
             $woocommerce->cart->empty_cart(true);
             $woocommerce->cart->add_to_cart($product_id, 1, $variation_id, $variation_data, array('subscription_renewal' => array('original_order' => $original_order->id, 'failed_order' => $order_id, 'role' => $role)));
             wp_safe_redirect($woocommerce->cart->get_checkout_url());
             exit;
         }
     }
 }