has_status( $required_status ) && ( 0 == $subscription->get_total() || $subscription->is_manual() || '' == $subscription->get_payment_method() || ! $subscription->payment_method_supports( 'gateway_scheduled_payments' ) ) ) { // Always put the subscription on hold in case something goes wrong while trying to process renewal $subscription->update_status( 'on-hold', $order_note ); // Generate a renewal order for payment gateways to use to record the payment (and determine how much is due) $renewal_order = wcs_create_renewal_order( $subscription ); if ( is_wp_error( $renewal_order ) ) { // let's try this again $renewal_order = wcs_create_renewal_order( $subscription ); if ( is_wp_error( $renewal_order ) ) { // translators: placeholder %1 is an order note. %2 is the error message that was thrown. throw new Exception( sprintf( __( 'Error: Unable to create renewal order with note "%1$s". Message: %2$s', 'woocommerce-subscriptions' ), $order_note, $renewal_order->get_error_message() ) ); } } if ( 0 == $renewal_order->get_total() ) { $renewal_order->payment_complete(); // We don't need to reactivate the subscription here because calling payment complete on the order will do that for us. } else { if ( $subscription->is_manual() ) { do_action( 'woocommerce_generated_manual_renewal_order', wcs_get_objects_property( $renewal_order, 'id' ), $subscription ); $renewal_order->add_order_note( __( 'Manual renewal order awaiting customer payment.', 'woocommerce-subscriptions' ) ); } else { $renewal_order->set_payment_method( wc_get_payment_gateway_by_order( $subscription ) ); // We need to pass the payment gateway instance to be compatible with WC < 3.0, only WC 3.0+ supports passing the string name if ( is_callable( array( $renewal_order, 'save' ) ) ) { // WC 3.0+ We need to save the payment method. $renewal_order->save(); } } } } else { $renewal_order = false; } return $renewal_order; } /** * Expires a single subscription on a users account. * * @param int $subscription_id The ID of a 'shop_subscription' post * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.0 */ public static function expire_subscription( $subscription_id, $deprecated = null ) { if ( null !== $deprecated ) { _deprecated_argument( __METHOD__, '2.0', 'The subscription key is deprecated. Use a subscription post ID' ); $subscription = wcs_get_subscription_from_key( $deprecated ); } else { $subscription = wcs_get_subscription( $subscription_id ); } if ( false === $subscription ) { // translators: placeholder is a subscription ID. throw new InvalidArgumentException( sprintf( __( 'Subscription doesn\'t exist in scheduled action: %d', 'woocommerce-subscriptions' ), $subscription_id ) ); } $subscription->update_status( 'expired' ); } /** * Fires when a cancelled subscription reaches the end of its prepaid term. * * @param int $subscription_id The ID of a 'shop_subscription' post * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.3 */ public static function subscription_end_of_prepaid_term( $subscription_id, $deprecated = null ) { if ( null !== $deprecated ) { _deprecated_argument( __METHOD__, '2.0', 'The subscription key is deprecated. Use a subscription post ID' ); $subscription = wcs_get_subscription_from_key( $deprecated ); } else { $subscription = wcs_get_subscription( $subscription_id ); } if ( $subscription ) { $subscription->update_status( 'cancelled' ); } } /** * Trigger action hook after a subscription's trial period has ended. * * @since 5.5.0 * * @param int $subscription_id */ public static function trigger_subscription_trial_ended_hook( $subscription_id ) { do_action( 'woocommerce_subscription_trial_ended', $subscription_id ); } /** * Records a payment on a subscription. * * @param int $user_id The id of the user who owns the subscription. * @param string $subscription_key A subscription key of the form obtained by @see get_subscription_key( $order_id, $product_id ) * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.0 */ public static function process_subscription_payment( $user_id, $subscription_key ) { _deprecated_function( __METHOD__, '2.0', 'WC_Subscription::payment_complete()' ); $subscription = wcs_get_subscription_from_key( $subscription_key ); $subscription->payment_complete(); // Reset failed payment count & suspension count $subscription = array(); // we only want to reset the failed payments and susp count $subscription['failed_payments'] = $subscription['suspension_count'] = 0; self::update_users_subscriptions( $user_id, array( $subscription_key => $subscription ) ); } /** * Processes a failed payment on a subscription by recording the failed payment and cancelling the subscription if it exceeds the * maximum number of failed payments allowed on the site. * * @param int $user_id The id of the user who owns the expiring subscription. * @param string $subscription_key A subscription key of the form obtained by @see get_subscription_key( $order_id, $product_id ) * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.0 */ public static function process_subscription_payment_failure( $user_id, $subscription_key ) { _deprecated_function( __METHOD__, '2.0', 'WC_Subscription::payment_failed()' ); $subscription = wcs_get_subscription_from_key( $subscription_key ); // Allow a short circuit for plugins & payment gateways to force max failed payments exceeded if ( apply_filters( 'woocommerce_subscriptions_max_failed_payments_exceeded', false, $user_id, $subscription_key ) ) { $new_status = 'cancelled'; } else { $new_status = 'on-hold'; } $subscription->payment_failed( $new_status ); // Reset failed payment count & suspension count $subscription = array(); // we only want to reset the failed payments and susp count $subscription['failed_payments'] = $subscription['failed_payments'] + 1; self::update_users_subscriptions( $user_id, array( $subscription_key => $subscription ) ); } /** * This function should be called whenever a subscription payment is made on an order. This includes * when the subscriber signs up and for a recurring payment. * * The function is a convenience wrapper for @see self::process_subscription_payment(), so if calling that * function directly, do not call this function also. * * @param WC_Order|int $order The order or ID of the order for which subscription payments should be marked against. * @param int $product_id The ID of the product. * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.0 */ public static function process_subscription_payments_on_order( $order, $product_id = 0 ) { wcs_deprecated_function( __METHOD__, '2.6.0' ); $subscriptions = wcs_get_subscriptions_for_order( $order ); if ( ! empty( $subscriptions ) ) { foreach ( $subscriptions as $subscription ) { $subscription->payment_complete(); } do_action( 'processed_subscription_payments_for_order', $order ); } } /** * This function should be called whenever a subscription payment has failed on a parent order. * * The function is a convenience wrapper for @see self::process_subscription_payment_failure(), so if calling that * function directly, do not call this function also. * * @param int|WC_Order $order The order or ID of the order for which subscription payments should be marked against. * @param int $product_id The ID of the product. * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.0 */ public static function process_subscription_payment_failure_on_order( $order, $product_id = 0 ) { wcs_deprecated_function( __METHOD__, '2.6.0' ); $subscriptions = wcs_get_subscriptions_for_order( $order ); if ( ! empty( $subscriptions ) ) { foreach ( $subscriptions as $subscription ) { $subscription->payment_failed(); } do_action( 'processed_subscription_payment_failure_for_order', $order ); } } /** * Activates all the subscriptions created by a given order. * * @param WC_Order|int $order The order or ID of the order for which subscriptions should be marked as activated. * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.0 */ public static function activate_subscriptions_for_order( $order ) { $subscriptions = wcs_get_subscriptions_for_order( $order ); if ( ! empty( $subscriptions ) ) { foreach ( $subscriptions as $subscription ) { try { $subscription->update_status( 'active' ); } catch ( Exception $e ) { // translators: $1: order number, $2: error message $subscription->add_order_note( sprintf( __( 'Failed to activate subscription status for order #%1$s: %2$s', 'woocommerce-subscriptions' ), is_object( $order ) ? $order->get_order_number() : $order, $e->getMessage() ) ); } } do_action( 'subscriptions_activated_for_order', $order ); } } /** * Suspends all the subscriptions on an order by changing their status to "on-hold". * * @param WC_Order|int $order The order or ID of the order for which subscriptions should be marked as activated. * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.0 */ public static function put_subscription_on_hold_for_order( $order ) { $subscriptions = wcs_get_subscriptions_for_order( $order, array( 'order_type' => 'parent' ) ); if ( ! empty( $subscriptions ) ) { foreach ( $subscriptions as $subscription ) { try { if ( $subscription->can_be_updated_to( 'on-hold' ) ) { $subscription->update_status( 'on-hold' ); } } catch ( Exception $e ) { // translators: $1: order number, $2: error message $subscription->add_order_note( sprintf( __( 'Failed to update subscription status after order #%1$s was put on-hold: %2$s', 'woocommerce-subscriptions' ), is_object( $order ) ? $order->get_order_number() : $order, $e->getMessage() ) ); } } do_action( 'subscriptions_put_on_hold_for_order', $order ); } } /** * Mark all subscriptions in an order as cancelled on the user's account. * * @param WC_Order|int $order The order or ID of the order for which subscriptions should be marked as cancelled. * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.0 */ public static function cancel_subscriptions_for_order( $order ) { $subscriptions = wcs_get_subscriptions_for_order( $order, array( 'order_type' => 'parent' ) ); if ( ! empty( $subscriptions ) ) { foreach ( $subscriptions as $subscription ) { try { if ( ! $subscription->has_status( wcs_get_subscription_ended_statuses() ) ) { $subscription->cancel_order(); } } catch ( Exception $e ) { // translators: $1: order number, $2: error message $subscription->add_order_note( sprintf( __( 'Failed to cancel subscription after order #%1$s was cancelled: %2$s', 'woocommerce-subscriptions' ), is_object( $order ) ? $order->get_order_number() : $order, $e->getMessage() ) ); } } do_action( 'subscriptions_cancelled_for_order', $order ); } } /** * Marks all the subscriptions in an order as expired * * @param WC_Order|int $order The order or ID of the order for which subscriptions should be marked as expired. * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.0 */ public static function expire_subscriptions_for_order( $order ) { $subscriptions = wcs_get_subscriptions_for_order( $order ); if ( ! empty( $subscriptions ) ) { foreach ( $subscriptions as $subscription ) { try { if ( ! $subscription->has_status( wcs_get_subscription_ended_statuses() ) ) { $subscription->update_status( 'expired' ); } } catch ( Exception $e ) { // translators: $1: order number, $2: error message $subscription->add_order_note( sprintf( __( 'Failed to set subscription as expired for order #%1$s: %2$s', 'woocommerce-subscriptions' ), is_object( $order ) ? $order->get_order_number() : $order, $e->getMessage() ) ); } } do_action( 'subscriptions_expired_for_order', $order ); } } /** * Called when a sign up fails during the payment processing step. * * This method only performs actions when a parent order changed to failed status. * Overlaps with WC_Subscriptions_Order::maybe_record_subscription_payment. * * @param WC_Order|int $order The order or ID of the order for which subscriptions should be marked as failed. * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.0 */ public static function failed_subscription_sign_ups_for_order( $order ) { $subscriptions = wcs_get_subscriptions_for_order( $order, array( 'order_type' => 'parent' ) ); if ( empty( $subscriptions ) ) { return; } if ( ! is_object( $order ) ) { $order = wc_get_order( $order ); } // Set subscription status to failed and log failure if ( $order->has_status( 'failed' ) ) { $order->update_status( 'failed', __( 'Subscription sign up failed.', 'woocommerce-subscriptions' ) ); } foreach ( $subscriptions as $subscription ) { try { /** * Parent status failure should not change the subscription status in most cases. * We only change the status when the parent order is the last order and subscription is active. * In that case, we need to put the subscription on hold as we do when the latest renewal order fails. * Examples: * - if subscription is pending and initial payment fails, we keep subscription as pending to activate it on successful payment. * - if subscription has successful renewals and somehow the parent order fails after that, we still keep subscription as active. * - if subscription is active after successful initial payment, but later the parent order fails, we move subscription to on-hold. */ $new_status = $subscription->get_status(); if ( 'active' === $new_status && $subscription->get_parent_id() === $order->get_id() ) { $last_order = $subscription->get_last_order( 'ids', 'any' ); $new_status = $last_order === $order->get_id() ? 'on-hold' : 'active'; } $subscription->payment_failed_for_related_order( $new_status, $order ); } catch ( Exception $e ) { // translators: $1: order number, $2: error message $subscription->add_order_note( sprintf( __( 'Failed to process failed payment on subscription for order #%1$s: %2$s', 'woocommerce-subscriptions' ), is_object( $order ) ? $order->get_order_number() : $order, $e->getMessage() ) ); } } /** * Fires after an order is marked as failed. * * @param WC_Order $order Failed order object. * * @since 1.5.0 */ do_action( 'failed_subscription_sign_ups_for_order', $order ); } /** * Uses the details of an order to create a pending subscription on the customers account * for a subscription product, as specified with $product_id. * * @param int|WC_Order $order The order ID or WC_Order object to create the subscription from. * @param int $product_id The ID of the subscription product on the order, if a variation, it must be the variation's ID. * @param array $args An array of name => value pairs to customise the details of the subscription, including: * 'start_date' A MySQL formatted date/time string on which the subscription should start, in UTC timezone * 'expiry_date' A MySQL formatted date/time string on which the subscription should expire, in UTC timezone * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.1 */ public static function create_pending_subscription_for_order( $order, $product_id, $args = array() ) { _deprecated_function( __METHOD__, '2.0', 'wcs_create_subscription()' ); if ( ! is_object( $order ) ) { $order = new WC_Order( $order ); } if ( ! WC_Subscriptions_Product::is_subscription( $product_id ) ) { return; } $args = wp_parse_args( $args, array( 'start_date' => wcs_get_datetime_utc_string( wcs_get_objects_property( $order, 'date_created' ) ), // get_date_created() can return null, but if it does, we have an error anyway 'expiry_date' => '', ) ); $billing_period = WC_Subscriptions_Product::get_period( $product_id ); $billing_interval = WC_Subscriptions_Product::get_interval( $product_id ); // Support passing timestamps $args['start_date'] = is_numeric( $args['start_date'] ) ? gmdate( 'Y-m-d H:i:s', $args['start_date'] ) : $args['start_date']; $product = wc_get_product( $product_id ); // Check if there is already a subscription for this product and order $subscriptions = wcs_get_subscriptions( array( 'order_id' => wcs_get_objects_property( $order, 'id' ), 'product_id' => $product_id, ) ); if ( ! empty( $subscriptions ) ) { $subscription = array_pop( $subscriptions ); // Make sure the subscription is pending and start date is set correctly wp_update_post( array( 'ID' => $subscription->get_id(), 'post_status' => 'wc-' . apply_filters( 'woocommerce_default_subscription_status', 'pending' ), 'post_date' => get_date_from_gmt( $args['start_date'] ), ) ); } else { $subscription = wcs_create_subscription( array( 'start_date' => get_date_from_gmt( $args['start_date'] ), 'order_id' => wcs_get_objects_property( $order, 'id' ), 'customer_id' => $order->get_user_id(), 'billing_period' => $billing_period, 'billing_interval' => $billing_interval, 'customer_note' => wcs_get_objects_property( $order, 'customer_note' ), ) ); if ( is_wp_error( $subscription ) ) { throw new Exception( __( 'Error: Unable to create subscription. Please try again.', 'woocommerce-subscriptions' ) ); } $item_id = $subscription->add_product( $product, 1, array( 'variation' => ( method_exists( $product, 'get_variation_attributes' ) ) ? $product->get_variation_attributes() : array(), 'totals' => array( 'subtotal' => $product->get_price(), 'subtotal_tax' => 0, 'total' => $product->get_price(), 'tax' => 0, 'tax_data' => array( 'subtotal' => array(), 'total' => array(), ), ), ) ); if ( ! $item_id ) { throw new Exception( __( 'Error: Unable to add product to created subscription. Please try again.', 'woocommerce-subscriptions' ) ); } } // Make sure some of the meta is copied form the order rather than the store's defaults if ( wcs_get_objects_property( $order, 'prices_include_tax' ) ) { $prices_include_tax = 'yes'; } else { $prices_include_tax = 'no'; } update_post_meta( $subscription->get_id(), '_order_currency', wcs_get_objects_property( $order, 'currency' ) ); update_post_meta( $subscription->get_id(), '_prices_include_tax', $prices_include_tax ); // Adding a new subscription so set the expiry date/time from the order date if ( ! empty( $args['expiry_date'] ) ) { if ( is_numeric( $args['expiry_date'] ) ) { $args['expiry_date'] = gmdate( 'Y-m-d H:i:s', $args['expiry_date'] ); } $expiration = $args['expiry_date']; } else { $expiration = WC_Subscriptions_Product::get_expiration_date( $product_id, $args['start_date'] ); } // Adding a new subscription so set the expiry date/time from the order date $trial_expiration = WC_Subscriptions_Product::get_trial_expiration_date( $product_id, $args['start_date'] ); $dates_to_update = array(); if ( $trial_expiration > 0 ) { $dates_to_update['trial_end'] = $trial_expiration; } if ( $expiration > 0 ) { $dates_to_update['end'] = $expiration; } if ( ! empty( $dates_to_update ) ) { $subscription->update_dates( $dates_to_update ); } // Set the recurring totals on the subscription $subscription->set_total( 0, 'tax' ); $subscription->set_total( $product->get_price(), 'total' ); $subscription->add_order_note( __( 'Pending subscription created.', 'woocommerce-subscriptions' ) ); do_action( 'pending_subscription_created_for_order', $order, $product_id ); } /** * Excludes subscriptions from the order cleanup process. * * @param bool $should_cancel Whether the order should be cancelled. * @param WC_Order $order The order object. * * @return bool Whether the order should be cancelled. */ public static function exclude_subscription_from_order_cleanup( $should_cancel, $order ) { if ( $should_cancel && 'shop_subscription' === $order->get_type() ) { $should_cancel = false; } return $should_cancel; } /** * Creates subscriptions against a users account with a status of pending when a user creates * an order containing subscriptions. * * @param int|WC_Order $order The order ID or WC_Order object to create the subscription from. * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.0 */ public static function process_subscriptions_on_checkout( $order ) { _deprecated_function( __METHOD__, '2.0', 'WC_Subscriptions_Checkout::process_checkout()' ); if ( ! empty( $_POST['_wpnonce'] ) && wp_verify_nonce( wc_clean( wp_unslash( $_POST['_wpnonce'] ) ), 'woocommerce-process_checkout' ) ) { WC_Subscriptions_Checkout::process_checkout( $order, $_POST ); } } /** * Updates a user's subscriptions for each subscription product in the order. * * @param WC_Order $order The order to get subscriptions and user details from. * @param string $status (optional) A status to change the subscriptions in an order to. Default is 'active'. * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.0 */ public static function update_users_subscriptions_for_order( $order, $status = 'pending' ) { _deprecated_function( __METHOD__, '2.0', 'WC_Subscriptions::update_status()' ); if ( ! is_object( $order ) ) { $order = new WC_Order( $order ); } if ( 'suspend' === $status ) { $status = 'on-hold'; _deprecated_argument( __METHOD__, '1.2', 'The "suspend" status value is deprecated. Use "on-hold"' ); } foreach ( wcs_get_subscriptions_for_order( wcs_get_objects_property( $order, 'id' ), array( 'order_type' => 'parent' ) ) as $subscription_id => $subscription ) { switch ( $status ) { case 'cancelled': $subscription->cancel_order(); break; case 'active': case 'expired': case 'on-hold': $subscription->update_status( $status ); break; case 'failed': _deprecated_argument( __METHOD__, '2.0', 'The "failed" status value is deprecated.' ); self::failed_subscription_signup( $order->get_user_id(), $subscription_id ); break; case 'pending': _deprecated_argument( __METHOD__, '2.0', 'The "pending" status value is deprecated.' ); default: // @phpstan-ignore arguments.count self::create_pending_subscription_for_order( $order ); break; } } do_action( 'updated_users_subscriptions_for_order', $order, $status ); } /** * Takes a user ID and array of subscription details and updates the users subscription details accordingly. * * @uses wp_parse_args To allow only part of a subscription's details to be updated, like status. * @param int $user_id The ID of the user for whom subscription details should be updated * @param array $subscriptions An array of arrays with a subscription key and corresponding 'detail' => 'value' pair. Can alter any of these details: * 'start_date' The date the subscription was activated * 'expiry_date' The date the subscription expires or expired, false if the subscription will never expire * 'failed_payments' The date the subscription's trial expires or expired, false if the subscription has no trial period * 'end_date' The date the subscription ended, false if the subscription has not yet ended * 'status' Subscription status can be: cancelled, active, expired or failed * 'completed_payments' An array of MySQL formatted dates for all payments that have been made on the subscription * 'failed_payments' An integer representing a count of failed payments * 'suspension_count' An integer representing a count of the number of times the subscription has been suspended for this billing period * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.0 */ public static function update_users_subscriptions( $user_id, $subscriptions ) { _deprecated_function( __METHOD__, '2.0', 'WC_Subscriptions API methods' ); foreach ( $subscriptions as $subscription_key => $new_subscription_details ) { $subscription = wcs_get_subscription_from_key( $subscription_key ); if ( isset( $new_subscription_details['status'] ) && 'deleted' == $new_subscription_details['status'] ) { wp_delete_post( $subscription->get_id() ); } else { // There is no direct analog for this in WC_Subscription, so we need to call the deprecated method self::update_subscription( $subscription_key, $new_subscription_details ); } } do_action( 'updated_users_subscriptions', $user_id, $subscriptions ); return self::get_users_subscriptions( $user_id ); // We need to call this deprecated method to preserve the return value in the deprecated array structure } /** * Takes a subscription key and array of subscription details and updates the users subscription details accordingly. * * @uses wp_parse_args To allow only part of a subscription's details to be updated, like status. * @param string $subscription_key A subscription key of the form created by @see self::get_subscription_key() * @param array $new_subscription_details An array of arrays with a subscription key and corresponding 'detail' => 'value' pair. Can alter any of these details: * 'start_date' The date the subscription was activated * 'expiry_date' The date the subscription expires or expired, false if the subscription will never expire * 'failed_payments' The date the subscription's trial expires or expired, false if the subscription has no trial period * 'end_date' The date the subscription ended, false if the subscription has not yet ended * 'status' Subscription status can be: cancelled, active, expired or failed * 'completed_payments' An array of MySQL formatted dates for all payments that have been made on the subscription * 'failed_payments' An integer representing a count of failed payments * 'suspension_count' An integer representing a count of the number of times the subscription has been suspended for this billing period * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.4 */ public static function update_subscription( $subscription_key, $new_subscription_details ) { _deprecated_function( __METHOD__, '2.0', 'WC_Subscriptions API methods' ); $subscription = wcs_get_subscription_from_key( $subscription_key ); if ( isset( $new_subscription_details['status'] ) && 'deleted' == $new_subscription_details['status'] ) { wp_delete_post( $subscription->get_id() ); } else { foreach ( $new_subscription_details as $meta_key => $meta_value ) { switch ( $meta_key ) { case 'start_date': $subscription->update_dates( array( 'date_created' => $meta_value ) ); break; case 'trial_expiry_date': $subscription->update_dates( array( 'trial_end' => $meta_value ) ); break; case 'expiry_date': $subscription->update_dates( array( 'end' => $meta_value ) ); break; case 'failed_payments': _deprecated_argument( __METHOD__, '2.0', 'The "failed_payments" meta value is deprecated. Create a renewal order with "failed" status instead.' ); break; case 'completed_payments': _deprecated_argument( __METHOD__, '2.0', 'The "completed_payments" meta value is deprecated. Create a renewal order with completed payment instead.' ); break; case 'suspension_count': $subscription->set_suspension_count( $subscription->get_suspension_count() + 1 ); break; } } } do_action( 'updated_users_subscription', $subscription_key, $new_subscription_details ); return wcs_get_subscription_in_deprecated_structure( $subscription ); } /** * Takes a user ID and cancels any subscriptions that user has. * * @uses wp_parse_args To allow only part of a subscription's details to be updated, like status. * @param int $user_id The ID of the user for whom subscription details should be updated * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.3.8 */ public static function cancel_users_subscriptions( $user_id ) { $subscriptions = wcs_get_users_subscriptions( $user_id ); if ( ! empty( $subscriptions ) ) { foreach ( $subscriptions as $subscription ) { if ( $subscription->can_be_updated_to( 'cancelled' ) ) { $subscription->update_status( 'cancelled' ); } } do_action( 'cancelled_users_subscriptions', $user_id ); } } /** * Takes a user ID and cancels any subscriptions that user has on any site in a WordPress network * * @uses wp_parse_args To allow only part of a subscription's details to be updated, like status. * @param int $user_id The ID of the user for whom subscription details should be updated * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.3.8 */ public static function cancel_users_subscriptions_for_network( $user_id ) { $sites = get_blogs_of_user( $user_id ); if ( ! empty( $sites ) ) { foreach ( $sites as $site ) { switch_to_blog( $site->userblog_id ); self::cancel_users_subscriptions( $user_id ); restore_current_blog(); } } do_action( 'cancelled_users_subscriptions_for_network', $user_id ); } /** * Clear all subscriptions for a given order. * * @param WC_Order $order The order for which subscriptions should be cleared. * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.0 */ public static function clear_users_subscriptions_from_order( $order ) { foreach ( wcs_get_subscriptions_for_order( $order, array( 'order_type' => 'parent' ) ) as $subscription_id => $subscription ) { $subscription->delete( true ); } do_action( 'cleared_users_subscriptions_from_order', $order ); } /** * Trash all subscriptions attached to an order when it's trashed. * * Also make sure all related scheduled actions are cancelled when deleting a subscription. * * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.0 * * @param int $order_id The order ID of the WC Subscription or WC Order being trashed */ public static function maybe_trash_subscription( $order_id ) { if ( 'shop_order' === WC_Data_Store::load( 'order' )->get_order_type( $order_id ) ) { // delete subscription foreach ( wcs_get_subscriptions_for_order( $order_id, [ 'order_type' => 'parent' ] ) as $subscription ) { $subscription->delete(); } } } /** * Untrash all subscriptions attached to an order when it's restored. * * @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.2.17 * * @param int $order_id The Order ID of the order being restored */ public static function maybe_untrash_subscription( $order_id ) { if ( 'shop_order' !== WC_Data_Store::load( 'order' )->get_order_type( $order_id ) ) { return; } $data_store = WC_Data_Store::load( 'subscription' ); $use_crud_method = method_exists( $data_store, 'has_callable' ) && $data_store->has_callable( 'untrash_order' ); $subscriptions = wcs_get_subscriptions_for_order( $order_id, [ 'order_type' => 'parent', 'subscription_status' => [ 'trash' ], ] ); foreach ( $subscriptions as $subscription ) { if ( $use_crud_method ) { $data_store->untrash_order( $subscription ); } else { wp_untrash_post( $subscription->get_id() ); } } } /** * Delete related subscriptions when an order is deleted. * * @param int $order_id The post ID being deleted. */ public static function maybe_delete_subscription( $order_id ) { if ( 'shop_order' !== WC_Data_Store::load( 'order' )->get_order_type( $order_id ) ) { return; } /** @var WC_Subscription[] $subscriptions */ $subscriptions = wcs_get_subscriptions_for_order( $order_id, [ 'order_type' => 'parent', 'subscription_status' => [ 'any', 'trash' ], ] ); foreach ( $subscriptions as $subscription ) { $subscription->delete( true ); } } /** * Make sure a subscription is cancelled before it is trashed or deleted * * @param int $id * @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.0 */ public static function maybe_cancel_subscription( $id ) { $subscription = wcs_get_subscription( $id ); if ( ! $subscription ) { return; } if ( $subscription->get_type() !== 'shop_subscription' ) { return; } if ( $subscription->can_be_updated_to( 'cancelled' ) ) { $subscription->update_status( 'cancelled' ); } } /** * When an order is trashed, store the '_wp_trash_meta_status' meta value with a cancelled subscription status * to prevent subscriptions being restored with an active status. * * When WordPress and WooCommerce set this meta value, they use the status of the order in memory. * If that status is changed on the before trashed or before deleted hooks, * as is the case with a subscription, which is cancelled before being trashed if it is active or on-hold, * then the '_wp_trash_meta_status' value will be incorrectly set to its status before being trashed. * * This function fixes that by setting '_wp_trash_meta_status' to 'wc-cancelled' whenever its former status * is something that can not be restored. * * @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.0 * * @param int $id */ public static function fix_trash_meta_status( $id ) { $subscription = wcs_get_subscription( $id ); if ( ! $subscription ) { return; } if ( $subscription->get_type() !== 'shop_subscription' ) { return; } $data_store = $subscription->get_data_store(); $meta_data = $data_store->read_meta( $subscription ); foreach ( $meta_data as $meta ) { if ( '_wp_trash_meta_status' === $meta->meta_key && ! in_array( $meta->meta_value, [ 'wc-pending', 'wc-expired', 'wc-cancelled' ], true ) ) { $new_meta = (object) [ 'id' => $meta->meta_id, 'key' => $meta->meta_key, 'value' => 'wc-cancelled', ]; $data_store->update_meta( $subscription, $new_meta ); break; } } } /** * Trigger action hook after a subscription has been trashed. * * @param int $id * @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.0 */ public static function trigger_subscription_trashed_hook( $id ) { if ( 'shop_subscription' === WC_Data_Store::load( 'subscription' )->get_order_type( $id ) ) { do_action( 'woocommerce_subscription_trashed', $id ); } } /** * Takes a user ID and trashes any subscriptions that user has. * * @param int $user_id The ID of the user whose subscriptions will be trashed * @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.0 */ public static function trash_users_subscriptions( $user_id ) { $subscriptions = wcs_get_users_subscriptions( $user_id ); $current_user = is_user_logged_in() ? wp_get_current_user() : null; if ( ! empty( $subscriptions ) ) { foreach ( $subscriptions as $subscription ) { $subscription_number = $subscription->get_order_number(); if ( WCS_Gifting::is_gifted_subscription( $subscription ) ) { // translators: %s is the email address of the recipient. $message = sprintf( __( 'The gifted subscription moved to the purchaser after the recipient user with email address %s was deleted.', 'woocommerce-subscriptions' ), $subscription->get_meta( '_recipient_user_email_address' ) ); $subscription->delete_meta_data( '_recipient_user' ); $subscription->delete_meta_data( '_recipient_user_email_address' ); $subscription->save(); $subscription->add_order_note( $message, $subscription_number ); // Check needed for tests. if ( $subscription->get_parent() ) { $subscription->get_parent()->add_order_note( $message, $subscription_number ); } continue; } // Before deleting the subscription, add an order note to the related orders. foreach ( $subscription->get_related_orders( 'all', array( 'parent', 'renewal', 'switch' ) ) as $order ) { if ( $current_user ) { // Translators: 1: The subscription ID number. 2: The current user's username. $order->add_order_note( sprintf( __( 'The related subscription #%1$s has been deleted after the customer was deleted by %2$s.', 'woocommerce-subscriptions' ), $subscription_number, $current_user->display_name ) ); } else { // Translators: Placeholder is the subscription ID number. $order->add_order_note( sprintf( __( 'The related subscription #%s has been deleted after the customer was deleted.', 'woocommerce-subscriptions' ), $subscription_number ) ); } } $subscription->delete( true ); } } } /** * Takes a user ID and trashes any subscriptions that user has on any site in a WordPress network * * @param int $user_id The ID of the user whose subscriptions will be trashed * @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.0 */ public static function trash_users_subscriptions_for_network( $user_id ) { $sites = get_blogs_of_user( $user_id ); if ( ! empty( $sites ) ) { foreach ( $sites as $site ) { switch_to_blog( $site->userblog_id ); self::trash_users_subscriptions( $user_id ); restore_current_blog(); } } } /** * Trigger action hook after a subscription has been deleted. * * @param int $id * @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.0 */ public static function trigger_subscription_deleted_hook( $id ) { if ( 'shop_subscription' === WC_Data_Store::load( 'subscription' )->get_order_type( $id ) ) { do_action( 'woocommerce_subscription_deleted', $id ); } } /** * 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.0 - Migrated from WooCommerce Subscriptions v1.0 * @deprecated 1.0.0 - Migrated from WooCommerce Subscriptions v2.0 */ public static function maybe_change_users_subscription() { _deprecated_function( __METHOD__, '2.0', 'WCS_User_Change_Status_Handler::maybe_change_users_subscription()' ); WCS_User_Change_Status_Handler::maybe_change_users_subscription(); } /** * Check if a given subscription can be changed to a given a status. * * The function checks the subscription's current status and if the payment gateway used to purchase the * subscription allows for the given status to be set via its API. * * @param string $new_status_or_meta The status or meta data you want to change th subscription to. Can be 'active', 'on-hold', 'cancelled', 'expired', 'trash', 'deleted', 'failed', 'new-payment-date' or some other value attached to the 'woocommerce_can_subscription_be_changed_to' filter. * @param string $subscription_key A subscription key of the form created by @see self::get_subscription_key() * @param int $user_id The ID of the user who owns the subscriptions. Although this parameter is optional, if you have the User ID you should pass it to improve performance. * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.0 */ public static function can_subscription_be_changed_to( $new_status_or_meta, $subscription_key, $user_id = 0 ) { _deprecated_function( __METHOD__, '2.0', 'WC_Subscription::can_be_updated_to( $new_status_or_meta )' ); if ( 'new-payment-date' == $new_status_or_meta ) { _deprecated_argument( __METHOD__, '2.0', 'The "new-payment-date" parameter value is deprecated. Use WC_Subscription::can_date_be_updated( "next_payment" ) method instead.' ); } elseif ( 'suspended' == $new_status_or_meta ) { _deprecated_argument( __METHOD__, '2.0', 'The "suspended" parameter value is deprecated. Use "on-hold" instead.' ); $new_status_or_meta = 'on-hold'; } try { $subscription = wcs_get_subscription_from_key( $subscription_key ); switch ( $new_status_or_meta ) { case 'new-payment-date': $subscription_can_be_changed = $subscription->can_date_be_updated( 'next_payment' ); break; case 'active': case 'on-hold': case 'cancelled': case 'expired': case 'trash': case 'deleted': case 'failed': default: $subscription_can_be_changed = $subscription->can_be_updated_to( $new_status_or_meta ); break; } } catch ( Exception $e ) { $subscription_can_be_changed = false; } return $subscription_can_be_changed; } /* * Subscription Getters & Property functions */ /** * Return an associative array of a given subscriptions details (if it exists). * * @param string $subscription_key A subscription key of the form created by @see self::get_subscription_key() * @param mixed $deprecated Don't use * @return array Subscription details * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.1 */ public static function get_subscription( $subscription_key, $deprecated = null ) { if ( null != $deprecated ) { _deprecated_argument( __METHOD__, '1.4', 'Second parameter is deprecated' ); } _deprecated_function( __METHOD__, '2.0', 'wcs_get_subscription( $subscription_id )' ); try { $subscription = wcs_get_subscription_from_key( $subscription_key ); $subscription = wcs_get_subscription_in_deprecated_structure( $subscription ); } catch ( Exception $e ) { $subscription = array(); } return apply_filters( 'woocommerce_get_subscription', $subscription, $subscription_key, $deprecated ); } /** * Return an i18n'ified string for a given subscription status. * * @param string $status An subscription status of it's internal form. * @return string A translated subscription status string for display. * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.2.3 */ public static function get_status_to_display( $status, $subscription_key = '', $user_id = 0 ) { _deprecated_function( __METHOD__, '2.0', 'wcs_get_subscription_statuses()' ); switch ( $status ) { case 'active': $status_string = _x( 'Active', 'Subscription status', 'woocommerce-subscriptions' ); break; case 'cancelled': $status_string = _x( 'Cancelled', 'Subscription status', 'woocommerce-subscriptions' ); break; case 'expired': $status_string = _x( 'Expired', 'Subscription status', 'woocommerce-subscriptions' ); break; case 'pending': $status_string = _x( 'Pending', 'Subscription status', 'woocommerce-subscriptions' ); break; case 'failed': $status_string = _x( 'Failed', 'Subscription status', 'woocommerce-subscriptions' ); break; case 'on-hold': case 'suspend': // Backward compatibility $status_string = _x( 'On-hold', 'Subscription status', 'woocommerce-subscriptions' ); break; default: $status_string = apply_filters( 'woocommerce_subscriptions_custom_status_string', ucfirst( $status ), $subscription_key, $user_id ); } return apply_filters( 'woocommerce_subscriptions_status_string', $status_string, $status, $subscription_key, $user_id ); } /** * Return an i18n'ified associative array of all possible subscription periods. * * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.1 * @deprecated 1.0.0 - Migrated from WooCommerce Subscriptions v2.0 */ public static function get_subscription_period_strings( $number = 1, $period = '' ) { _deprecated_function( __METHOD__, '2.0', 'wcs_get_subscription_period_strings()' ); return wcs_get_subscription_period_strings( $number, $period ); } /** * Return an i18n'ified associative array of all possible subscription periods. * * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.0 * @deprecated 1.0.0 - Migrated from WooCommerce Subscriptions v2.0 */ public static function get_subscription_period_interval_strings( $interval = '' ) { _deprecated_function( __METHOD__, '2.0', 'wcs_get_subscription_period_interval_strings()' ); return wcs_get_subscription_period_interval_strings( $interval ); } /** * Returns an array of subscription lengths. * * PayPal Standard Allowable Ranges * D – for days; allowable range is 1 to 90 * W – for weeks; allowable range is 1 to 52 * M – for months; allowable range is 1 to 24 * Y – for years; allowable range is 1 to 5 * * @param string $subscription_period string (optional) One of day, week, month or year. If empty, all subscription ranges are returned. * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.0 * @deprecated 1.0.0 - Migrated from WooCommerce Subscriptions v2.0 */ public static function get_subscription_ranges( $subscription_period = '' ) { _deprecated_function( __METHOD__, '2.0', 'wcs_get_subscription_ranges()' ); return wcs_get_subscription_ranges( $subscription_period ); } /** * Returns an array of allowable trial periods. * * @see self::get_subscription_ranges() * @param string $subscription_period string (optional) One of day, week, month or year. If empty, all subscription ranges are returned. * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.1 * @deprecated 1.0.0 - Migrated from WooCommerce Subscriptions v2.0 */ public static function get_subscription_trial_lengths( $subscription_period = '' ) { _deprecated_function( __METHOD__, '2.0', 'wcs_get_subscription_trial_lengths( $subscription_period )' ); return wcs_get_subscription_trial_lengths( $subscription_period ); } /** * Return an i18n'ified associative array of all possible subscription trial periods. * * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.2 * @deprecated 1.0.0 - Migrated from WooCommerce Subscriptions v2.0 */ public static function get_subscription_trial_period_strings( $number = 1, $period = '' ) { _deprecated_function( __METHOD__, '2.0', 'wcs_get_subscription_trial_period_strings( $number, $period )' ); return wcs_get_subscription_trial_period_strings( $number, $period ); } /** * Return an i18n'ified associative array of all time periods allowed for subscriptions. * * @param string $form Either 'singular' for singular trial periods or 'plural'. * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.2 * @deprecated 1.0.0 - Migrated from WooCommerce Subscriptions v2.0 */ public static function get_available_time_periods( $form = 'singular' ) { _deprecated_function( __METHOD__, '2.0', 'wcs_get_available_time_periods( $form )' ); return wcs_get_available_time_periods( $form ); } /** * Returns the string key for a subscription purchased in an order specified by $order_id * * @param int $order_id The ID of the order in which the subscription was purchased. * @param int $product_id The ID of the subscription product. * @return string The key representing the given subscription. * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.0 */ public static function get_subscription_key( $order_id, $product_id = 0 ) { _deprecated_function( __METHOD__, '2.0', 'wcs_get_old_subscription_key( WC_Subscription $subscription )' ); // If we have a child renewal order, we need the parent order's ID if ( wcs_order_contains_renewal( $order_id ) ) { $order_id = WC_Subscriptions_Renewal_Order::get_parent_order_id( $order_id ); } // Get the ID of the first order item in a subscription created by this order if ( empty( $product_id ) ) { $subscriptions = wcs_get_subscriptions_for_order( $order_id, array( 'order_type' => 'parent' ) ); foreach ( $subscriptions as $subscription ) { $subscription_items = $subscription->get_items(); if ( ! empty( $subscription_items ) ) { break; } } if ( ! empty( $subscription_items ) ) { $first_item = reset( $subscription_items ); $product_id = WC_Subscriptions_Order::get_items_product_id( $first_item ); } else { $product_id = ''; } } $subscription_key = $order_id . '_' . $product_id; return apply_filters( 'woocommerce_subscription_key', $subscription_key, $order_id, $product_id ); } /** * Returns the number of failed payments for a given subscription. * * @param string $subscription_key A subscription key of the form created by @see self::get_subscription_key() * @param int $user_id The ID of the user who owns the subscriptions. Although this parameter is optional, if you have the User ID you should pass it to improve performance. * @return int The number of outstanding failed payments on the subscription, if any. * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.0 * @deprecated 1.0.0 - Migrated from WooCommerce Subscriptions v2.0 */ public static function get_subscriptions_failed_payment_count( $subscription_key, $user_id = 0 ) { _deprecated_function( __METHOD__, '2.0', 'WC_Subscription::get_failed_payment_count()' ); return apply_filters( 'woocommerce_subscription_failed_payment_count', wcs_get_subscription_from_key( $subscription_key )->get_failed_payment_count(), $user_id, $subscription_key ); } /** * Returns the number of completed payments for a given subscription (including the initial payment). * * @param string $subscription_key A subscription key of the form created by @see self::get_subscription_key() * @return int The number of outstanding failed payments on the subscription, if any. * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.4 * @deprecated 1.0.0 - Migrated from WooCommerce Subscriptions v2.0 */ public static function get_subscriptions_completed_payment_count( $subscription_key ) { _deprecated_function( __METHOD__, '2.0', 'WC_Subscription::get_payment_count()' ); return apply_filters( 'woocommerce_subscription_completed_payment_count', wcs_get_subscription_from_key( $subscription_key )->get_payment_count(), $subscription_key ); } /** * Takes a subscription key and returns the date on which the subscription is scheduled to expire * or 0 if it is cancelled, expired, or never going to expire. * * @param string $subscription_key A subscription key of the form created by @see self::get_subscription_key() * @param int $user_id The ID of the user who owns the subscriptions. Although this parameter is optional, if you have the User ID you should pass it to improve performance. * @param string $type (optional) The format for the Either 'mysql' or 'timestamp'. * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.1 * @deprecated 1.0.0 - Migrated from WooCommerce Subscriptions v2.0 */ public static function get_subscription_expiration_date( $subscription_key, $user_id = 0, $type = 'mysql' ) { _deprecated_function( __METHOD__, '2.0', 'WC_Subscription::get_date( "end" )' ); $subscription = wcs_get_subscription_from_key( $subscription_key ); $expiration_date = ( 'mysql' == $type ) ? $subscription->get_date( 'end' ) : $subscription->get_time( 'end' ); return apply_filters( 'woocommerce_subscription_expiration_date', $expiration_date, $subscription_key, $user_id ); } /** * Updates a subscription's expiration date as scheduled in WP-Cron and in the subscription details array. * * @param string $subscription_key A subscription key of the form created by @see self::get_subscription_key() * @param int $user_id (optional) The ID of the user who owns the subscriptions. Although this parameter is optional, if you have the User ID you should pass it to improve performance. * @param string|int $expiration_date (optional)The date and time the subscription will expire, either as MySQL formatted datetime string or a Unix timestamp. If empty, @see self::calculate_subscription_expiration_date() will be called. * @return mixed If the expiration does not get set, returns false, otherwise it will return a MySQL datetime formatted string for the new date when the subscription will expire * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.2.4 * @deprecated 1.0.0 - Migrated from WooCommerce Subscriptions v2.0 */ public static function set_expiration_date( $subscription_key, $user_id = 0, $expiration_date = '' ) { _deprecated_function( __METHOD__, '2.0', 'WC_Subscription::update_dates( array( "end" => $expiration_date ) )' ); if ( is_int( $expiration_date ) ) { $expiration_date = gmdate( 'Y-m-d H:i:s', $expiration_date ); } $subscription = wcs_get_subscription_from_key( $subscription_key ); return apply_filters( 'woocommerce_subscriptions_set_expiration_date', $subscription->update_dates( array( 'end' => $expiration_date ) ), $subscription->get_date( 'end' ), $subscription_key, $user_id ); } /** * A subscription now either has an end date or it doesn't, there is no way to calculate it based on the original subscription * product (because a WC_Subscription object can have more than one product and syncing length with expiration date was both * cumbersome and error prone). * * Takes a subscription key and calculates the date on which the subscription is scheduled to expire * or 0 if it will never expire. * * @param string $subscription_key A subscription key of the form created by @see self::get_subscription_key() * @param int $user_id The ID of the user who owns the subscriptions. Although this parameter is optional, if you have the User ID you should pass it to improve performance. * @param string $type (optional) The format for the Either 'mysql' or 'timestamp'. * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.1 * @deprecated 1.0.0 - Migrated from WooCommerce Subscriptions v2.0 */ public static function calculate_subscription_expiration_date( $subscription_key, $user_id = 0, $type = 'mysql' ) { _deprecated_function( __METHOD__, '2.0', 'WC_Subscription::get_date( "end" )' ); $subscription = wcs_get_subscription_from_key( $subscription_key ); $expiration_date = ( 'mysql' == $type ) ? $subscription->get_date( 'end' ) : $subscription->get_time( 'end' ); return apply_filters( 'woocommerce_subscription_calculated_expiration_date', $expiration_date, $subscription_key, $user_id ); } /** * Takes a subscription key and returns the date on which the next recurring payment is to be billed, if any. * * @param string $subscription_key A subscription key of the form created by @see self::get_subscription_key() * @param int $user_id The ID of the user who owns the subscriptions. Although this parameter is optional, if you have the User ID you should pass it to improve performance. * @param string $type (optional) The format for the Either 'mysql' or 'timestamp'. * @return mixed If there is no future payment set, returns 0, otherwise it will return a date of the next payment in the form specified by $type * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.2 * @deprecated 1.0.0 - Migrated from WooCommerce Subscriptions v2.0 */ public static function get_next_payment_date( $subscription_key, $user_id = 0, $type = 'mysql' ) { _deprecated_function( __METHOD__, '2.0', 'WC_Subscription::get_date( "next_payment" )' ); $subscription = wcs_get_subscription_from_key( $subscription_key ); $next_payment = ( 'mysql' == $type ) ? $subscription->get_date( 'next_payment' ) : $subscription->get_time( 'next_payment' ); return apply_filters( 'woocommerce_subscription_next_payment_date', $next_payment, $subscription_key, $user_id, $type ); } /** * Clears the payment schedule for a subscription and schedules a new date for the next payment. * * If updating the an existing next payment date (instead of setting a new date, you should use @see self::update_next_payment_date() instead * as it will validate the next payment date and update the WP-Cron lock. * * @param string $subscription_key A subscription key of the form created by @see self::get_subscription_key() * @param int $user_id (optional) The ID of the user who owns the subscriptions. Although this parameter is optional, if you have the User ID you should pass it to improve performance. * @param string|int $next_payment (optional) The date and time the next payment is due, either as MySQL formatted datetime string or a Unix timestamp. If empty, @see self::calculate_next_payment_date() will be called. * @return mixed If there is no future payment set, returns 0, otherwise it will return a MySQL datetime formatted string for the date of the next payment * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.2 * @deprecated 1.0.0 - Migrated from WooCommerce Subscriptions v2.0 */ public static function set_next_payment_date( $subscription_key, $user_id = 0, $next_payment = '' ) { _deprecated_function( __METHOD__, '2.0', 'WC_Subscription::update_dates( array( "next_payment" => $next_payment ) )' ); if ( is_int( $next_payment ) ) { $next_payment = gmdate( 'Y-m-d H:i:s', $next_payment ); } $subscription = wcs_get_subscription_from_key( $subscription_key ); return apply_filters( 'woocommerce_subscription_set_next_payment_date', $subscription->update_dates( array( 'next_payment' => $next_payment ) ), $subscription->get_date( 'next_payment' ), $subscription_key, $user_id ); } /** * Takes a subscription key and returns the date on which the next recurring payment is to be billed, if any. * * @param string $subscription_key A subscription key of the form created by @see self::get_subscription_key() * @param int $user_id The ID of the user who owns the subscriptions. Although this parameter is optional, if you have the User ID you should pass it to improve performance. * @param string $type (optional) The format for the Either 'mysql' or 'timestamp'. * @return mixed If there is no future payment set, returns 0, otherwise it will return a date of the next payment in the form specified by $type * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.2 * @deprecated 1.0.0 - Migrated from WooCommerce Subscriptions v2.0 */ public static function get_last_payment_date( $subscription_key, $user_id = 0, $type = 'mysql' ) { _deprecated_function( __METHOD__, '2.0', 'WC_Subscription::get_date( "last_payment" )' ); $subscription = wcs_get_subscription_from_key( $subscription_key ); $last_payment_date = ( 'mysql' == $type ) ? $subscription->get_date( 'last_order_date_created' ) : $subscription->get_time( 'last_order_date_created' ); return apply_filters( 'woocommerce_subscription_last_payment_date', $last_payment_date, $subscription_key, $user_id, $type ); } /** * Changes the transient used to safeguard against firing scheduled_subscription_payments during a payment period. * * @param string $subscription_key A subscription key of the form created by @see self::get_subscription_key() * @param int $lock_time The amount of time to lock for in seconds from now, the lock will be set 1 hour before this time * @param int $user_id (optional) The ID of the user who owns the subscriptions. Although this parameter is optional, if you have the User ID you should pass it to improve performance. * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.2 * @deprecated 1.0.0 - Migrated from WooCommerce Subscriptions v2.0 */ public static function update_wp_cron_lock( $subscription_key, $lock_time, $user_id = 0 ) { _deprecated_function( __METHOD__, '2.0' ); } /** * Clears the payment schedule for a subscription and sets a net date * * @param string $subscription_key A subscription key of the form created by @see self::get_subscription_key() * @param int $user_id (optional) The ID of the user who owns the subscriptions. Although this parameter is optional, if you have the User ID you should pass it to improve performance. * @param string $type (optional) The format for the Either 'mysql' or 'timestamp'. * @return mixed If there is no future payment set, returns 0, otherwise it will return a date of the next payment of the type specified with $type * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.2 * @deprecated 1.0.0 - Migrated from WooCommerce Subscriptions v2.0 */ public static function calculate_next_payment_date( $subscription_key, $user_id = 0, $type = 'mysql', $from_date = '' ) { _deprecated_function( __METHOD__, '2.0', 'WC_Subscription::calculate_date( "next_payment" )' ); $subscription = wcs_get_subscription_from_key( $subscription_key ); $next_payment = $subscription->calculate_date( 'next_payment' ); return ( 'mysql' == $type ) ? $next_payment : wcs_date_to_time( $next_payment ); } /** * Takes a subscription key and returns the date on which the trial for the subscription ended or is going to end, if any. * * @param string $subscription_key A subscription key of the form created by @see self::get_subscription_key() * @param int $user_id The ID of the user who owns the subscriptions. Although this parameter is optional, if you have the User ID you should pass it to improve performance. * @return mixed If the subscription has no trial period, returns 0, otherwise it will return the date the trial period ends or ended in the form specified by $type * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.2 */ public static function get_trial_expiration_date( $subscription_key, $user_id = 0, $type = 'mysql' ) { _deprecated_function( __METHOD__, '2.0', 'WC_Subscription::get_date( "trial_end" )' ); $subscription = wcs_get_subscription_from_key( $subscription_key ); $trial_end_date = ( 'mysql' == $type ) ? $subscription->get_date( 'trial_end' ) : $subscription->get_time( 'trial_end' ); return apply_filters( 'woocommerce_subscription_trial_expiration_date', $trial_end_date, $subscription_key, $user_id, $type ); } /** * Updates the trial expiration date as scheduled in WP-Cron and in the subscription details array. * * @param string $subscription_key A subscription key of the form created by @see self::get_subscription_key() * @param int $user_id (optional) The ID of the user who owns the subscription. Although this parameter is optional, if you have the User ID you should pass it to improve performance. * @param string|int $trial_expiration_date (optional) The date and time the trial will expire, either as MySQL formatted datetime string or a Unix timestamp. If empty, @see self::calculate_next_payment_date() will be called. * @return mixed If the trial expiration does not get set, returns false, otherwise it will return a MySQL datetime formatted string for the new date when the trial will expire * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.2.4 */ public static function set_trial_expiration_date( $subscription_key, $user_id = 0, $trial_expiration_date = '' ) { _deprecated_function( __METHOD__, '2.0', 'WC_Subscription::update_dates( array( "trial_end" => $expiration_date ) )' ); if ( is_int( $trial_expiration_date ) ) { $trial_expiration_date = gmdate( 'Y-m-d H:i:s', $trial_expiration_date ); } $subscription = wcs_get_subscription_from_key( $subscription_key ); return apply_filters( 'woocommerce_subscriptions_set_trial_expiration_date', $subscription->update_dates( array( 'trial_end' => $trial_expiration_date ) ), $subscription->get_date( 'trial_end' ), $subscription_key, $user_id ); } /** * Takes a subscription key and calculates the date on which the subscription's trial should end * or 0 if no trial is set. * * @param string $subscription_key A subscription key of the form created by @see self::get_subscription_key() * @param int $user_id The ID of the user who owns the subscriptions. Although this parameter is optional, if you have the User ID you should pass it to improve performance. * @param string $type (optional) The format for the Either 'mysql' or 'timestamp'. * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.1 */ public static function calculate_trial_expiration_date( $subscription_key, $user_id = 0, $type = 'mysql' ) { _deprecated_function( __METHOD__, '2.0', 'WC_Subscription::calculate_date( "trial_end" )' ); $subscription = wcs_get_subscription_from_key( $subscription_key ); $trial_end = $subscription->calculate_date( 'trial_end' ); $trial_end = ( 'mysql' == $type ) ? $trial_end : wcs_date_to_time( $trial_end ); return apply_filters( 'woocommerce_subscription_calculated_trial_expiration_date', $trial_end, $subscription_key, $user_id ); } /** * Takes a subscription key and returns the user who owns the subscription (based on the order ID in the subscription key). * * @param string $subscription_key A subscription key of the form created by @see self::get_subscription_key() * @return int The ID of the user who owns the subscriptions, or 0 if no user can be found with the subscription * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.2 */ public static function get_user_id_from_subscription_key( $subscription_key ) { _deprecated_function( __METHOD__, '2.0', 'WC_Subscription::get_user_id()' ); $subscription = wcs_get_subscription_from_key( $subscription_key ); return $subscription->get_user_id(); } /** * Checks if a subscription requires manual payment because the payment gateway used to purchase the subscription * did not support automatic payments at the time of the subscription sign up. * * @param string $subscription_key A subscription key of the form created by @see self::get_subscription_key() * @param int $user_id The ID of the user who owns the subscriptions. Although this parameter is optional, if you have the User ID you should pass it to improve performance. * @return bool | null True if the subscription exists and requires manual payments, false if the subscription uses automatic payments, null if the subscription doesn't exist. * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.2 * @deprecated 1.0.0 - Migrated from WooCommerce Subscriptions v2.0 */ public static function requires_manual_renewal( $subscription_key, $user_id = 0 ) { _deprecated_function( __METHOD__, '2.0', 'WC_Subscription::is_manual()' ); return wcs_get_subscription_from_key( $subscription_key )->is_manual(); } /** * Checks if a subscription has an unpaid renewal order. * * @param string $subscription_key A subscription key of the form created by @see self::get_subscription_key() * @param int $user_id The ID of the user who owns the subscriptions. Although this parameter is optional, if you have the User ID you should pass it to improve performance. * @return bool True if the subscription has an unpaid renewal order, false if the subscription has no unpaid renewal orders. * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.2 */ public static function subscription_requires_payment( $subscription_key, $user_id ) { _deprecated_function( __METHOD__, '2.0', 'WC_Subscription::needs_payment()' ); $subscription = wcs_get_subscription_from_key( $subscription_key ); return apply_filters( 'woocommerce_subscription_requires_payment', $subscription->needs_payment(), wcs_get_subscription_in_deprecated_structure( $subscription ), $subscription_key, $user_id ); } /* * User API Functions */ /** * Check if a user owns a subscription, as specified with $subscription_key. * * If no user is specified, the currently logged in user will be used. * * @param string $subscription_key A subscription key of the form created by @see self::get_subscription_key() * @param int $user_id (optional) int The ID of the user to check against. Defaults to the currently logged in user. * @return bool True if the user has the subscription (or any subscription if no subscription specified), otherwise false. * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.3 * @deprecated 1.0.0 - Migrated from WooCommerce Subscriptions v2.0 */ public static function user_owns_subscription( $subscription_key, $user_id = 0 ) { _deprecated_function( __METHOD__, '2.0', 'WC_Subscriptions::get_user_id()' ); if ( 0 === $user_id ) { $user_id = get_current_user_id(); } $subscription = wcs_get_subscription_from_key( $subscription_key ); if ( $subscription->get_user_id() == $user_id ) { $owns_subscription = true; } else { $owns_subscription = false; } return apply_filters( 'woocommerce_user_owns_subscription', $owns_subscription, $subscription_key, $user_id ); } /** * Check if a user has a subscription, optionally specified with $product_id. * * @param int $user_id (optional) The id of the user whose subscriptions you want. Defaults to the currently logged in user. * @param int $product_id (optional) The ID of a subscription product. * @param string $status (optional) A subscription status to check against. For example, for a $status of 'active', a subscriber must have an active subscription for a return value of true. * @return bool True if the user has the subscription (or any subscription if no subscription specified), otherwise false. * @version 1.0.0 - Migrated from WooCommerce Subscriptions v1.3.5 */ public static function user_has_subscription( $user_id = 0, $product_id = 0, $status = 'any' ) { _deprecated_function( __METHOD__, '2.0', 'wcs_user_has_subscription()' ); return wcs_user_has_subscription( $user_id, $product_id, $status ); } /** * Gets all the active and inactive subscriptions for all users. * * @return array An associative array containing all users with subscriptions and the details of their subscriptions: 'user_id' => $subscriptions * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.0 */ public static function get_all_users_subscriptions() { _deprecated_function( __METHOD__, '2.0' ); $subscriptions_in_old_format = array(); foreach ( get_users() as $user ) { foreach ( wcs_get_users_subscriptions( $user->ID ) as $subscription ) { $subscriptions_in_old_format[ wcs_get_old_subscription_key( $subscription ) ] = wcs_get_subscription_in_deprecated_structure( $subscription ); } } return apply_filters( 'woocommerce_all_users_subscriptions', $subscriptions_in_old_format ); } /** * Gets all the active and inactive subscriptions for a user, as specified by $user_id * * @param int $user_id (optional) The id of the user whose subscriptions you want. Defaults to the currently logged in user. * @param array $order_ids (optional) An array of post_ids of WC_Order objects as a way to get only subscriptions for certain orders. Defaults to null, which will return subscriptions for all orders. * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.0 */ public static function get_users_subscriptions( $user_id = 0, $order_ids = array() ) { _deprecated_function( __METHOD__, '2.0', 'wcs_get_users_subscriptions( $user_id )' ); $subscriptions_in_old_format = array(); foreach ( wcs_get_users_subscriptions( $user_id ) as $subscription ) { $subscriptions_in_old_format[ wcs_get_old_subscription_key( $subscription ) ] = wcs_get_subscription_in_deprecated_structure( $subscription ); } return apply_filters( 'woocommerce_users_subscriptions', $subscriptions_in_old_format, $user_id ); } /** * Gets all the subscriptions for a user that have been trashed, as specified by $user_id * * @param int $user_id (optional) The id of the user whose subscriptions you want. Defaults to the currently logged in user. * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.0 */ public static function get_users_trashed_subscriptions( $user_id = 0 ) { $subscriptions = self::get_users_subscriptions( $user_id ); foreach ( $subscriptions as $key => $subscription ) { if ( 'trash' != $subscription['status'] ) { unset( $subscriptions[ $key ] ); } } return apply_filters( 'woocommerce_users_trashed_subscriptions', $subscriptions, $user_id ); } /** * A convenience wrapper to assign the inactive subscriber role to a user. * * @param int $user_id The id of the user whose role should be changed * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.2 * @deprecated 1.0.0 - Migrated from WooCommerce Subscriptions v2.0 */ public static function make_user_inactive( $user_id ) { _deprecated_function( __METHOD__, '2.0', 'wcs_make_user_inactive()' ); wcs_make_user_inactive( $user_id ); } /** * A convenience wrapper to assign the cancelled subscriber role to a user. * * Hooked to 'subscription_end_of_prepaid_term' hook. * * @param int $user_id The id of the user whose role should be changed * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.3.2 * @deprecated 1.0.0 - Migrated from WooCommerce Subscriptions v2.0 */ public static function maybe_assign_user_cancelled_role( $user_id ) { _deprecated_function( __METHOD__, '2.0', 'wcs_maybe_make_user_inactive()' ); wcs_maybe_make_user_inactive( $user_id ); } /** * A convenience wrapper for changing a users role. * * @param int $user_id The id of the user whose role should be changed * @param string $role_name Either a WordPress role or one of the WCS keys: 'default_subscriber_role' or 'default_cancelled_role' * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.0 * @deprecated 1.0.0 - Migrated from WooCommerce Subscriptions v2.0 */ public static function update_users_role( $user_id, $role_name ) { _deprecated_function( __METHOD__, '2.0', 'wcs_update_users_role()' ); wcs_update_users_role( $user_id, $role_name ); } /** * Marks a customer as a paying customer when their subscription is activated. * * A wrapper for the @see woocommerce_paying_customer() function. * * @param int $order The order for which customers should be pulled from and marked as paying. * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.0 * @deprecated 1.0.0 - Migrated from WooCommerce Subscriptions v2.0 */ public static function mark_paying_customer( $order ) { _deprecated_function( __METHOD__, '2.0' ); if ( ! is_object( $order ) ) { $order = new WC_Order( $order ); } update_user_meta( $order->get_user_id(), 'paying_customer', 1 ); } /** * Unlike someone making a once-off payment, a subscriber can cease to be a paying customer. This function * changes a user's status to non-paying. * * Deprecated as orders now take care of the customer's status as paying or not paying * * @param object $order The order for which a customer ID should be pulled from and marked as paying. * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.0 * @deprecated 1.0.0 - Migrated from WooCommerce Subscriptions v2.0 */ public static function mark_not_paying_customer( $order ) { _deprecated_function( __METHOD__, '2.0' ); if ( ! is_object( $order ) ) { $order = new WC_Order( $order ); } if ( $order->get_user_id() > 0 ) { update_user_meta( $order->get_user_id(), 'paying_customer', 0 ); } } /** * Return a link for subscribers to change the status of their subscription, as specified with $status parameter * * @param string $subscription_key A subscription key of the form created by @see self::get_subscription_key() * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.0 * @deprecated 1.0.0 - Migrated from WooCommerce Subscriptions v2.0 */ public static function get_users_change_status_link( $subscription_key, $status ) { _deprecated_function( __METHOD__, '2.0', 'wcs_get_users_change_status_link( $subscription_id, $status )' ); if ( 'suspended' == $status ) { _deprecated_argument( __METHOD__, '2.0', 'The "suspended" parameter value is deprecated. Use "on-hold" instead.' ); $status = 'on-hold'; } $subscription_id = wcs_get_subscription_id_from_key( $subscription_key ); $current_status = ''; $subscription = wcs_get_subscription( $subscription_id ); if ( $subscription instanceof WC_Subscription ) { $current_status = $subscription->get_status(); } return apply_filters( 'woocommerce_subscriptions_users_action_link', wcs_get_users_change_status_link( $subscription_id, $status, $current_status ), $subscription_key, $status ); } /** * Change a subscription's next payment date. * * @param mixed $new_payment_date Either a MySQL formatted Date/time string or a Unix timestamp. * @param string $subscription_key A subscription key of the form created by @see self::get_subscription_key() * @param int $user_id The id of the user who purchased the subscription * @param string $timezone Either 'server' or 'user' to describe the timezone of the $new_payment_date. * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.2 * @deprecated 1.0.0 - Migrated from WooCommerce Subscriptions v2.0 */ public static function update_next_payment_date( $new_payment_date, $subscription_key, $user_id = 0, $timezone = 'server' ) { _deprecated_function( __METHOD__, '2.0', 'WC_Subscription::update_dates( array( "next_payment" => $new_payment_date ) )' ); $new_payment_timestamp = ( is_numeric( $new_payment_date ) ) ? $new_payment_date : wcs_date_to_time( $new_payment_date ); // The date needs to be converted to GMT/UTC if ( 'server' != $timezone ) { $new_payment_timestamp = $new_payment_timestamp - ( get_option( 'gmt_offset' ) * 3600 ); } $new_payment_date = gmdate( 'Y-m-d H:i:s', $new_payment_timestamp ); $subscription = wcs_get_subscription_from_key( $subscription_key ); try { $subscription->update_dates( array( 'next_payment' => $new_payment_date ) ); $response = $subscription->get_time( 'next_payment' ); } catch ( Exception $e ) { $response = new WP_Error( 'invalid-date', $e->getMessage() ); } return $response; } /* * Helper Functions */ /** * Because neither PHP nor WP include a real array merge function that works recursively. * * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.0 */ public static function array_merge_recursive_for_real( $first_array, $second_array ) { $merged = $first_array; if ( is_array( $second_array ) ) { foreach ( $second_array as $key => $val ) { if ( is_array( $second_array[ $key ] ) ) { $merged[ $key ] = ( isset( $merged[ $key ] ) && is_array( $merged[ $key ] ) ) ? self::array_merge_recursive_for_real( $merged[ $key ], $second_array[ $key ] ) : $second_array[ $key ]; } else { $merged[ $key ] = $val; } } } return $merged; } /** * Takes a total and calculates the recurring proportion of that based on $proportion and then fixes any rounding bugs to * make sure the totals add up. * * Used mainly to calculate the recurring amount from a total which may also include a sign up fee. * * @param float $total The total amount * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.2 * @return float $proportion A proportion of the total (e.g. 0.5 is half of the total) */ public static function get_amount_from_proportion( $total, $proportion ) { $sign_up_fee_proportion = 1 - $proportion; $sign_up_total = round( $total * $sign_up_fee_proportion, 2 ); $recurring_amount = round( $total * $proportion, 2 ); // Handle any rounding bugs if ( $sign_up_total + $recurring_amount != $total ) { $recurring_amount = $recurring_amount - ( $sign_up_total + $recurring_amount - $total ); } return $recurring_amount; } /** * Creates a subscription price string from an array of subscription details. For example, ""$5 / month for 12 months". * * @param array $subscription_details A set of name => value pairs for the subscription details to include in the string. Available keys: * 'initial_amount': The upfront payment for the subscription, including sign up fees, as a string from the @see woocommerce_price(). Default empty string (no initial payment) * 'initial_description': The word after the initial payment amount to describe the amount. Examples include "now" or "initial payment". Defaults to "up front". * 'recurring_amount': The amount charged per period. Default 0 (no recurring payment). * 'subscription_interval': How regularly the subscription payments are charged. Default 1, meaning each period e.g. per month. * 'subscription_period': The temporal period of the subscription. Should be one of {day|week|month|year} as used by @see self::get_subscription_period_strings() * 'subscription_length': The total number of periods the subscription should continue for. Default 0, meaning continue indefinitely. * 'trial_length': The total number of periods the subscription trial period should continue for. Default 0, meaning no trial period. * 'trial_period': The temporal period for the subscription's trial period. Should be one of {day|week|month|year} as used by @see self::get_subscription_period_strings() * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.2 * @deprecated 1.0.0 - Migrated from WooCommerce Subscriptions v2.0 * @return float $proportion A proportion of the total (e.g. 0.5 is half of the total) */ public static function get_subscription_price_string( $subscription_details ) { _deprecated_function( __METHOD__, '2.0', 'wcs_price_string()' ); return wcs_price_string( $subscription_details ); } /** * Copy of the WordPress "touch_time" template function for use with a variety of different times * * @param array $args A set of name => value pairs to customise how the function operates. Available keys: * 'date': (string) the date to display in the selector in MySQL format ('Y-m-d H:i:s'). Required. * 'tab_index': (int) the tab index for the element. Optional. Default 0. * 'multiple': (bool) whether there will be multiple instances of the element on the same page (determines whether to include an ID or not). Default false. * 'echo': (bool) whether to return and print the element or simply return it. Default true. * 'include_time': (bool) whether to include a specific time for the selector. Default true. * 'include_year': (bool) whether to include a the year field. Default true. * 'include_buttons': (bool) whether to include submit buttons on the selector. Default true. * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.2 */ public static function touch_time( $args = array() ) { global $wp_locale; $args = wp_parse_args( $args, array( 'date' => true, 'tab_index' => 0, 'multiple' => false, 'echo' => true, 'include_time' => true, 'include_buttons' => true, ) ); if ( empty( $args['date'] ) ) { return; } $tab_index_attribute = ( (int) $args['tab_index'] > 0 ) ? ' tabindex="' . $args['tab_index'] . '"' : ''; $month = mysql2date( 'n', $args['date'], false ); $month_input = ''; $day_input = ''; $year_input = ''; if ( $args['include_time'] ) { $hour_input = ''; $minute_input = ''; // translators: all fields are full html nodes: 1$: month input, 2$: day input, 3$: year input, 4$: hour input, 5$: minute input. Change the order if you'd like $touch_time = sprintf( __( '%1$s%2$s, %3$s @ %4$s : %5$s', 'woocommerce-subscriptions' ), $month_input, $day_input, $year_input, $hour_input, $minute_input ); } else { // translators: all fields are full html nodes: 1$: month input, 2$: day input, 3$: year input. Change the order if you'd like $touch_time = sprintf( __( '%1$s%2$s, %3$s', 'woocommerce-subscriptions' ), $month_input, $day_input, $year_input ); } if ( $args['include_buttons'] ) { $touch_time .= '
'; $touch_time .= '
'; } $allowed_html = array( 'select' => array( 'id' => array(), 'name' => array(), 'tabindex' => array(), ), 'option' => array( 'value' => array(), 'selected' => array(), ), 'input' => array( 'type' => array(), 'id' => array(), 'name' => array(), 'value' => array(), 'size' => array(), 'tabindex' => array(), 'maxlength' => array(), 'autocomplete' => array(), ), 'p' => array(), 'a' => array( 'href' => array(), 'title' => array(), 'class' => array(), ), ); if ( $args['echo'] ) { echo wp_kses( $touch_time, $allowed_html ); } return $touch_time; } /** * If a gateway doesn't manage payment schedules, then we should suspend the subscription until it is paid (i.e. for manual payments * or token gateways like Stripe). If the gateway does manage the scheduling, then we shouldn't suspend the subscription because a * gateway may use batch processing on the time payments are charged and a subscription could end up being incorrectly suspended. * * @param int $user_id The id of the user whose subscription should be put on-hold. * @param string $subscription_key A subscription key of the form created by @see self::get_subscription_key() * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.2.5 * @deprecated 1.0.0 - Migrated from WooCommerce Subscriptions v2.0 */ public static function maybe_put_subscription_on_hold( $user_id, $subscription_key ) { _deprecated_function( __METHOD__, '2.0', 'WC_Subscription::update_status()' ); try { $subscription = wcs_get_subscription_from_key( $subscription_key ); if ( $subscription->has_status( 'on-hold' ) ) { return false; } } catch ( Exception $e ) { return false; } // If the subscription is using manual payments, the gateway isn't active or it manages scheduled payments if ( 0 == $subscription->get_total() || $subscription->is_manual() || '' == $subscription->get_payment_method() || ! $subscription->payment_method_supports( 'gateway_scheduled_payments' ) ) { $subscription->update_status( 'on-hold', _x( 'Subscription renewal payment due:', 'used in order note as reason for why subscription status changed', 'woocommerce-subscriptions' ) ); } } /** * 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 1.0.0 - Migrated from WooCommerce Subscriptions v2.0.2 */ public static function maybe_process_failed_renewal_for_repair( $subscription_id ) { $subscription = wcs_get_subscription( $subscription_id ); if ( 'true' === $subscription->get_meta( '_wcs_repaired_2_0_2_needs_failed_payment', true ) ) { // 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 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 ); } } /* Deprecated Functions */ /** * When a scheduled subscription payment hook is fired, automatically process the subscription payment * if the amount is for $0 (and therefore, there is no payment to be processed by a gateway, and likely * no gateway used on the initial order). * * If a subscription has a $0 recurring total and is not already active (after being activated by something else * handling the 'scheduled_subscription_payment' with the default priority of 10), then this function will call * @see self::process_subscription_payment() to reactive the subscription, generate a renewal order etc. * * @param int $user_id The id of the user who the subscription belongs to * @param string $subscription_key A subscription key of the form created by @see self::get_subscription_key() * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.3.2 * @deprecated 1.0.0 - Migrated from WooCommerce Subscriptions v2.0 */ public static function maybe_process_subscription_payment( $user_id, $subscription_key ) { _deprecated_function( __METHOD__, '2.0', __CLASS__ . '::prepare_renewal( $subscription_id )' ); self::prepare_renewal( wcs_get_subscription_id_from_key( $subscription_key ) ); } /** * Return a link for subscribers to change the status of their subscription, as specified with $status parameter * * @param string $subscription_key A subscription key of the form created by @see self::get_subscription_key() * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.0 */ public static function current_user_can_suspend_subscription( $subscription_key ) { _deprecated_function( __METHOD__, '2.0', 'wcs_can_user_put_subscription_on_hold( $subscription, $user )' ); return wcs_can_user_put_subscription_on_hold( wcs_get_subscription_from_key( $subscription_key ) ); } /** * Return a multi-dimensional associative array of subscriptions with a certain value, grouped by user ID. * * A slow PHP based search routine which can't use the speed of MySQL because subscription details. If you * know the key for the value you are search by, use @see self::get_subscriptions() for better performance. * * @param string $search_query The query to search the database for. * @return array Subscription details * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.1 * @deprecated 1.0.0 - Migrated from WooCommerce Subscriptions v2.0 */ public static function search_subscriptions( $search_query ) { _deprecated_function( __METHOD__, '2.0', 'wcs_get_subscriptions()' ); global $wpdb; $subscriptions_to_search = self::get_all_users_subscriptions(); $subscriptions_found = array(); $search_terms = explode( ' ', $search_query ); foreach ( $subscriptions_to_search as $user_id => $subscriptions ) { $user = get_user_by( 'id', $user_id ); if ( false === $user || ! is_object( $user ) ) { continue; } $user = $user->data; foreach ( $search_terms as $search_term ) { // If the search query is found in the user's details, add all of their subscriptions, otherwise add only subscriptions with a matching item if ( false !== stripos( $user->user_nicename, $search_term ) || false !== stripos( $user->display_name, $search_term ) ) { $subscriptions_found[ $user_id ] = $subscriptions; } elseif ( false !== stripos( $user->user_login, $search_term ) || false !== stripos( $user->user_email, $search_term ) ) { $subscriptions_found[ $user_id ] = $subscriptions; } else { foreach ( $subscriptions as $subscription_key => $subscription ) { $product_title = get_the_title( $subscription['product_id'] ); if ( in_array( $search_term, $subscription, true ) || false != preg_match( "/$search_term/i", $product_title ) ) { $subscriptions_found[ $user_id ][ $subscription_key ] = $subscription; } } } } } return apply_filters( 'woocommerce_search_subscriptions', $subscriptions_found, $search_query ); } /** * Marks a single subscription as active on a users account. * * @param int $user_id The id of the user whose subscription is to be activated. * @param string $subscription_key A subscription key of the form created by @see self::get_subscription_key() * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.0 */ public static function activate_subscription( $user_id, $subscription_key ) { _deprecated_function( __METHOD__, '2.0' ); try { $subscription = wcs_get_subscription_from_key( $subscription_key ); if ( $subscription->has_status( 'active' ) ) { return false; } } catch ( Exception $e ) { return false; } if ( ! $subscription->has_status( 'pending' ) && ! $subscription->can_be_updated_to( 'active' ) ) { do_action( 'unable_to_activate_subscription', $user_id, $subscription_key ); $activated_subscription = false; } else { $subscription->update_status( 'active' ); do_action( 'activated_subscription', $user_id, $subscription_key ); $activated_subscription = true; } return $activated_subscription; } /** * Changes a single subscription from on-hold to active on a users account. * * @param int $user_id The id of the user whose subscription is to be activated. * @param string $subscription_key A subscription key of the form created by @see self::get_subscription_key() * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.0 */ public static function reactivate_subscription( $user_id, $subscription_key ) { _deprecated_function( __METHOD__, '2.0' ); if ( false !== self::activate_subscription( $user_id, $subscription_key ) ) { do_action( 'reactivated_subscription', $user_id, $subscription_key ); } } /** * Suspends a single subscription on a users account by placing it in the "on-hold" status. * * @param int $user_id The id of the user whose subscription should be put on-hold. * @param string $subscription_key A subscription key of the form created by @see self::get_subscription_key() * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.0 */ public static function put_subscription_on_hold( $user_id, $subscription_key ) { _deprecated_function( __METHOD__, '2.0', 'WC_Subscription::update_status( "on-hold" )' ); try { $subscription = wcs_get_subscription_from_key( $subscription_key ); if ( $subscription->has_status( 'on-hold' ) ) { return false; } } catch ( Exception $e ) { return false; } if ( ! $subscription->can_be_updated_to( 'on-hold' ) ) { do_action( 'unable_to_put_subscription_on-hold', $user_id, $subscription_key ); do_action( 'unable_to_suspend_subscription', $user_id, $subscription_key ); } else { $subscription->update_status( 'on-hold' ); do_action( 'subscription_put_on-hold', $user_id, $subscription_key ); // Backward, backward compatibility do_action( 'suspended_subscription', $user_id, $subscription_key ); } } /** * Cancels a single subscription on a users account. * * @param int $user_id The id of the user whose subscription should be cancelled. * @param string $subscription_key A subscription key of the form created by @see self::get_subscription_key() * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.0 */ public static function cancel_subscription( $user_id, $subscription_key ) { _deprecated_function( __METHOD__, '2.0', 'WC_Subscriptions::cancel_order()' ); try { $subscription = wcs_get_subscription_from_key( $subscription_key ); if ( $subscription->has_status( array( 'pending-cancel', 'cancelled' ) ) ) { return false; } } catch ( Exception $e ) { return false; } if ( ! $subscription->can_be_updated_to( 'cancelled' ) ) { do_action( 'unable_to_cancel_subscription', $user_id, $subscription_key ); } else { $subscription->update_status( 'cancelled' ); do_action( 'cancelled_subscription', $user_id, $subscription_key ); } } /** * Sets a single subscription on a users account to be 'on-hold' and keeps a record of the failed sign up on an order. * * @param int $user_id The id of the user whose subscription should be cancelled. * @param string $subscription_key A subscription key of the form created by @see self::get_subscription_key() * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.0 */ public static function failed_subscription_signup( $user_id, $subscription_key ) { _deprecated_function( __METHOD__, '2.0' ); try { $subscription = wcs_get_subscription_from_key( $subscription_key ); if ( $subscription->has_status( 'on-hold' ) ) { return false; } } catch ( Exception $e ) { return false; } // Place the subscription on-hold $subscription->update_status( 'on-hold' ); // Log failure on order // translators: placeholder is subscription ID $subscription->get_parent()->add_order_note( sprintf( __( 'Failed sign-up for subscription %s.', 'woocommerce-subscriptions' ), $subscription->get_id() ) ); do_action( 'subscription_sign_up_failed', $user_id, $subscription_key ); } /** * Trashes a single subscription on a users account. * * @param int $user_id The ID of the user who the subscription belongs to * @param string $subscription_key A subscription key of the form created by @see self::get_subscription_key() * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.0 */ public static function trash_subscription( $user_id, $subscription_key ) { _deprecated_function( __METHOD__, '2.0', 'wp_trash_post()' ); try { $subscription = wcs_get_subscription_from_key( $subscription_key ); if ( $subscription->has_status( 'trash' ) ) { return false; } } catch ( Exception $e ) { return false; } if ( ! $subscription->can_be_updated_to( 'cancelled' ) ) { do_action( 'unable_to_trash_subscription', $user_id, $subscription_key ); } else { // Run all cancellation related functions on the subscription if ( ! $subscription->has_status( array( 'cancelled', 'expired', 'trash' ) ) ) { $subscription->update_status( 'cancelled' ); } wp_trash_post( $subscription->get_id() ); do_action( 'subscription_trashed', $user_id, $subscription_key ); } } /** * Permanently deletes a single subscription on a users account. * * @param int $user_id The ID of the user who the subscription belongs to * @param string $subscription_key A subscription key of the form created by @see self::get_subscription_key() * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.2 */ public static function delete_subscription( $user_id, $subscription_key ) { _deprecated_function( __METHOD__, '2.0', 'wp_delete_post()' ); try { $subscription = wcs_get_subscription_from_key( $subscription_key ); } catch ( Exception $e ) { return false; } if ( ! $subscription->can_be_updated_to( 'deleted' ) && ! $subscription->can_be_updated_to( 'cancelled' ) ) { do_action( 'unable_to_delete_subscription', $user_id, $subscription_key ); } else { // Run all cancellation related functions on the subscription if ( ! $subscription->has_status( array( 'cancelled', 'expired', 'trash' ) ) ) { $subscription->update_status( 'cancelled' ); } wp_delete_post( $subscription->get_id(), true ); do_action( 'subscription_deleted', $user_id, $subscription_key, $subscription, null ); } } /** * Processes an ajax request to change a subscription's next payment date. * * Deprecated because editing a subscription's next payment date is now done from the Edit Subscription screen. * * @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.2 * @deprecated 1.0.0 - Migrated from WooCommerce Subscriptions v2.0 */ public static function ajax_update_next_payment_date() { _deprecated_function( __METHOD__, '2.0', 'wp_delete_post()' ); $response = array( 'status' => 'error' ); if ( ! wp_verify_nonce( wc_clean( wp_unslash( $_POST['wcs_nonce'] ) ), 'woocommerce-subscriptions' ) ) { $response['message'] = ' '; $touch_time .= ' '; $touch_time .= '