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