/**
  * Print admin styles/scripts
  */
 public function enqueue_styles_scripts()
 {
     global $post;
     // Get admin screen id
     $screen = get_current_screen();
     if ('shop_subscription' == $screen->id) {
         wp_register_script('jstz', plugin_dir_url(WC_Subscriptions::$plugin_file) . '/assets/js/admin/jstz.min.js');
         wp_register_script('momentjs', plugin_dir_url(WC_Subscriptions::$plugin_file) . '/assets/js/admin/moment.min.js');
         wp_enqueue_script('wcs-admin-meta-boxes-subscription', plugin_dir_url(WC_Subscriptions::$plugin_file) . '/assets/js/admin/meta-boxes-subscription.js', array('wc-admin-meta-boxes', 'jstz', 'momentjs'), WC_VERSION);
         wp_localize_script('wcs-admin-meta-boxes-subscription', 'wcs_admin_meta_boxes', apply_filters('woocommerce_subscriptions_admin_meta_boxes_script_parameters', array('i18n_start_date_notice' => __('Please enter a start date in the past.', 'woocommerce-subscriptions'), 'i18n_past_date_notice' => __('Please enter a date at least one hour into the future.', 'woocommerce-subscriptions'), 'i18n_next_payment_start_notice' => __('Please enter a date after the trial end.', 'woocommerce-subscriptions'), 'i18n_next_payment_trial_notice' => __('Please enter a date after the start date.', 'woocommerce-subscriptions'), 'i18n_trial_end_start_notice' => __('Please enter a date after the start date.', 'woocommerce-subscriptions'), 'i18n_trial_end_next_notice' => __('Please enter a date before the next payment.', 'woocommerce-subscriptions'), 'i18n_end_date_notice' => __('Please enter a date after the next payment.', 'woocommerce-subscriptions'), 'process_renewal_action_warning' => __("Are you sure you want to process a renewal?\n\nThis will charge the customer and email them the renewal order (if emails are enabled).", 'woocommerce-subscriptions'), 'payment_method' => wcs_get_subscription($post)->payment_method, 'search_customers_nonce' => wp_create_nonce('search-customers'))));
     }
 }
 /**
  * Find all subscription with a given billing agreement ID and cancel them becasue that billing agreement has been
  * cancelled at PayPal, and therefore, no future payments can be charged.
  *
  * @since 2.0
  */
 protected function cancel_subscriptions($billing_agreement_id)
 {
     $subscription_ids = get_posts(array('posts_per_page' => -1, 'post_type' => 'shop_subscription', 'post_status' => 'any', 'fields' => 'ids', 'orderby' => 'date', 'order' => 'DESC', 'meta_query' => array(array('key' => '_paypal_subscription_id', 'compare' => '=', 'value' => $billing_agreement_id))));
     if (empty($subscription_ids)) {
         return;
     }
     $note = esc_html__('Billing agreement cancelled at PayPal.', 'woocommerce-subscriptions');
     foreach ($subscription_ids as $subscription_id) {
         $subscription = wcs_get_subscription($subscription_id);
         try {
             if (false !== $subscription && !$subscription->has_status(wcs_get_subscription_ended_statuses())) {
                 $subscription->cancel_order($note);
                 WC_Gateway_Paypal::log(sprintf('Subscription %s Cancelled: %s', $subscription_id, $note));
             }
         } catch (Exception $e) {
             WC_Gateway_Paypal::log(sprintf('Unable to cancel subscription %s: %s', $subscription_id, $e->getMessage()));
         }
     }
 }
 /**
  * Filter the "Orders" list to show only orders associated with a specific subscription.
  *
  * @param string $where
  * @param string $request
  * @return string
  * @since 2.0
  */
 public static function filter_orders($where)
 {
     global $typenow, $wpdb;
     if (is_admin() && 'shop_order' == $typenow) {
         $related_orders = array();
         if (isset($_GET['_subscription_related_orders']) && $_GET['_subscription_related_orders'] > 0) {
             $subscription_id = absint($_GET['_subscription_related_orders']);
             $subscription = wcs_get_subscription($subscription_id);
             if (!wcs_is_subscription($subscription)) {
                 // translators: placeholder is a number
                 wcs_add_admin_notice(sprintf(__('We can\'t find a subscription with ID #%d. Perhaps it was deleted?', 'woocommerce-subscriptions'), $subscription_id), 'error');
                 $where .= " AND {$wpdb->posts}.ID = 0";
             } else {
                 self::$found_related_orders = true;
                 $where .= sprintf(" AND {$wpdb->posts}.ID IN (%s)", implode(',', array_map('absint', array_unique($subscription->get_related_orders('ids')))));
             }
         }
     }
     return $where;
 }
 /**
  * Save meta box data
  */
 public static function save($post_id, $post)
 {
     if ('shop_subscription' == $post->post_type && !empty($_POST['woocommerce_meta_nonce']) && wp_verify_nonce($_POST['woocommerce_meta_nonce'], 'woocommerce_save_data')) {
         if (isset($_POST['_billing_interval'])) {
             update_post_meta($post_id, '_billing_interval', $_POST['_billing_interval']);
         }
         if (!empty($_POST['_billing_period'])) {
             update_post_meta($post_id, '_billing_period', $_POST['_billing_period']);
         }
         $subscription = wcs_get_subscription($post_id);
         $dates = array();
         foreach (wcs_get_subscription_date_types() as $date_key => $date_label) {
             if ('last_payment' == $date_key) {
                 continue;
             }
             $utc_timestamp_key = $date_key . '_timestamp_utc';
             // A subscription needs a start date, even if it wasn't set
             if (isset($_POST[$utc_timestamp_key])) {
                 $datetime = $_POST[$utc_timestamp_key];
             } elseif ('start' === $date_key) {
                 $datetime = current_time('timestamp', true);
             } else {
                 // No date to set
                 continue;
             }
             $dates[$date_key] = date('Y-m-d H:i:s', $datetime);
         }
         try {
             $subscription->update_dates($dates, 'gmt');
             wp_cache_delete($post_id, 'posts');
         } catch (Exception $e) {
             wcs_add_admin_notice($e->getMessage(), 'error');
         }
     }
 }
 /**
  * Displays the renewal orders in the Related Orders meta box.
  *
  * @param object $post A WordPress post
  * @since 2.0
  */
 public static function output_rows($post)
 {
     $subscriptions = array();
     $orders = array();
     // On the subscription page, just show related orders
     if (wcs_is_subscription($post->ID)) {
         $subscriptions[] = wcs_get_subscription($post->ID);
     } elseif (wcs_order_contains_subscription($post->ID, array('parent', 'renewal'))) {
         $subscriptions = wcs_get_subscriptions_for_order($post->ID, array('order_type' => array('parent', 'renewal')));
     }
     // First, display all the subscriptions
     foreach ($subscriptions as $subscription) {
         $subscription->relationship = __('Subscription', 'woocommerce-subscriptions');
         $orders[] = $subscription;
     }
     //Resubscribed
     $initial_subscriptions = array();
     if (wcs_is_subscription($post->ID)) {
         $initial_subscriptions = wcs_get_subscriptions_for_resubscribe_order($post->ID);
         $resubscribed_subscriptions = get_posts(array('meta_key' => '_subscription_resubscribe', 'meta_value' => $post->ID, 'post_type' => 'shop_subscription', 'post_status' => 'any', 'posts_per_page' => -1));
         foreach ($resubscribed_subscriptions as $subscription) {
             $subscription = wcs_get_subscription($subscription);
             $subscription->relationship = _x('Resubscribed Subscription', 'relation to order', 'woocommerce-subscriptions');
             $orders[] = $subscription;
         }
     } else {
         if (wcs_order_contains_subscription($post->ID, array('resubscribe'))) {
             $initial_subscriptions = wcs_get_subscriptions_for_order($post->ID, array('order_type' => array('resubscribe')));
         }
     }
     foreach ($initial_subscriptions as $subscription) {
         $subscription->relationship = _x('Initial Subscription', 'relation to order', 'woocommerce-subscriptions');
         $orders[] = $subscription;
     }
     // Now, if we're on a single subscription or renewal order's page, display the parent orders
     if (1 == count($subscriptions)) {
         foreach ($subscriptions as $subscription) {
             if (false !== $subscription->order) {
                 $subscription->order->relationship = _x('Parent Order', 'relation to order', 'woocommerce-subscriptions');
                 $orders[] = $subscription->order;
             }
         }
     }
     // Finally, display the renewal orders
     foreach ($subscriptions as $subscription) {
         foreach ($subscription->get_related_orders('all', 'renewal') as $order) {
             $order->relationship = _x('Renewal Order', 'relation to order', 'woocommerce-subscriptions');
             $orders[] = $order;
         }
     }
     $orders = apply_filters('woocommerce_subscriptions_admin_related_orders_to_display', $orders, $subscriptions, $post);
     foreach ($orders as $order) {
         if ($order->id == $post->ID) {
             continue;
         }
         include 'views/html-related-orders-row.php';
     }
 }
 /**
  * Process the remove or re-add a line item from a subscription request.
  *
  * @since 2.0
  */
 public static function maybe_remove_or_add_item_to_subscription()
 {
     if (isset($_GET['subscription_id']) && (isset($_GET['remove_item']) || isset($_GET['undo_remove_item'])) && isset($_GET['_wpnonce'])) {
         $subscription = wcs_is_subscription($_GET['subscription_id']) ? wcs_get_subscription($_GET['subscription_id']) : false;
         $undo_request = isset($_GET['undo_remove_item']) ? true : false;
         $item_id = $undo_request ? $_GET['undo_remove_item'] : $_GET['remove_item'];
         if (false === $subscription) {
             wc_add_notice(sprintf(_x('Subscription #%d does not exist.', 'hash before subscription ID', 'woocommerce-subscriptions'), $_GET['subscription_id']), 'error');
             wp_safe_redirect(wc_get_page_permalink('myaccount'));
             exit;
         }
         if (self::validate_remove_items_request($subscription, $item_id, $undo_request)) {
             if ($undo_request) {
                 // handle undo request
                 $removed_item = WC()->session->get('removed_subscription_items', array());
                 if (!empty($removed_item[$item_id]) && $subscription->id == $removed_item[$item_id]) {
                     // restore the item
                     wc_update_order_item($item_id, array('order_item_type' => 'line_item'));
                     unset($removed_item[$item_id]);
                     WC()->session->set('removed_subscription_items', $removed_item);
                     // restore download permissions for this item
                     $line_items = $subscription->get_items();
                     $line_item = $line_items[$item_id];
                     $_product = $subscription->get_product_from_item($line_item);
                     $product_id = wcs_get_canonical_product_id($line_item);
                     if ($_product && $_product->exists() && $_product->is_downloadable()) {
                         $downloads = $_product->get_files();
                         foreach (array_keys($downloads) as $download_id) {
                             wc_downloadable_file_permission($download_id, $product_id, $subscription, $line_item['qty']);
                         }
                     }
                     // translators: 1$: product name, 2$: product id
                     $subscription->add_order_note(sprintf(_x('Customer added "%1$s" (Product ID: #%2$d) via the My Account page.', 'used in order note', 'woocommerce-subscriptions'), wcs_get_line_item_name($line_item), $product_id));
                 } else {
                     wc_add_notice(__('Your request to undo your previous action was unsuccessful.', 'woocommerce-subscriptions'));
                 }
             } else {
                 // handle remove item requests
                 WC()->session->set('removed_subscription_items', array($item_id => $subscription->id));
                 // remove download access for the item
                 $line_items = $subscription->get_items();
                 $line_item = $line_items[$item_id];
                 $product_id = wcs_get_canonical_product_id($line_item);
                 WCS_Download_Handler::revoke_downloadable_file_permission($product_id, $subscription->id, $subscription->get_user_id());
                 // remove the line item from subscription but preserve its data in the DB
                 wc_update_order_item($item_id, array('order_item_type' => 'line_item_removed'));
                 // translators: 1$: product name, 2$: product id
                 $subscription->add_order_note(sprintf(_x('Customer removed "%1$s" (Product ID: #%2$d) via the My Account page.', 'used in order note', 'woocommerce-subscriptions'), wcs_get_line_item_name($line_item), $product_id));
                 // translators: placeholders are 1$: item name, and, 2$: opening and, 3$: closing link tags
                 wc_add_notice(sprintf(__('You have successfully removed "%1$s" from your subscription. %2$sUndo?%3$s', 'woocommerce-subscriptions'), $line_item['name'], '<a href="' . esc_url(self::get_undo_remove_url($subscription->id, $item_id, $subscription->get_view_order_url())) . '" >', '</a>'));
             }
         }
         $subscription->calculate_totals();
         wp_safe_redirect($subscription->get_view_order_url());
         exit;
     }
 }
