type ) { $start_date = time(); $next_date = sdevs_wp_strtotime( $recurr_timing, $start_date ); if ( $trial && ! empty( $trial ) ) { $trial_started = get_post_meta( $subscription_id, '_subscrpt_trial_started', true ); $trial_ended = get_post_meta( $subscription_id, '_subscrpt_trial_ended', true ); if ( empty( $trial_started ) && empty( $trial_ended ) ) { $start_date = sdevs_wp_strtotime( $trial ); $next_date = $start_date; update_post_meta( $subscription_id, '_subscrpt_trial_started', time() ); update_post_meta( $subscription_id, '_subscrpt_trial_ended', $start_date ); update_post_meta( $subscription_id, '_subscrpt_trial_mode', 'on' ); } if ( ! empty( $trial_ended ) ) { $start_date = $trial_ended; $next_date = $start_date; } } update_post_meta( $subscription_id, '_subscrpt_start_date', $start_date ); } elseif ( 'renew' === $subscription_history->type ) { if ( $trial ) { delete_post_meta( $subscription_id, '_subscrpt_trial' ); delete_post_meta( $subscription_id, '_subscrpt_trial_mode' ); delete_post_meta( $subscription_id, '_subscrpt_trial_started' ); delete_post_meta( $subscription_id, '_subscrpt_trial_ended' ); } $next_date = sdevs_wp_strtotime( $recurr_timing, time() ); } elseif ( 'early-renew' === $subscription_history->type ) { if ( $trial ) { delete_post_meta( $subscription_id, '_subscrpt_trial' ); delete_post_meta( $subscription_id, '_subscrpt_trial_mode' ); delete_post_meta( $subscription_id, '_subscrpt_trial_started' ); delete_post_meta( $subscription_id, '_subscrpt_trial_ended' ); } $next_date = sdevs_wp_strtotime( $recurr_timing, time() ); } // Allow filtering of next due date logic $next_date = apply_filters( 'subscrpt_split_payment_next_due_date', $next_date, $subscription_id, $recurr_timing, $subscription_history->type ); update_post_meta( $subscription_id, '_subscrpt_next_date', $next_date ); } /** * Add custom column on order item. * * @return void */ public function register_custom_column() { ?> get_id(); $subscription_id = Helper::get_subscription_from_order_item_id( $item->get_id() ); if ( ! $subscription_id ) { echo "-"; return; } $subscription_id = $subscription_id->subscription_id; $price = get_post_meta( $subscription_id, '_subscrpt_price', true ); $subtotal = Helper::format_price_with_order_item( $price, $item_id ); ?>
2; if ( $has_trial ) { echo '
+ Got ' . esc_html( $trial ) . ' free trial!'; } } /** * Take some actions based on order status changed. * * @param int $order_id Order Id. */ public function order_status_changed( $order_id ) { $order = wc_get_order( $order_id ); $post_status = 'active'; switch ( $order->get_status() ) { case 'on-hold': case 'pending': $post_status = 'pending'; break; case 'refunded': case 'failed': case 'cancelled': $post_status = 'cancelled'; break; default: $post_status = 'active'; break; } $post_status = apply_filters( 'subscript_order_status_to_post_status', $post_status, $order ); global $wpdb; $table_name = $wpdb->prefix . 'subscrpt_order_relation'; // @phpcs:ignore $histories = $wpdb->get_results( $wpdb->prepare( 'SELECT * FROM %i WHERE order_id=%d', array( $table_name, $order_id ) ) ); foreach ( $histories as $history ) { if ( 'new' === $history->type || 'renew' === $history->type ) { $subscription_id = $history->subscription_id; wp_update_post( array( 'ID' => $subscription_id, 'post_status' => $post_status, ) ); // If possible change order status to completed if it has a trial subscription. $this->maybe_trigger_auto_complete_trial_order( $order_id, $subscription_id ); // Increment renewal count for completed renewal orders (wps-pro) if ( 'renew' === $history->type && 'active' === $post_status && function_exists( 'subscrpt_pro_activated' ) && subscrpt_pro_activated() ) { if ( class_exists( '\\SpringDevs\\SubscriptionPro\\Illuminate\\LimitChecker' ) ) { \SpringDevs\SubscriptionPro\Illuminate\LimitChecker::increment_renewal_count( $history->subscription_id ); } } // Add enhanced split payment activity logging $this->add_split_payment_activity_note( $history->subscription_id, $history->type, $post_status, $order ); Action::write_comment( $post_status, $history->subscription_id ); } else { do_action( 'subscrpt_order_status_changed', $order, $history ); } } } /** * Delete the subscription. * * @param int $order_id Order ID. * * @return void */ public function delete_the_subscription( $order_id ) { global $wpdb; $table_name = $wpdb->prefix . 'subscrpt_order_relation'; $histories = Helper::get_subscriptions_from_order( $order_id ); foreach ( (array) $histories as $history ) { $subscription_order_id = get_post_meta( $history->subscription_id, '_subscrpt_order_id', true ); if ( (int) $subscription_order_id === $order_id ) { wp_delete_post( $history->subscription_id, true ); } } // phpcs:ignore $wpdb->delete( $table_name, array( 'order_id' => $order_id ), array( '%d' ) ); } /** * Add enhanced split payment activity note with payment progress and access information. * * @param int $subscription_id Subscription ID. * @param string $history_type History type (new, renew, etc.). * @param string $post_status Post status. * @param \WC_Order $order WooCommerce order object. */ private function add_split_payment_activity_note( $subscription_id, $history_type, $post_status, $order ) { // Only add enhanced notes for active subscriptions if ( 'active' !== $post_status ) { return; } // Check if this is a split payment subscription if ( ! function_exists( 'subscrpt_get_payment_type' ) ) { return; } $payment_type = subscrpt_get_payment_type( $subscription_id ); if ( 'split_payment' !== $payment_type ) { return; } // Get payment progress information $max_payments = function_exists( 'subscrpt_get_max_payments' ) ? subscrpt_get_max_payments( $subscription_id ) : 0; $payments_made = function_exists( 'subscrpt_count_payments_made' ) ? subscrpt_count_payments_made( $subscription_id ) : 0; $remaining_payments = function_exists( 'subscrpt_get_remaining_payments' ) ? subscrpt_get_remaining_payments( $subscription_id ) : 0; // Determine payment number for this order $payment_number = $payments_made; $order_total = $order->get_total(); $order_currency = $order->get_currency(); // Create enhanced activity note $comment_content = ''; $activity_type = ''; if ( 'new' === $history_type ) { $comment_content = sprintf( /* translators: %1$d: payment number, %2$d: total payments, %3$s: amount, %4$s: currency */ __( 'Split payment %1$d of %2$d received (%3$s %4$s). Initial access granted.', 'subscription' ), $payment_number, $max_payments, $order_total, $order_currency ); $activity_type = __( 'Split Payment - Initial', 'subscription' ); } elseif ( 'renew' === $history_type ) { $comment_content = sprintf( /* translators: %1$d: payment number, %2$d: total payments, %3$s: amount, %4$s: currency, %5$d: remaining */ __( 'Split payment %1$d of %2$d received (%3$s %4$s). %5$d payments remaining.', 'subscription' ), $payment_number, $max_payments, $order_total, $order_currency, $remaining_payments ); $activity_type = __( 'Split Payment - Installment', 'subscription' ); } // Add the enhanced activity note if ( $comment_content ) { $comment_id = wp_insert_comment( array( 'comment_author' => 'Subscription for WooCommerce', 'comment_content' => $comment_content, 'comment_post_ID' => $subscription_id, 'comment_type' => 'order_note', ) ); update_comment_meta( $comment_id, '_subscrpt_activity', $activity_type ); update_comment_meta( $comment_id, '_subscrpt_activity_type', 'split_payment' ); // Add order note with split payment context $order_note = sprintf( /* translators: %1$d: payment number, %2$d: total payments, %3$d: subscription id */ __( 'Split payment %1$d of %2$d received for subscription #%3$d', 'subscription' ), $payment_number, $max_payments, $subscription_id ); $order->add_order_note( $order_note ); } // Add payment milestone notes for significant progress $this->add_payment_milestone_notes( $subscription_id, $payments_made, $max_payments ); } /** * Add payment milestone notes for significant progress (25%, 50%, 75%, 100%). * * @param int $subscription_id Subscription ID. * @param int $payments_made Number of payments made. * @param int $max_payments Maximum number of payments. */ private function add_payment_milestone_notes( $subscription_id, $payments_made, $max_payments ) { if ( ! $max_payments || $max_payments <= 0 ) { return; } $percentage = round( ( $payments_made / $max_payments ) * 100 ); $milestone_key = '_subscrpt_milestone_' . $percentage . '_logged'; // Check if this milestone has already been logged if ( get_post_meta( $subscription_id, $milestone_key, true ) ) { return; } $milestone_note = ''; $activity_type = ''; switch ( $percentage ) { case 25: $milestone_note = sprintf( /* translators: %1$d: payments made, %2$d: total payments */ __( 'Payment milestone reached: %1$d of %2$d payments completed (25%%).', 'subscription' ), $payments_made, $max_payments ); $activity_type = __( 'Payment Milestone - 25%', 'subscription' ); break; case 50: $milestone_note = sprintf( /* translators: %1$d: payments made, %2$d: total payments */ __( 'Payment milestone reached: %1$d of %2$d payments completed (50%%). Halfway there!', 'subscription' ), $payments_made, $max_payments ); $activity_type = __( 'Payment Milestone - 50%', 'subscription' ); break; case 75: $milestone_note = sprintf( /* translators: %1$d: payments made, %2$d: total payments */ __( 'Payment milestone reached: %1$d of %2$d payments completed (75%%). Almost complete!', 'subscription' ), $payments_made, $max_payments ); $activity_type = __( 'Payment Milestone - 75%', 'subscription' ); break; case 100: $milestone_note = sprintf( /* translators: %1$d: payments made, %2$d: total payments */ __( 'Payment milestone reached: %1$d of %2$d payments completed (100%%). Split payment plan complete!', 'subscription' ), $payments_made, $max_payments ); $activity_type = __( 'Payment Milestone - 100%', 'subscription' ); break; } // Add milestone note if applicable if ( $milestone_note ) { $comment_id = wp_insert_comment( array( 'comment_author' => 'Subscription for WooCommerce', 'comment_content' => $milestone_note, 'comment_post_ID' => $subscription_id, 'comment_type' => 'order_note', ) ); update_comment_meta( $comment_id, '_subscrpt_activity', $activity_type ); update_comment_meta( $comment_id, '_subscrpt_activity_type', 'split_payment' ); // Mark milestone as logged update_post_meta( $subscription_id, $milestone_key, current_time( 'timestamp' ) ); } } /** * Maybe complete the order if it has a trial subscription and is still in processing status. * * @param int $order_id Order ID. * @param int $subscription_id Subscription ID. */ public function maybe_trigger_auto_complete_trial_order( $order_id, $subscription_id ) { $order = wc_get_order( $order_id ); $order_items = $order->get_items(); // Only attempt to complete if order is still in processing status. if ( 'processing' !== $order->get_status() ) { return; } $is_subs_trial_order = false; foreach ( $order_items as $order_item ) { $subscrpt_meta = $order_item->get_meta( '_subscrpt_meta', true ); if ( ! empty( $subscrpt_meta ) && isset( $subscrpt_meta['trial'] ) ) { $is_subs_trial_order = true; } } if ( $is_subs_trial_order ) { as_enqueue_async_action( 'subscrpt_queue_trial_order_autocomplete', [ 'order_id' => $order_id ] ); $log_message = "Queued auto complete task for free trial order [ID: {$order_id}]"; subscrpt_write_log( $log_message ); subscrpt_write_debug_log( $log_message ); } } /** * Autocomplete subscription trial order. * * @param int $order_id Order ID. */ public function auto_complete_subscription_trial_order( $order_id ) { $order = wc_get_order( $order_id ); if ( ! $order ) { return; } sleep( 3 ); // Adding a small delay to ensure order status is updated before we check it. $order->update_status( 'completed', __( 'Subscription order with trial.', 'subscription' ) ); } }