示例#7
0
/**
 * Get the subscriptions that had an item switch for a given order (if any).
 *
 * @param int|WC_Order $order_id The post_id of a shop_order post or an instance of a WC_Order object
 * @return array Subscription details in post_id => WC_Subscription form.
 * @since  2.0
 */
function wcs_get_subscriptions_for_switch_order($order_id)
{
    if (is_object($order_id)) {
        $order_id = $order_id->id;
    }
    $subscriptions = array();
    $subscription_ids = get_post_meta($order_id, '_subscription_switch', false);
    foreach ($subscription_ids as $subscription_id) {
        $subscriptions[$subscription_id] = wcs_get_subscription($subscription_id);
    }
    return $subscriptions;
}
/**
 * Return an instance of a WC_Subscription object for the given subscription key (if one exists).
 *
 * @param string $subscription_key A subscription key in the deprecated form created by @see self::get_subscription_key()
 * @return WC_Subscription|null The subscription object if it can be found (i.e. an order exists) or null if no order exists for the subscription (i.e. it was manually created).
 * @since 2.0
 */
function wcs_get_subscription_from_key($subscription_key)
{
    $subscription_id = wcs_get_subscription_id_from_key($subscription_key);
    if (null !== $subscription_id && is_numeric($subscription_id)) {
        $subscription = wcs_get_subscription($subscription_id);
    }
    if (!is_object($subscription)) {
        // translators: placeholder is either subscription key or a subscription id, or, failing that, empty (e.g. "145_21" or "145")
        throw new InvalidArgumentException(sprintf(__('Could not get subscription. Most likely the subscription key does not refer to a subscription. The key was: "%s".', 'woocommerce-subscriptions'), $subscription_key));
    }
    return $subscription;
}
 /**
  * Set the subscription page title when viewing a subscription.
  *
  * @since 2.0
  * @param $title
  */
 public function get_endpoint_title($endpoint)
 {
     global $wp;
     switch ($endpoint) {
         case 'view-subscription':
             $subscription = wcs_get_subscription($wp->query_vars['view-subscription']);
             $title = $subscription ? sprintf(_x('Subscription #%s', 'hash before order number', 'woocommerce-subscriptions'), $subscription->get_order_number()) : '';
             break;
         default:
             $title = '';
             break;
     }
     return $title;
 }
 /**
  * Check whether the cart needs payment even if the order total is $0 because it's a subscription switch request for a subscription using
  * PayPal Standard as the subscription.
  *
  * @param bool $needs_payment The existing flag for whether the cart needs payment or not.
  * @param WC_Cart $cart The WooCommerce cart object.
  * @return bool
  */
 public static function cart_needs_payment($needs_payment, $cart)
 {
     $cart_switch_items = WC_Subscriptions_Switcher::cart_contains_switches();
     if (false === $needs_payment && 0 == $cart->total && false !== $cart_switch_items && 'yes' !== get_option(WC_Subscriptions_Admin::$option_prefix . '_turn_off_automatic_payments', 'no')) {
         foreach ($cart_switch_items as $cart_switch_details) {
             $subscription = wcs_get_subscription($cart_switch_details['subscription_id']);
             if ('paypal' === $subscription->payment_method && !wcs_is_paypal_profile_a(wcs_get_paypal_id($subscription->id), 'billing_agreement')) {
                 $needs_payment = true;
                 break;
             }
         }
     }
     return $needs_payment;
 }
 /**
  * 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) === 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)) {
         WC_Subscriptions::add_notice(sprintf(__('That subscription can not be changed to %s. Please contact us if you need assistance.', 'woocommerce-subscriptions'), $new_status), 'error');
         return false;
     }
     return true;
 }
 /**
  * Display a notice if functions are hooked to the old filter and apply the old filters args
  *
  * @since 2.0
  */
 protected function trigger_hook($old_hook, $new_callback_args)
 {
     if (0 === strpos($old_hook, 'admin_changed_subscription_to_')) {
         // New arg spec: $subscription_id
         // Old arg spec: $subscription_key
         $subscription = wcs_get_subscription($new_callback_args[0]);
         do_action($old_hook, wcs_get_old_subscription_key($subscription));
     } elseif (0 === strpos($old_hook, 'scheduled_subscription_payment_')) {
         // New arg spec: $amount, $renewal_order
         // Old arg spec: $amount, $original_order, $product_id
         $subscription = $new_callback_args[0];
         $subscriptions = wcs_get_subscriptions_for_renewal_order($new_callback_args[1]);
         if (!empty($subscriptions)) {
             $subscription = array_pop($subscriptions);
             do_action($old_hook, $new_callback_args[0], self::get_order($subscription), self::get_product_id($subscription));
         }
     } elseif (0 === strpos($old_hook, 'activated_subscription_') || 0 === strpos($old_hook, 'reactivated_subscription_') || 0 === strpos($old_hook, 'subscription_put_on-hold_') || 0 === strpos($old_hook, 'cancelled_subscription_') || 0 === strpos($old_hook, 'subscription_expired_')) {
         // New arg spec: $subscription
         // Old arg spec: $order, $product_id
         $subscription = $new_callback_args[0];
         do_action($old_hook, self::get_order($subscription), self::get_product_id($subscription));
     } elseif (0 === strpos($old_hook, 'customer_changed_subscription_to_')) {
         // New arg spec: $subscription
         // Old arg spec: $subscription_key
         do_action($old_hook, wcs_get_old_subscription_key($new_callback_args[0]));
     } elseif (0 === strpos($old_hook, 'woocommerce_subscriptions_updated_recurring_payment_method_to_')) {
         // New arg spec: $subscription, $old_payment_method
         // Old arg spec: $order, $subscription_key, $old_payment_method
         $subscription = $new_callback_args[0];
         $old_payment_method = $new_callback_args[2];
         do_action($old_hook, self::get_order($subscription), wcs_get_old_subscription_key($subscription), $old_payment_method);
     } elseif (0 === strpos($old_hook, 'woocommerce_subscriptions_updated_recurring_payment_method_from_')) {
         // New arg spec: $subscription, $new_payment_method
         // Old arg spec: $order, $subscription_key, $new_payment_method
         $subscription = $new_callback_args[0];
         $new_payment_method = $new_callback_args[1];
         do_action($old_hook, self::get_order($subscription), wcs_get_old_subscription_key($subscription), $new_payment_method);
     } elseif (0 === strpos($old_hook, 'woocommerce_subscriptions_changed_failing_payment_method_')) {
         // New arg spec: $subscription, $renewal_order
         // Old arg spec: $original_order, $renewal_order, $subscription_key
         $subscription = $new_callback_args[0];
         do_action($old_hook, self::get_order($subscription), $new_callback_args[1], wcs_get_old_subscription_key($subscription));
     }
 }
示例#13
0
 /**
  * Get order containing item.
  *
  * @since 160608 Order item utilities.
  *
  * @param string|int $item_id Order item ID.
  *
  * @return \WC_Abstract_Order|null Order on success.
  */
 public function orderByItemId($item_id)
 {
     if (!($item_id = (int) $item_id)) {
         return null;
         // Not possible.
     }
     $WpDb = $this->s::wpDb();
     // DB instance.
     $table = $WpDb->prefix . 'woocommerce_order_items';
     $sql = '
         SELECT `order_id` FROM `' . esc_sql($table) . '`
          WHERE `order_item_id` = %s LIMIT 1';
     $sql = $WpDb->prepare($sql, $item_id);
     // Prepare.
     if (!($order_id = (int) $WpDb->get_var($sql))) {
         return null;
         // Not possible; can't get order ID.
     } elseif (!($post_type = get_post_type($order_id))) {
         debug(0, $this->c::issue(vars(), 'Unable to acquire order post type.'));
         return null;
         // Not possible; can't get post type.
     }
     switch ($post_type) {
         // Based on post type.
         case 'shop_subscription':
             $subscription_id = $order_id;
             // It's a subscription ID.
             if ($WC_Subscription = wcs_get_subscription($subscription_id)) {
                 return $WC_Subscription;
             }
             return null;
             // Not possible.
         // Not possible.
         case 'shop_order':
         default:
             // Any other order type.
             if ($WC_Order = wc_get_order($order_id)) {
                 return $WC_Order;
             }
             return null;
             // Not possible.
     }
 }
 /**
  * Update any subscription that need to be repaired.
  *
  * @return array The counts of repaired and unrepaired subscriptions
  */
 public static function maybe_repair_subscriptions($subscription_ids_to_repair)
 {
     global $wpdb;
     // don't allow data to be half upgraded on a subscription in case of a script timeout or other non-recoverable error
     $wpdb->query('START TRANSACTION');
     $repaired_count = $unrepaired_count = 0;
     foreach ($subscription_ids_to_repair as $subscription_id) {
         $subscription = wcs_get_subscription($subscription_id);
         if (false !== $subscription && self::maybe_repair_subscription($subscription)) {
             WCS_Upgrade_Logger::add(sprintf('For subscription %d: repair completed', $subscription->id));
             $repaired_count++;
             update_post_meta($subscription_id, '_wcs_repaired_2_0_2', 'true');
         } else {
             WCS_Upgrade_Logger::add(sprintf('For subscription %d: no repair needed', $subscription->id));
             $unrepaired_count++;
             update_post_meta($subscription_id, '_wcs_repaired_2_0_2', 'false');
         }
     }
     $wpdb->query('COMMIT');
     return array('repaired_count' => $repaired_count, 'unrepaired_count' => $unrepaired_count);
 }
 /**
  * Displays the renewal orders in the Related Orders meta box.
  *
  * @param object $post A WordPress post
  * @since 2.0
  */
 public static function output_rows($post)
 {
     $subscriptions = array();
     $orders = array();
     // On the subscription page, just show related orders
     if (wcs_is_subscription($post->ID)) {
         $subscriptions[] = wcs_get_subscription($post->ID);
     } elseif (wcs_order_contains_subscription($post->ID, array('parent', 'renewal'))) {
         $subscriptions = wcs_get_subscriptions_for_order($post->ID, array('order_type' => array('parent', 'renewal')));
     }
     // First, display all the subscriptions
     foreach ($subscriptions as $subscription) {
         $subscription->relationship = _x('Subscription', 'relation to order', 'woocommerce-subscriptions');
         $orders[] = $subscription;
     }
     // Now, if we're on a single subscription or renewal order's page, display the parent orders
     if (1 == count($subscriptions)) {
         foreach ($subscriptions as $subscription) {
             if (false !== $subscription->order) {
                 $subscription->order->relationship = _x('Parent Order', 'relation to order', 'woocommerce-subscriptions');
                 $orders[] = $subscription->order;
             }
         }
     }
     // Finally, display the renewal orders
     foreach ($subscriptions as $subscription) {
         foreach ($subscription->get_related_orders('all', 'renewal') as $order) {
             $order->relationship = _x('Renewal Order', 'relation to order', 'woocommerce-subscriptions');
             $orders[] = $order;
         }
     }
     foreach ($orders as $order) {
         if ($order->id == $post->ID) {
             continue;
         }
         include 'views/html-related-orders-row.php';
     }
 }
 /**
  * Add order note to subscription to record the renewal order
  *
  * @param WC_Order|int $renewal_order
  * @param WC_Subscription|int $subscription
  * @since 2.0
  */
 public static function add_order_note($renewal_order, $subscription)
 {
     if (!is_object($subscription)) {
         $subscription = wcs_get_subscription($subscription);
     }
     if (!is_object($renewal_order)) {
         $renewal_order = wc_get_order($renewal_order);
     }
     if (is_a($renewal_order, 'WC_Order') && wcs_is_subscription($subscription)) {
         // translators: placeholder is order number, hash before order number
         $order_number = sprintf(__('#%s', 'woocommerce-subscriptions'), $renewal_order->get_order_number());
         // translators: placeholder is order ID
         $subscription->add_order_note(sprintf(__('Order %s created to record renewal.', 'woocommerce-subscriptions'), sprintf('<a href="%s">%s</a> ', esc_url(wcs_get_edit_post_link($renewal_order->id)), $order_number)));
     }
     return $renewal_order;
 }
 /**
  * Save meta box data
  */
 public static function save($post_id, $post)
 {
     global $wpdb;
     if ('shop_subscription' != $post->post_type || empty($_POST['woocommerce_meta_nonce']) || !wp_verify_nonce($_POST['woocommerce_meta_nonce'], 'woocommerce_save_data')) {
         return;
     }
     self::init_address_fields();
     // Update meta
     update_post_meta($post_id, '_customer_user', absint($_POST['customer_user']));
     if (self::$billing_fields) {
         foreach (self::$billing_fields as $key => $field) {
             update_post_meta($post_id, '_billing_' . $key, wc_clean($_POST['_billing_' . $key]));
         }
     }
     if (self::$shipping_fields) {
         foreach (self::$shipping_fields as $key => $field) {
             update_post_meta($post_id, '_shipping_' . $key, wc_clean($_POST['_shipping_' . $key]));
         }
     }
     $subscription = wcs_get_subscription($post_id);
     try {
         WCS_Change_Payment_Method_Admin::save_meta($subscription);
         if ('cancelled' == $_POST['order_status']) {
             $subscription->cancel_order();
         } else {
             $subscription->update_status($_POST['order_status'], '', true);
         }
     } catch (Exception $e) {
         // translators: placeholder is error message from by payment gateway
         wcs_add_admin_notice(sprintf(__('Unable to change payment method: %s', 'woocommerce-subscriptions'), $e->getMessage()), 'error');
     }
     do_action('woocommerce_process_shop_subscription_meta', $post_id, $post);
 }
 /**
  * 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;
                 }
             }
         }
     }
 }
 /**
  * Check if a product is a renewal order line item (rather than a "susbscription") - to pick up non-subsbcription products added a subscription manually
  *
  * @param  int	$product_id
  * @param  array  $cart_item
  * @param  WC_Cart  $cart The WooCommerce cart object.
  * @return boolean whether a product is a renewal order line item
  * @since 2.0.10
  */
 private static function is_subsbcription_renewal_line_item($product_id, $cart_item)
 {
     $is_subscription_line_item = false;
     if (is_object($product_id)) {
         $product = $product_id;
         $product_id = $product->id;
     } elseif (is_numeric($product_id)) {
         $product = wc_get_product($product_id);
     }
     if (!empty($cart_item['subscription_renewal'])) {
         if ($subscription = wcs_get_subscription($cart_item['subscription_renewal']['subscription_id'])) {
             foreach ($subscription->get_items() as $item) {
                 $item_product_id = $item['variation_id'] ? $item['variation_id'] : $item['product_id'];
                 if (!empty($item_product_id) && $item_product_id == $product_id) {
                     $is_subscription_line_item = true;
                 }
             }
         }
     }
     return apply_filters('woocommerce_is_subscription_renewal_line_item', $is_subscription_line_item, $product_id, $cart_item);
 }
示例#20
0
    esc_html_e('Next Payment', 'woocommerce-subscriptions');
    ?>
</span></th>
				<th class="subscription-total order-total"><span class="nobr"><?php 
    esc_html_e('Total', 'woocommerce-subscriptions');
    ?>
</span></th>
				<th class="subscription-actions order-actions">&nbsp;</th>
			</tr>

	<tbody>
	<?php 
    foreach ($subscriptions as $subscription_id => $subscription) {
        ?>
		<?php 
        $sub = wcs_get_subscription($subscription);
        $items = $sub->get_items();
        $link = '';
        foreach ($items as $id => $item) {
            if (isset($item['product_id'])) {
                $post_id = (int) $item['product_id'];
                $link = get_post_meta($post_id, 'ndv_link', true);
            }
        }
        ?>
		<tr class="order">
			<td class="subscription-id order-number" data-title="<?php 
        esc_attr_e('ID', 'woocommerce-subscriptions');
        ?>
">
				<a href="<?php 
 /**
  * Get PayPal Args for passing to PP
  *
  * Based on the HTML Variables documented here: https://developer.paypal.com/webapps/developer/docs/classic/paypal-payments-standard/integration-guide/Appx_websitestandard_htmlvariables/#id08A6HI00JQU
  *
  * @param WC_Order $order
  * @return array
  */
 public static function get_paypal_args($paypal_args, $order)
 {
     $is_payment_change = WC_Subscriptions_Change_Payment_Gateway::$is_request_to_change_payment;
     $order_contains_failed_renewal = false;
     // Payment method changes act on the subscription not the original order
     if ($is_payment_change) {
         $subscriptions = array(wcs_get_subscription($order->id));
         $subscription = array_pop($subscriptions);
         $order = $subscription->order;
         // We need the subscription's total
         remove_filter('woocommerce_order_amount_total', 'WC_Subscriptions_Change_Payment_Gateway::maybe_zero_total', 11, 2);
     } else {
         // Otherwise the order is the $order
         if ($cart_item = wcs_cart_contains_failed_renewal_order_payment() || false !== WC_Subscriptions_Renewal_Order::get_failed_order_replaced_by($order->id)) {
             $subscriptions = wcs_get_subscriptions_for_renewal_order($order);
             $order_contains_failed_renewal = true;
         } else {
             $subscriptions = wcs_get_subscriptions_for_order($order);
         }
         // Only one subscription allowed per order with PayPal
         $subscription = array_pop($subscriptions);
     }
     if ($order_contains_failed_renewal || !empty($subscription) && $subscription->get_total() > 0 && 'yes' !== get_option(WC_Subscriptions_Admin::$option_prefix . '_turn_off_automatic_payments', 'no')) {
         // It's a subscription
         $paypal_args['cmd'] = '_xclick-subscriptions';
         // Store the subscription ID in the args sent to PayPal so we can access them later
         $paypal_args['custom'] = wcs_json_encode(array('order_id' => $order->id, 'order_key' => $order->order_key, 'subscription_id' => $subscription->id, 'subscription_key' => $subscription->order_key));
         foreach ($subscription->get_items() as $item) {
             if ($item['qty'] > 1) {
                 $item_names[] = $item['qty'] . ' x ' . wcs_get_paypal_item_name($item['name']);
             } elseif ($item['qty'] > 0) {
                 $item_names[] = wcs_get_paypal_item_name($item['name']);
             }
         }
         // translators: 1$: subscription ID, 2$: order ID, 3$: names of items, comma separated
         $paypal_args['item_name'] = wcs_get_paypal_item_name(sprintf(_x('Subscription %1$s (Order %2$s) - %3$s', 'item name sent to paypal', 'woocommerce-subscriptions'), $subscription->get_order_number(), $order->get_order_number(), implode(', ', $item_names)));
         $unconverted_periods = array('billing_period' => $subscription->billing_period, 'trial_period' => $subscription->trial_period);
         $converted_periods = array();
         // Convert period strings into PayPay's format
         foreach ($unconverted_periods as $key => $period) {
             switch (strtolower($period)) {
                 case 'day':
                     $converted_periods[$key] = 'D';
                     break;
                 case 'week':
                     $converted_periods[$key] = 'W';
                     break;
                 case 'year':
                     $converted_periods[$key] = 'Y';
                     break;
                 case 'month':
                 default:
                     $converted_periods[$key] = 'M';
                     break;
             }
         }
         $price_per_period = $subscription->get_total();
         $subscription_interval = $subscription->billing_interval;
         $start_timestamp = $subscription->get_time('start');
         $trial_end_timestamp = $subscription->get_time('trial_end');
         $next_payment_timestamp = $subscription->get_time('next_payment');
         $is_synced_subscription = WC_Subscriptions_Synchroniser::subscription_contains_synced_product($subscription->id);
         if ($is_synced_subscription) {
             $length_from_timestamp = $next_payment_timestamp;
         } elseif ($trial_end_timestamp > 0) {
             $length_from_timestamp = $trial_end_timestamp;
         } else {
             $length_from_timestamp = $start_timestamp;
         }
         $subscription_length = wcs_estimate_periods_between($length_from_timestamp, $subscription->get_time('end'), $subscription->billing_period);
         $subscription_installments = $subscription_length / $subscription_interval;
         $initial_payment = $is_payment_change ? 0 : $order->get_total();
         if ($order_contains_failed_renewal || $is_payment_change) {
             if ($is_payment_change) {
                 // Add a nonce to the order ID to avoid "This invoice has already been paid" error when changing payment method to PayPal when it was previously PayPal
                 $suffix = '-wcscpm-' . wp_create_nonce();
             } else {
                 // Failed renewal order, append a descriptor and renewal order's ID
                 $suffix = '-wcsfrp-' . $order->id;
             }
             // Change the 'invoice' and the 'custom' values to be for the original order (if there is one)
             if (false === $subscription->order) {
                 // No original order so we need to use the subscriptions values instead
                 $order_number = ltrim($subscription->get_order_number(), _x('#', 'hash before the order number. Used as a character to remove from the actual order number', 'woocommerce-subscriptions')) . '-subscription';
                 $order_id_key = array('order_id' => $subscription->id, 'order_key' => $subscription->order_key);
             } else {
                 $order_number = ltrim($subscription->order->get_order_number(), _x('#', 'hash before the order number. Used as a character to remove from the actual order number', 'woocommerce-subscriptions'));
                 $order_id_key = array('order_id' => $subscription->order->id, 'order_key' => $subscription->order->order_key);
             }
             $order_details = false !== $subscription->order ? $subscription->order : $subscription;
             // Set the invoice details to the original order's invoice but also append a special string and this renewal orders ID so that we can match it up as a failed renewal order payment later
             $paypal_args['invoice'] = WCS_PayPal::get_option('invoice_prefix') . $order_number . $suffix;
             $paypal_args['custom'] = wcs_json_encode(array_merge($order_id_key, array('subscription_id' => $subscription->id, 'subscription_key' => $subscription->order_key)));
         }
         if ($order_contains_failed_renewal) {
             $subscription_trial_length = 0;
             $subscription_installments = max($subscription_installments - $subscription->get_completed_payment_count(), 0);
             // If we're changing the payment date or switching subs, we need to set the trial period to the next payment date & installments to be the number of installments left
         } elseif ($is_payment_change || $is_synced_subscription) {
             $next_payment_timestamp = $subscription->get_time('next_payment');
             // When the subscription is on hold
             if (false != $next_payment_timestamp && !empty($next_payment_timestamp)) {
                 $trial_until = wcs_calculate_paypal_trial_periods_until($next_payment_timestamp);
                 $subscription_trial_length = $trial_until['first_trial_length'];
                 $converted_periods['trial_period'] = $trial_until['first_trial_period'];
                 $second_trial_length = $trial_until['second_trial_length'];
                 $second_trial_period = $trial_until['second_trial_period'];
             } else {
                 $subscription_trial_length = 0;
             }
             // If this is a payment change, we need to account for completed payments on the number of installments owing
             if ($is_payment_change && $subscription_length > 0) {
                 $subscription_installments = max($subscription_installments - $subscription->get_completed_payment_count(), 0);
             }
         } else {
             $subscription_trial_length = wcs_estimate_periods_between($start_timestamp, $trial_end_timestamp, $subscription->trial_period);
         }
         if ($subscription_trial_length > 0) {
             // Specify a free trial period
             $paypal_args['a1'] = $initial_payment > 0 ? $initial_payment : 0;
             // Trial period length
             $paypal_args['p1'] = $subscription_trial_length;
             // Trial period
             $paypal_args['t1'] = $converted_periods['trial_period'];
             // We need to use a second trial period before we have more than 90 days until the next payment
             if (isset($second_trial_length) && $second_trial_length > 0) {
                 $paypal_args['a2'] = 0.01;
                 // Alas, although it's undocumented, PayPal appears to require a non-zero value in order to allow a second trial period
                 $paypal_args['p2'] = $second_trial_length;
                 $paypal_args['t2'] = $second_trial_period;
             }
         } elseif ($initial_payment != $price_per_period) {
             // No trial period, but initial amount includes a sign-up fee and/or other items, so charge it as a separate period
             if (1 == $subscription_installments) {
                 $param_number = 3;
             } else {
                 $param_number = 1;
             }
             $paypal_args['a' . $param_number] = $initial_payment;
             // Sign Up interval
             $paypal_args['p' . $param_number] = $subscription_interval;
             // Sign Up unit of duration
             $paypal_args['t' . $param_number] = $converted_periods['billing_period'];
         }
         // We have a recurring payment
         if (!isset($param_number) || 1 == $param_number) {
             // Subscription price
             $paypal_args['a3'] = $price_per_period;
             // Subscription duration
             $paypal_args['p3'] = $subscription_interval;
             // Subscription period
             $paypal_args['t3'] = $converted_periods['billing_period'];
         }
         // Recurring payments
         if (1 == $subscription_installments || $initial_payment != $price_per_period && 0 == $subscription_trial_length && 2 == $subscription_installments) {
             // Non-recurring payments
             $paypal_args['src'] = 0;
         } else {
             $paypal_args['src'] = 1;
             if ($subscription_installments > 0) {
                 // An initial period is being used to charge a sign-up fee
                 if ($initial_payment != $price_per_period && 0 == $subscription_trial_length) {
                     $subscription_installments--;
                 }
                 $paypal_args['srt'] = $subscription_installments;
             }
         }
         // Don't reattempt failed payments, instead let Subscriptions handle the failed payment
         $paypal_args['sra'] = 0;
         // Force return URL so that order description & instructions display
         $paypal_args['rm'] = 2;
         // Reattach the filter we removed earlier
         if ($is_payment_change) {
             add_filter('woocommerce_order_amount_total', 'WC_Subscriptions_Change_Payment_Gateway::maybe_zero_total', 11, 2);
         }
     }
     return $paypal_args;
 }
示例#22
0
 *
 * @author    Prospress
 * @package   WooCommerce_Subscription/Templates
 * @version   2.0
 */
if (!defined('ABSPATH')) {
    exit;
    // Exit if accessed directly
}
if (empty($subscription)) {
    global $wp;
    if (!isset($wp->query_vars['view-subscription']) || 'shop_subscription' != get_post_type(absint($wp->query_vars['view-subscription'])) || !current_user_can('view_order', absint($wp->query_vars['view-subscription']))) {
        echo '<div class="woocommerce-error">' . esc_html__('Invalid Subscription.', 'woocommerce-subscriptions') . ' <a href="' . esc_url(wc_get_page_permalink('myaccount')) . '" class="wc-forward">' . esc_html__('My Account', 'woocommerce-subscriptions') . '</a>' . '</div>';
        return;
    }
    $subscription = wcs_get_subscription($wp->query_vars['view-subscription']);
}
wc_print_notices();
?>

<table class="shop_table subscription_details">
	<tr>
		<td><?php 
esc_html_e('Status', 'woocommerce-subscriptions');
?>
</td>
		<td><?php 
echo esc_html(wcs_get_subscription_status_name($subscription->get_status()));
?>
</td>
	</tr>
 /**
  * Process a PayPal Standard Subscription IPN request
  *
  * @param array $transaction_details Post data after wp_unslash
  * @since 2.0
  */
 protected function process_ipn_request($transaction_details)
 {
     // Get the subscription ID and order_key with backward compatibility
     $subscription_id_and_key = self::get_order_id_and_key($transaction_details, 'shop_subscription');
     $subscription = wcs_get_subscription($subscription_id_and_key['order_id']);
     $subscription_key = $subscription_id_and_key['order_key'];
     // We have an invalid $subscription, probably because invoice_prefix has changed since the subscription was first created, so get the subscription by order key
     if (!isset($subscription->id)) {
         $subscription = wcs_get_subscription(wc_get_order_id_by_order_key($subscription_key));
     }
     if ('recurring_payment_suspended_due_to_max_failed_payment' == $transaction_details['txn_type'] && empty($subscription)) {
         WC_Gateway_Paypal::log('Returning as "recurring_payment_suspended_due_to_max_failed_payment" transaction is for a subscription created with Express Checkout');
         return;
     }
     if (empty($subscription)) {
         WC_Gateway_Paypal::log('Subscription IPN Error: Could not find matching Subscription.');
         exit;
     }
     if ($subscription->order_key != $subscription_key) {
         WC_Gateway_Paypal::log('Subscription IPN Error: Subscription Key does not match invoice.');
         exit;
     }
     if (isset($transaction_details['ipn_track_id'])) {
         // Make sure the IPN request has not already been handled
         $handled_ipn_requests = get_post_meta($subscription->id, '_paypal_ipn_tracking_ids', true);
         if (empty($handled_ipn_requests)) {
             $handled_ipn_requests = array();
         }
         // The 'ipn_track_id' is not a unique ID and is shared between different transaction types, so create a unique ID by prepending the transaction type
         $ipn_id = $transaction_details['txn_type'] . '_' . $transaction_details['ipn_track_id'];
         if (in_array($ipn_id, $handled_ipn_requests)) {
             WC_Gateway_Paypal::log('Subscription IPN Error: IPN ' . $ipn_id . ' message has already been correctly handled.');
             exit;
         }
         // Make sure we're not in the process of handling this IPN request on a server under extreme load and therefore, taking more than a minute to process it (which is the amount of time PayPal allows before resending the IPN request)
         $ipn_lock_transient_name = 'wcs_pp_' . $ipn_id;
         // transient names need to be less than 45 characters and the $ipn_id will be around 30 characters, e.g. subscr_payment_5ab4c38e1f39d
         if ('in-progress' == get_transient($ipn_lock_transient_name) && 'recurring_payment_suspended_due_to_max_failed_payment' !== $transaction_details['txn_type']) {
             WC_Gateway_Paypal::log('Subscription IPN Error: an older IPN request with ID ' . $ipn_id . ' is still in progress.');
             // We need to send an error code to make sure PayPal does retry the IPN after our lock expires, in case something is actually going wrong and the server isn't just taking a long time to process the request
             status_header(503);
             exit;
         }
         // Set a transient to block IPNs with this transaction ID for the next 5 minutes
         set_transient($ipn_lock_transient_name, 'in-progress', apply_filters('woocommerce_subscriptions_paypal_ipn_request_lock_time', 5 * MINUTE_IN_SECONDS));
     }
     if (isset($transaction_details['txn_id'])) {
         // Make sure the IPN request has not already been handled
         $handled_transactions = get_post_meta($subscription->id, '_paypal_transaction_ids', true);
         if (empty($handled_transactions)) {
             $handled_transactions = array();
         }
         $transaction_id = $transaction_details['txn_id'];
         if (isset($transaction_details['txn_type'])) {
             $transaction_id .= '_' . $transaction_details['txn_type'];
         }
         // The same transaction ID is used for different payment statuses, so make sure we handle it only once. See: http://stackoverflow.com/questions/9240235/paypal-ipn-unique-identifier
         if (isset($transaction_details['payment_status'])) {
             $transaction_id .= '_' . $transaction_details['payment_status'];
         }
         if (in_array($transaction_id, $handled_transactions)) {
             WC_Gateway_Paypal::log('Subscription IPN Error: transaction ' . $transaction_id . ' has already been correctly handled.');
             exit;
         }
     }
     WC_Gateway_Paypal::log('Subscription transaction details: ' . print_r($transaction_details, true));
     WC_Gateway_Paypal::log('Subscription Transaction Type: ' . $transaction_details['txn_type']);
     $is_renewal_sign_up_after_failure = false;
     // If the invoice ID doesn't match the default invoice ID and contains the string '-wcsfrp-', the IPN is for a subscription payment to fix up a failed payment
     if (in_array($transaction_details['txn_type'], array('subscr_signup', 'subscr_payment')) && false !== strpos($transaction_details['invoice'], '-wcsfrp-')) {
         $renewal_order = wc_get_order(substr($transaction_details['invoice'], strrpos($transaction_details['invoice'], '-') + 1));
         // check if the failed signup has been previously recorded
         if ($renewal_order->id != get_post_meta($subscription->id, '_paypal_failed_sign_up_recorded', true)) {
             $is_renewal_sign_up_after_failure = true;
         }
     }
     // If the invoice ID doesn't match the default invoice ID and contains the string '-wcscpm-', the IPN is for a subscription payment method change
     if ('subscr_signup' == $transaction_details['txn_type'] && false !== strpos($transaction_details['invoice'], '-wcscpm-')) {
         $is_payment_change = true;
     } else {
         $is_payment_change = false;
     }
     // Ignore IPN messages when the payment method isn't PayPal
     if ('paypal' != $subscription->payment_method) {
         // The 'recurring_payment_suspended' transaction is actually an Express Checkout transaction type, but PayPal also send it for PayPal Standard Subscriptions suspended by admins at PayPal, so we need to handle it *if* the subscription has PayPal as the payment method, or leave it if the subscription is using a different payment method (because it might be using PayPal Express Checkout or PayPal Digital Goods)
         if ('recurring_payment_suspended' == $transaction_details['txn_type']) {
             WC_Gateway_Paypal::log('"recurring_payment_suspended" IPN ignored: recurring payment method is not "PayPal". Returning to allow another extension to process the IPN, like PayPal Digital Goods.');
             return;
         } elseif (false === $is_renewal_sign_up_after_failure && false === $is_payment_change) {
             WC_Gateway_Paypal::log('IPN ignored, recurring payment method has changed.');
             exit;
         }
     }
     if ($is_renewal_sign_up_after_failure || $is_payment_change) {
         // Store the old profile ID on the order (for the first IPN message that comes through)
         $existing_profile_id = wcs_get_paypal_id($subscription);
         if (empty($existing_profile_id) || $existing_profile_id !== $transaction_details['subscr_id']) {
             update_post_meta($subscription->id, '_old_paypal_subscriber_id', $existing_profile_id);
             update_post_meta($subscription->id, '_old_payment_method', $subscription->payment_method);
         }
     }
     // Save the profile ID if it's not a cancellation/expiration request
     if (isset($transaction_details['subscr_id']) && !in_array($transaction_details['txn_type'], array('subscr_cancel', 'subscr_eot'))) {
         wcs_set_paypal_id($subscription, $transaction_details['subscr_id']);
         if (wcs_is_paypal_profile_a($transaction_details['subscr_id'], 'out_of_date_id') && 'disabled' != get_option('wcs_paypal_invalid_profile_id')) {
             update_option('wcs_paypal_invalid_profile_id', 'yes');
         }
     }
     $is_first_payment = $subscription->get_completed_payment_count() < 1 ? true : false;
     if ($subscription->has_status('switched')) {
         WC_Gateway_Paypal::log('IPN ignored, subscription has been switched.');
         exit;
     }
     switch ($transaction_details['txn_type']) {
         case 'subscr_signup':
             // Store PayPal Details on Subscription and Order
             $this->save_paypal_meta_data($subscription, $transaction_details);
             $this->save_paypal_meta_data($subscription->order, $transaction_details);
             // When there is a free trial & no initial payment amount, we need to mark the order as paid and activate the subscription
             if (!$is_payment_change && !$is_renewal_sign_up_after_failure && 0 == $subscription->order->get_total()) {
                 // Safe to assume the subscription has an order here because otherwise we wouldn't get a 'subscr_signup' IPN
                 $subscription->order->payment_complete();
                 // No 'txn_id' value for 'subscr_signup' IPN messages
                 update_post_meta($subscription->id, '_paypal_first_ipn_ignored_for_pdt', 'true');
             }
             // Payment completed
             if ($is_payment_change) {
                 // Set PayPal as the new payment method
                 WC_Subscriptions_Change_Payment_Gateway::update_payment_method($subscription, 'paypal');
                 // We need to cancel the subscription now that the method has been changed successfully
                 if ('paypal' == get_post_meta($subscription->id, '_old_payment_method', true)) {
                     self::cancel_subscription($subscription, get_post_meta($subscription->id, '_old_paypal_subscriber_id', true));
                 }
                 $subscription->add_order_note(_x('IPN subscription payment method changed to PayPal.', 'when it is a payment change, and there is a subscr_signup message, this will be a confirmation message that PayPal accepted it being the new payment method', 'woocommerce-subscriptions'));
             } else {
                 $subscription->add_order_note(__('IPN subscription sign up completed.', 'woocommerce-subscriptions'));
             }
             if ($is_payment_change) {
                 WC_Gateway_Paypal::log('IPN subscription payment method changed for subscription ' . $subscription->id);
             } else {
                 WC_Gateway_Paypal::log('IPN subscription sign up completed for subscription ' . $subscription->id);
             }
             break;
         case 'subscr_payment':
             if (!$is_first_payment && !$is_renewal_sign_up_after_failure) {
                 if ($subscription->has_status('active')) {
                     remove_action('woocommerce_subscription_on-hold_paypal', 'WCS_PayPal_Status_Manager::suspend_subscription');
                     $subscription->update_status('on-hold');
                     add_action('woocommerce_subscription_on-hold_paypal', 'WCS_PayPal_Status_Manager::suspend_subscription');
                 }
                 // Generate a renewal order to record the payment (and determine how much is due)
                 $renewal_order = wcs_create_renewal_order($subscription);
                 // Set PayPal as the payment method (we can't use $renewal_order->set_payment_method() here as it requires an object we don't have)
                 $available_gateways = WC()->payment_gateways->get_available_payment_gateways();
                 $renewal_order->set_payment_method($available_gateways['paypal']);
             }
             if ('completed' == strtolower($transaction_details['payment_status'])) {
                 // Store PayPal Details
                 $this->save_paypal_meta_data($subscription, $transaction_details);
                 // Subscription Payment completed
                 $subscription->add_order_note(__('IPN subscription payment completed.', 'woocommerce-subscriptions'));
                 WC_Gateway_Paypal::log('IPN subscription payment completed for subscription ' . $subscription->id);
                 // First payment on order, process payment & activate subscription
                 if ($is_first_payment) {
                     $subscription->order->payment_complete($transaction_details['txn_id']);
                     // Store PayPal Details on Order
                     $this->save_paypal_meta_data($subscription->order, $transaction_details);
                     // IPN got here first or PDT will never arrive. Normally PDT would have arrived, so the first IPN would not be the first payment. In case the the first payment is an IPN, we need to make sure to not ignore the second one
                     update_post_meta($subscription->id, '_paypal_first_ipn_ignored_for_pdt', 'true');
                     // Ignore the first IPN message if the PDT should have handled it (if it didn't handle it, it will have been dealt with as first payment), but set a flag to make sure we only ignore it once
                 } elseif ($subscription->get_completed_payment_count() == 1 && '' !== WCS_PayPal::get_option('identity_token') && 'true' != get_post_meta($subscription->id, '_paypal_first_ipn_ignored_for_pdt', true) && false === $is_renewal_sign_up_after_failure) {
                     WC_Gateway_Paypal::log('IPN subscription payment ignored for subscription ' . $subscription->id . ' due to PDT previously handling the payment.');
                     update_post_meta($subscription->id, '_paypal_first_ipn_ignored_for_pdt', 'true');
                     // Process the payment if the subscription is active
                 } elseif (!$subscription->has_status(array('cancelled', 'expired', 'switched', 'trash'))) {
                     if (true === $is_renewal_sign_up_after_failure && is_object($renewal_order)) {
                         update_post_meta($subscription->id, '_paypal_failed_sign_up_recorded', $renewal_order->id);
                         // We need to cancel the old subscription now that the method has been changed successfully
                         if ('paypal' == get_post_meta($subscription->id, '_old_payment_method', true)) {
                             $profile_id = get_post_meta($subscription->id, '_old_paypal_subscriber_id', true);
                             // Make sure we don't cancel the current profile
                             if ($profile_id !== $transaction_details['subscr_id']) {
                                 self::cancel_subscription($subscription, $profile_id);
                             }
                             $subscription->add_order_note(__('IPN subscription failing payment method changed.', 'woocommerce-subscriptions'));
                         }
                     }
                     try {
                         // to cover the case when PayPal drank too much coffee and sent IPNs early - needs to happen before $renewal_order->payment_complete
                         $update_dates = array();
                         if ($subscription->get_time('trial_end') > gmdate('U')) {
                             $update_dates['trial_end'] = gmdate('Y-m-d H:i:s', gmdate('U') - 1);
                             WC_Gateway_Paypal::log(sprintf('IPN subscription payment for subscription %d: trial_end is in futute (date: %s) setting to %s.', $subscription->id, $subscription->get_date('trial_end'), $update_dates['trial_end']));
                         } else {
                             WC_Gateway_Paypal::log(sprintf('IPN subscription payment for subscription %d: trial_end is in past (date: %s).', $subscription->id, $subscription->get_date('trial_end')));
                         }
                         if ($subscription->get_time('next_payment') > gmdate('U')) {
                             $update_dates['next_payment'] = gmdate('Y-m-d H:i:s', gmdate('U') - 1);
                             WC_Gateway_Paypal::log(sprintf('IPN subscription payment for subscription %d: next_payment is in future (date: %s) setting to %s.', $subscription->id, $subscription->get_date('next_payment'), $update_dates['next_payment']));
                         } else {
                             WC_Gateway_Paypal::log(sprintf('IPN subscription payment for subscription %d: next_payment is in past (date: %s).', $subscription->id, $subscription->get_date('next_payment')));
                         }
                         if (!empty($update_dates)) {
                             $subscription->update_dates($update_dates);
                         }
                     } catch (Exception $e) {
                         WC_Gateway_Paypal::log(sprintf('IPN subscription payment exception subscription %d: %s.', $subscription->id, $e->getMessage()));
                     }
                     remove_action('woocommerce_subscription_activated_paypal', 'WCS_PayPal_Status_Manager::reactivate_subscription');
                     try {
                         $renewal_order->payment_complete($transaction_details['txn_id']);
                     } catch (Exception $e) {
                         WC_Gateway_Paypal::log(sprintf('IPN subscription payment exception calling $renewal_order->payment_complete() for subscription %d: %s.', $subscription->id, $e->getMessage()));
                     }
                     $renewal_order->add_order_note(__('IPN subscription payment completed.', 'woocommerce-subscriptions'));
                     add_action('woocommerce_subscription_activated_paypal', 'WCS_PayPal_Status_Manager::reactivate_subscription');
                     wcs_set_paypal_id($renewal_order, $transaction_details['subscr_id']);
                 }
             } elseif (in_array(strtolower($transaction_details['payment_status']), array('pending', 'failed'))) {
                 // Subscription Payment completed
                 // translators: placeholder is payment status (e.g. "completed")
                 $subscription->add_order_note(sprintf(_x('IPN subscription payment %s.', 'used in order note', 'woocommerce-subscriptions'), $transaction_details['payment_status']));
                 if (!$is_first_payment) {
                     update_post_meta($renewal_order->id, '_transaction_id', $transaction_details['txn_id']);
                     // translators: placeholder is payment status (e.g. "completed")
                     $renewal_order->add_order_note(sprintf(_x('IPN subscription payment %s.', 'used in order note', 'woocommerce-subscriptions'), $transaction_details['payment_status']));
                     $subscription->payment_failed();
                 }
                 WC_Gateway_Paypal::log('IPN subscription payment failed for subscription ' . $subscription->id);
             } else {
                 WC_Gateway_Paypal::log('IPN subscription payment notification received for subscription ' . $subscription->id . ' with status ' . $transaction_details['payment_status']);
             }
             break;
             // Admins can suspend subscription at PayPal triggering this IPN
         // Admins can suspend subscription at PayPal triggering this IPN
         case 'recurring_payment_suspended':
             if ($subscription->has_status('active')) {
                 // We don't need to suspend the subscription at PayPal because it's already on-hold there
                 remove_action('woocommerce_subscription_on-hold_paypal', 'WCS_PayPal_Status_Manager::suspend_subscription');
                 $subscription->update_status('on-hold', __('IPN subscription suspended.', 'woocommerce-subscriptions'));
                 add_action('woocommerce_subscription_on-hold_paypal', 'WCS_PayPal_Status_Manager::suspend_subscription');
                 WC_Gateway_Paypal::log('IPN subscription suspended for subscription ' . $subscription->id);
             } else {
                 WC_Gateway_Paypal::log(sprintf('IPN "recurring_payment_suspended" ignored for subscription %d. Subscription already %s.', $subscription->id, $subscription->get_status()));
             }
             break;
         case 'subscr_cancel':
             // Make sure the subscription hasn't been linked to a new payment method
             if (wcs_get_paypal_id($subscription) != $transaction_details['subscr_id']) {
                 WC_Gateway_Paypal::log('IPN subscription cancellation request ignored - new PayPal Profile ID linked to this subscription, for subscription ' . $subscription->id);
             } else {
                 $subscription->cancel_order(__('IPN subscription cancelled.', 'woocommerce-subscriptions'));
                 WC_Gateway_Paypal::log('IPN subscription cancelled for subscription ' . $subscription->id);
             }
             break;
         case 'subscr_eot':
             // Subscription ended, either due to failed payments or expiration
             WC_Gateway_Paypal::log('IPN EOT request ignored for subscription ' . $subscription->id);
             break;
         case 'subscr_failed':
             // Subscription sign up failed
         // Subscription sign up failed
         case 'recurring_payment_suspended_due_to_max_failed_payment':
             // Recurring payment failed
             $ipn_failure_note = __('IPN subscription payment failure.', 'woocommerce-subscriptions');
             if (!$is_first_payment && !$is_renewal_sign_up_after_failure && $subscription->has_status('active')) {
                 // Generate a renewal order to record the failed payment
                 $renewal_order = wcs_create_renewal_order($subscription);
                 // Set PayPal as the payment method
                 $available_gateways = WC()->payment_gateways->get_available_payment_gateways();
                 $renewal_order->set_payment_method($available_gateways['paypal']);
                 $renewal_order->add_order_note($ipn_failure_note);
             }
             WC_Gateway_Paypal::log('IPN subscription payment failure for subscription ' . $subscription->id);
             // Subscription Payment completed
             $subscription->add_order_note($ipn_failure_note);
             try {
                 $subscription->payment_failed();
             } catch (Exception $e) {
                 WC_Gateway_Paypal::log(sprintf('IPN subscription payment failure, unable to process payment failure. Exception: %s ', $e->getMessage()));
             }
             break;
     }
     // Store the transaction IDs to avoid handling requests duplicated by PayPal
     if (isset($transaction_details['ipn_track_id'])) {
         $handled_ipn_requests[] = $ipn_id;
         update_post_meta($subscription->id, '_paypal_ipn_tracking_ids', $handled_ipn_requests);
     }
     if (isset($transaction_details['txn_id'])) {
         $handled_transactions[] = $transaction_id;
         update_post_meta($subscription->id, '_paypal_transaction_ids', $handled_transactions);
     }
     // And delete the transient that's preventing other IPN's being processed
     if (isset($ipn_lock_transient_name)) {
         delete_transient($ipn_lock_transient_name);
     }
     // Log completion
     $log_message = 'IPN subscription request processed for ' . $subscription->id;
     if (isset($ipn_id) && !empty($ipn_id)) {
         $log_message .= sprintf(' (%s)', $ipn_id);
     }
     WC_Gateway_Paypal::log($log_message);
     // Prevent default IPN handling for subscription txn_types
     exit;
 }
/**
 * Get the subscription to which a renewal order relates.
 *
 * @param WC_Order|int $order The WC_Order object or ID of a WC_Order order.
 * @since 2.0
 */
function wcs_get_subscriptions_for_renewal_order($order)
{
    if (!is_object($order)) {
        $order = wc_get_order($order);
    }
    $subscriptions = array();
    $subscription_ids = get_post_meta($order->id, '_subscription_renewal', false);
    foreach ($subscription_ids as $subscription_id) {
        if (wcs_is_subscription($subscription_id)) {
            $subscriptions[$subscription_id] = wcs_get_subscription($subscription_id);
        }
    }
    return apply_filters('wcs_subscriptions_for_renewal_order', $subscriptions, $order);
}
 *
 * @author  Sébastien Dumont
 * @package WooCommerce_Skip_One/Templates
 * @version 1.0.0
 */
if (!defined('ABSPATH')) {
    exit;
    // Exit if accessed directly
}
if (empty($subscription)) {
    global $wp;
    if (!isset($wp->query_vars['cancel-subscription']) || 'shop_subscription' != get_post_type(absint($wp->query_vars['cancel-subscription'])) || !current_user_can('view_order', absint($wp->query_vars['cancel-subscription']))) {
        wc_add_notice(esc_html__('Invalid Subscription.', 'woocommerce-skip-one') . ' <a href="' . esc_url(wc_get_page_permalink('myaccount')) . '" class="wc-forward">' . esc_html__('My Account', 'woocommerce-skip-one') . '</a>', 'error');
        return;
    } else {
        $subscription = wcs_get_subscription($wp->query_vars['cancel-subscription']);
        $subscription_skipped = $subscription->get_date_to_display('next_payment');
    }
}
wc_print_notices();
do_action('woocommerce_skip_one_before_skip_option');
?>
<h3><?php 
echo sprintf(__('You could just Skip a %s...', 'woocommerce-skip-one'), $subscription->billing_period);
?>
</h3>

<p><?php 
echo sprintf(__('Here\'s another option: You can <span>Skip a %1$s</span> and continue the following %1$s, ready for your next subscription!', 'woocommerce-skip-one'), $subscription->billing_period);
?>
</p>
示例#26
0
/**
 * Checks if a user has a certain capability
 *
 * @access public
 * @param array $allcaps
 * @param array $caps
 * @param array $args
 * @return bool
 */
function wcs_user_has_capability($allcaps, $caps, $args)
{
    if (isset($caps[0])) {
        switch ($caps[0]) {
            case 'edit_shop_subscription_payment_method':
                $user_id = $args[1];
                $subscription = wcs_get_subscription($args[2]);
                if ($user_id === $subscription->get_user_id()) {
                    $allcaps['edit_shop_subscription_payment_method'] = true;
                }
                break;
            case 'edit_shop_subscription_status':
                $user_id = $args[1];
                $subscription = wcs_get_subscription($args[2]);
                if ($user_id === $subscription->get_user_id()) {
                    $allcaps['edit_shop_subscription_status'] = true;
                }
                break;
            case 'edit_shop_subscription_line_items':
                $user_id = $args[1];
                $subscription = wcs_get_subscription($args[2]);
                if ($user_id === $subscription->get_user_id()) {
                    $allcaps['edit_shop_subscription_line_items'] = true;
                }
                break;
            case 'switch_shop_subscription':
                $user_id = $args[1];
                $subscription = wcs_get_subscription($args[2]);
                if ($user_id === $subscription->get_user_id()) {
                    $allcaps['switch_shop_subscription'] = true;
                }
                break;
            case 'subscribe_again':
                $user_id = $args[1];
                $subscription = wcs_get_subscription($args[2]);
                if ($user_id === $subscription->get_user_id()) {
                    $allcaps['subscribe_again'] = true;
                }
                break;
        }
    }
    return $allcaps;
}
示例#27
0
 /**
  * @param $sub
  * @param $old_status
  * @param $new_status
  * @return bool
  */
 public function woocommerce_subscription_status_updated($sub, $old_status, $new_status)
 {
     $sub = wcs_get_subscription($sub);
     $user = $sub->get_user();
     if (!$user->ID) {
         return false;
     }
     self::get_jwt_token($user);
 }
 /**
  * Check if the subscription needs to use the failed payment process to repair its status after it incorrectly expired due to a date migration
  * bug in upgrade process for 2.0.0 of Subscriptions (i.e. not 2.0.1 or newer). See WCS_Repair_2_0_2::maybe_repair_status() for more details.
  *
  * @param int $subscription_id The ID of a 'shop_subscription' post
  * @since 2.0.2
  */
 public static function maybe_process_failed_renewal_for_repair($subscription_id)
 {
     if ('true' == get_post_meta($subscription_id, '_wcs_repaired_2_0_2_needs_failed_payment', true)) {
         $subscription = wcs_get_subscription($subscription_id);
         // Always put the subscription on hold in case something goes wrong while trying to process renewal
         $subscription->update_status('on-hold', _x('Subscription renewal payment due:', 'used in order note as reason for why subscription status changed', 'woocommerce-subscriptions'));
         // Create a renewal order to record the failed payment which can then be used by the customer to reactivate the subscription
         $renewal_order = wcs_create_renewal_order($subscription);
         // Mark the payment as failed so the customer can login to fix up the failed payment
         $subscription->payment_failed();
         // Only force the failed payment once
         update_post_meta($subscription_id, '_wcs_repaired_2_0_2_needs_failed_payment', 'false');
         // We've already processed the renewal
         remove_action('woocommerce_scheduled_subscription_payment', __CLASS__ . '::prepare_renewal');
         remove_action('woocommerce_scheduled_subscription_payment', 'WC_Subscriptions_Payment_Gateways::gateway_scheduled_subscription_payment', 10, 1);
     }
 }
示例#29
0
/**
 * Get all subscription items which have a trial.
 *
 * @param mixed WC_Subscription|post_id
 * @return array
 * @since 2.0
 */
function wcs_get_line_items_with_a_trial($subscription_id)
{
    $subscription = is_object($subscription_id) ? $subscription_id : wcs_get_subscription($subscription_id);
    $trial_items = array();
    foreach ($subscription->get_items() as $line_item_id => $line_item) {
        if (isset($line_item['has_trial'])) {
            $trial_items[$line_item_id] = $line_item;
        }
    }
    return apply_filters('woocommerce_subscription_trial_line_items', $trial_items, $subscription_id);
}
    /**
     * Output custom columns for subscriptions
     * @param  string $column
     */
    public function render_shop_subscription_columns($column)
    {
        global $post, $the_subscription, $wp_list_table;
        if (empty($the_subscription) || $the_subscription->id != $post->ID) {
            $the_subscription = wcs_get_subscription($post->ID);
        }
        $column_content = '';
        switch ($column) {
            case 'status':
                // The status label
                $column_content = sprintf('<mark class="%s tips" data-tip="%s">%s</mark>', sanitize_title($the_subscription->get_status()), wcs_get_subscription_status_name($the_subscription->get_status()), wcs_get_subscription_status_name($the_subscription->get_status()));
                $post_type_object = get_post_type_object($post->post_type);
                $actions = array();
                $action_url = add_query_arg(array('post' => $the_subscription->id, '_wpnonce' => wp_create_nonce('bulk-posts')));
                if (isset($_REQUEST['status'])) {
                    $action_url = add_query_arg(array('status' => $_REQUEST['status']), $action_url);
                }
                $all_statuses = array('active' => __('Reactivate', 'woocommerce-subscriptions'), 'on-hold' => __('Suspend', 'woocommerce-subscriptions'), 'cancelled' => _x('Cancel', 'an action on a subscription', 'woocommerce-subscriptions'), 'trash' => __('Trash', 'woocommerce-subscriptions'), 'deleted' => __('Delete Permanently', 'woocommerce-subscriptions'));
                foreach ($all_statuses as $status => $label) {
                    if ($the_subscription->can_be_updated_to($status)) {
                        if (in_array($status, array('trash', 'deleted'))) {
                            if (current_user_can($post_type_object->cap->delete_post, $post->ID)) {
                                if ('trash' == $post->post_status) {
                                    $actions['untrash'] = '<a title="' . esc_attr(__('Restore this item from the Trash', 'woocommerce-subscriptions')) . '" href="' . wp_nonce_url(admin_url(sprintf($post_type_object->_edit_link . '&amp;action=untrash', $post->ID)), 'untrash-post_' . $post->ID) . '">' . __('Restore', 'woocommerce-subscriptions') . '</a>';
                                } elseif (EMPTY_TRASH_DAYS) {
                                    $actions['trash'] = '<a class="submitdelete" title="' . esc_attr(__('Move this item to the Trash', 'woocommerce-subscriptions')) . '" href="' . get_delete_post_link($post->ID) . '">' . __('Trash', 'woocommerce-subscriptions') . '</a>';
                                }
                                if ('trash' == $post->post_status || !EMPTY_TRASH_DAYS) {
                                    $actions['delete'] = '<a class="submitdelete" title="' . esc_attr(__('Delete this item permanently', 'woocommerce-subscriptions')) . '" href="' . get_delete_post_link($post->ID, '', true) . '">' . __('Delete Permanently', 'woocommerce-subscriptions') . '</a>';
                                }
                            }
                        } else {
                            if ('pending-cancel' === $the_subscription->get_status()) {
                                $label = __('Cancel Now', 'woocommerce-subscriptions');
                            }
                            $actions[$status] = sprintf('<a href="%s">%s</a>', add_query_arg('action', $status, $action_url), $label);
                        }
                    }
                }
                if ('pending' === $the_subscription->get_status()) {
                    unset($actions['active']);
                    unset($actions['trash']);
                } elseif (!in_array($the_subscription->get_status(), array('cancelled', 'pending-cancel', 'expired', 'switched', 'suspended'))) {
                    unset($actions['trash']);
                }
                $actions = apply_filters('woocommerce_subscription_list_table_actions', $actions, $the_subscription);
                $column_content .= $wp_list_table->row_actions($actions);
                $column_content = apply_filters('woocommerce_subscription_list_table_column_status_content', $column_content, $the_subscription, $actions);
                break;
            case 'order_title':
                $customer_tip = '';
                if ($address = $the_subscription->get_formatted_billing_address()) {
                    $customer_tip .= _x('Billing:', 'meaning billing address', 'woocommerce-subscriptions') . ' ' . esc_html($address);
                }
                if ($the_subscription->billing_email) {
                    // translators: placeholder is customer's billing email
                    $customer_tip .= '<br/><br/>' . sprintf(__('Email: %s', 'woocommerce-subscriptions'), esc_attr($the_subscription->billing_email));
                }
                if ($the_subscription->billing_phone) {
                    // translators: placeholder is customer's billing phone number
                    $customer_tip .= '<br/><br/>' . sprintf(__('Tel: %s', 'woocommerce-subscriptions'), esc_html($the_subscription->billing_phone));
                }
                if (!empty($customer_tip)) {
                    echo '<div class="tips" data-tip="' . esc_attr($customer_tip) . '">';
                }
                // This is to stop PHP from complaining
                $username = '';
                if ($the_subscription->get_user_id() && false !== ($user_info = get_userdata($the_subscription->get_user_id()))) {
                    $username = '******' . absint($user_info->ID) . '">';
                    if ($the_subscription->billing_first_name || $the_subscription->billing_last_name) {
                        $username .= esc_html(ucfirst($the_subscription->billing_first_name) . ' ' . ucfirst($the_subscription->billing_last_name));
                    } elseif ($user_info->first_name || $user_info->last_name) {
                        $username .= esc_html(ucfirst($user_info->first_name) . ' ' . ucfirst($user_info->last_name));
                    } else {
                        $username .= esc_html(ucfirst($user_info->display_name));
                    }
                    $username .= '</a>';
                } elseif ($the_subscription->billing_first_name || $the_subscription->billing_last_name) {
                    $username = trim($the_subscription->billing_first_name . ' ' . $the_subscription->billing_last_name);
                }
                // translators: $1: is opening link, $2: is subscription order number, $3: is closing link tag, $4: is user's name
                $column_content = sprintf(_x('%1$s#%2$s%3$s for %4$s', 'Subscription title on admin table. (e.g.: #211 for John Doe)', 'woocommerce-subscriptions'), '<a href="' . esc_url(admin_url('post.php?post=' . absint($post->ID) . '&action=edit')) . '">', '<strong>' . esc_attr($the_subscription->get_order_number()) . '</strong>', '</a>', $username);
                $column_content .= '</div>';
                $column_content .= '<button type="button" class="toggle-row"><span class="screen-reader-text">' . __('Show more details', 'woocommerce-subscriptions') . '</span></button>';
                break;
            case 'order_items':
                // Display either the item name or item count with a collapsed list of items
                $subscription_items = $the_subscription->get_items();
                switch (count($subscription_items)) {
                    case 0:
                        $column_content .= '&ndash;';
                        break;
                    case 1:
                        foreach ($subscription_items as $item) {
                            $_product = apply_filters('woocommerce_order_item_product', $the_subscription->get_product_from_item($item), $item);
                            $item_meta = wcs_get_order_item_meta($item, $_product);
                            $item_meta_html = $item_meta->display(true, true);
                            $item_quantity = absint($item['qty']);
                            $item_name = '';
                            if (wc_product_sku_enabled() && $_product && $_product->get_sku()) {
                                $item_name .= $_product->get_sku() . ' - ';
                            }
                            $item_name .= $item['name'];
                            $item_name = apply_filters('woocommerce_order_item_name', $item_name, $item);
                            $item_name = esc_html($item_name);
                            if ($item_quantity > 1) {
                                $item_name = sprintf('%s &times; %s', absint($item_quantity), $item_name);
                            }
                            if ($_product) {
                                $item_name = sprintf('<a href="%s">%s</a>', get_edit_post_link($_product->id), $item_name);
                            }
                            ob_start();
                            ?>
							<div class="order-item">
								<?php 
                            echo wp_kses($item_name, array('a' => array('href' => array())));
                            ?>
								<?php 
                            if ($item_meta_html) {
                                ?>
								<a class="tips" href="#" data-tip="<?php 
                                echo esc_attr($item_meta_html);
                                ?>
">[?]</a>
								<?php 
                            }
                            ?>
							</div>
							<?php 
                            $column_content .= ob_get_clean();
                        }
                        break;
                    default:
                        $column_content .= '<a href="#" class="show_order_items">' . esc_html(apply_filters('woocommerce_admin_order_item_count', sprintf(_n('%d item', '%d items', $the_subscription->get_item_count(), 'woocommerce-subscriptions'), $the_subscription->get_item_count()), $the_subscription)) . '</a>';
                        $column_content .= '<table class="order_items" cellspacing="0">';
                        foreach ($the_subscription->get_items() as $item) {
                            $_product = apply_filters('woocommerce_order_item_product', $the_subscription->get_product_from_item($item), $item);
                            $item_meta = wcs_get_order_item_meta($item, $_product);
                            $item_meta_html = $item_meta->display(true, true);
                            ob_start();
                            ?>
							<tr class="<?php 
                            echo esc_attr(apply_filters('woocommerce_admin_order_item_class', '', $item));
                            ?>
">
								<td class="qty"><?php 
                            echo absint($item['qty']);
                            ?>
</td>
								<td class="name">
									<?php 
                            if (wc_product_sku_enabled() && $_product && $_product->get_sku()) {
                                echo esc_html($_product->get_sku()) . ' - ';
                            }
                            echo esc_html(apply_filters('woocommerce_order_item_name', $item['name'], $item));
                            if ($item_meta_html) {
                                ?>
										<a class="tips" href="#" data-tip="<?php 
                                echo esc_attr($item_meta_html);
                                ?>
">[?]</a>
									<?php 
                            }
                            ?>
								</td>
							</tr>
							<?php 
                            $column_content .= ob_get_clean();
                        }
                        $column_content .= '</table>';
                        break;
                }
                break;
            case 'recurring_total':
                $column_content .= esc_html(strip_tags($the_subscription->get_formatted_order_total()));
                // translators: placeholder is the display name of a payment gateway a subscription was paid by
                $column_content .= '<small class="meta">' . esc_html(sprintf(__('Via %s', 'woocommerce-subscriptions'), $the_subscription->get_payment_method_to_display())) . '</small>';
                break;
            case 'start_date':
            case 'trial_end_date':
            case 'next_payment_date':
            case 'last_payment_date':
            case 'end_date':
                if (0 == $the_subscription->get_time($column, 'gmt')) {
                    $column_content .= '-';
                } else {
                    $column_content .= sprintf('<time class="%s" title="%s">%s</time>', esc_attr($column), esc_attr(date(__('Y/m/d g:i:s A', 'woocommerce-subscriptions'), $the_subscription->get_time($column, 'site'))), esc_html($the_subscription->get_date_to_display($column)));
                    if ('next_payment_date' == $column && $the_subscription->payment_method_supports('gateway_scheduled_payments') && !$the_subscription->is_manual() && $the_subscription->has_status('active')) {
                        $column_content .= '<div class="woocommerce-help-tip" data-tip="' . esc_attr__('This date should be treated as an estimate only. The payment gateway for this subscription controls when payments are processed.', 'woocommerce-subscriptions') . '"></div>';
                    }
                }
                $column_content = $column_content;
                break;
            case 'orders':
                $column_content .= $this->get_related_orders_link($the_subscription);
                break;
        }
        echo wp_kses(apply_filters('woocommerce_subscription_list_table_column_content', $column_content, $the_subscription, $column), array('a' => array('class' => array(), 'href' => array(), 'data-tip' => array(), 'title' => array()), 'time' => array('class' => array(), 'title' => array()), 'mark' => array('class' => array(), 'data-tip' => array()), 'small' => array('class' => array()), 'table' => array('class' => array(), 'cellspacing' => array(), 'cellpadding' => array()), 'tr' => array('class' => array()), 'td' => array('class' => array()), 'div' => array('class' => array(), 'data-tip' => array()), 'br' => array(), 'strong' => array(), 'span' => array('class' => array()), 'p' => array('class' => array()), 'button' => array('type' => array(), 'class' => array())));
    }