| @@ -1,9 +1,15 @@ | ||
| 1 | 1 | <?php |
| 2 | +/** | |
| 3 | + * Checkout handlers for subscription plugin. | |
| 4 | + * | |
| 5 | + * @package wp_subscription | |
| 6 | + */ | |
| 2 | 7 | |
| 3 | 8 | namespace SpringDevs\Subscription\Frontend; |
| 4 | 9 | |
| 5 | 10 | use SpringDevs\Subscription\Illuminate\Helper; |
| 11 | +use SpringDevs\Subscription\Illuminate\Subscription\Subscription; | |
| 6 | 12 | |
| 7 | 13 | /** |
| 8 | 14 | * Checkout class |
| 9 | 15 | */ |
| @@ -12,12 +18,16 @@ | ||
| 12 | 18 | /** |
| 13 | 19 | * Initialize the class |
| 14 | 20 | */ |
| 15 | 21 | public function __construct() { |
| 16 | - add_action( 'woocommerce_checkout_order_processed', array( $this, 'create_subscription_after_checkout' ) ); | |
| 17 | - add_action( 'woocommerce_store_api_checkout_order_processed', array( $this, 'create_subscription_after_checkout_storeapi' ) ); | |
| 18 | - add_action( 'woocommerce_resume_order', array( $this, 'remove_subscriptions' ) ); | |
| 19 | - add_action( 'woocommerce_checkout_create_order_line_item', array( $this, 'save_order_item_product_meta' ), 10, 3 ); | |
| 22 | + // Subscription upgrade/downgrade order created hook. | |
| 23 | + add_action( 'woocommerce_checkout_order_processed', [ $this, 'trigger_subscription_switch_order_created' ] ); | |
| 24 | + add_action( 'woocommerce_store_api_checkout_order_processed', [ $this, 'trigger_subscription_switch_order_created_storeapi' ] ); | |
| 25 | + | |
| 26 | + add_action( 'woocommerce_checkout_order_processed', [ $this, 'create_subscription_after_checkout' ] ); | |
| 27 | + add_action( 'woocommerce_store_api_checkout_order_processed', [ $this, 'create_subscription_after_checkout_storeapi' ] ); | |
| 28 | + add_action( 'woocommerce_resume_order', [ $this, 'remove_subscriptions' ] ); | |
| 29 | + add_action( 'woocommerce_checkout_create_order_line_item', [ $this, 'save_order_item_product_meta' ], 10, 3 ); | |
| 20 | 30 | } |
| 21 | 31 | |
| 22 | 32 | /** |
| 23 | 33 | * Create subscription during checkout on storeAPI. |
| @@ -55,13 +65,19 @@ | ||
| 55 | 65 | |
| 56 | 66 | // Create subscription for order items. |
| 57 | 67 | $order_items = $order->get_items(); |
| 58 | 68 | foreach ( $order_items as $order_item ) { |
| 59 | - $product = sdevs_get_subscription_product( $order_item['product_id'] ); | |
| 69 | + $product = Subscription::get_subs_product( $order_item['product_id'] ); | |
| 60 | 70 | |
| 61 | - if ( $product->is_type( 'simple' ) && ! subscrpt_pro_activated() ) { | |
| 71 | + // Plan items are created by Frontend\PlanCheckout on `subscrpt_product_checkout` | |
| 72 | + // below (resolution order: tied plan first, else classic meta). Skipping | |
| 73 | + // them here keeps the classic path from creating a second subscription. | |
| 74 | + if ( $product->is_type( 'simple' ) && ! subscrpt_pro_activated() && ! $order_item->get_meta( '_subscrpt_plan_id' ) ) { | |
| 75 | + // A plan product bought as One-Time carries no plan id — it is not a | |
| 76 | + // subscription, so never record one for it. | |
| 77 | + $is_one_time = function_exists( 'subscrpt_product_has_plan' ) && subscrpt_product_has_plan( $product->get_id() ); | |
| 62 | 78 | |
| 63 | - if ( $product->is_enabled() ) { | |
| 79 | + if ( $product->is_enabled() && ! $is_one_time ) { | |
| 64 | 80 | $is_renew = isset( $order_item['renew_subscrpt'] ); |
| 65 | 81 | |
| 66 | 82 | $timing_option = $product->get_timing_option(); |
| 67 | 83 | $trial = $product->get_trial(); |
| @@ -80,13 +96,9 @@ | ||
| 80 | 96 | $renew_subscription_id = Helper::subscription_exists( $product->get_id(), 'expired' ); |
| 81 | 97 | $selected_subscription_id = null; |
| 82 | 98 | if ( $is_renew && $renew_subscription_id && 'cancelled' !== $post_status ) { |
| 83 | 99 | $selected_subscription_id = $renew_subscription_id; |
| 84 | - Helper::process_order_renewal( | |
| 85 | - $selected_subscription_id, | |
| 86 | - $order_id, | |
| 87 | - $order_item->get_id() | |
| 88 | - ); | |
| 100 | + Helper::process_order_renewal( $selected_subscription_id, $order_id, $order_item->get_id() ); | |
| 89 | 101 | } else { |
| 90 | 102 | $selected_subscription_id = Helper::process_new_subscription_order( $order_item, $post_status, $product ); |
| 91 | 103 | } |
| 92 | 104 | |
| @@ -92,9 +104,9 @@ | ||
| 92 | 104 | |
| 93 | 105 | if ( $selected_subscription_id ) { |
| 94 | 106 | // product related. |
| 95 | 107 | update_post_meta( $selected_subscription_id, '_subscrpt_timing_option', $timing_option ); |
| 96 | - update_post_meta( $selected_subscription_id, '_subscrpt_price', $product->get_price() * $order_item['quantity'] ); | |
| 108 | + update_post_meta( $selected_subscription_id, '_subscrpt_price', $product->get_price() ); | |
| 97 | 109 | update_post_meta( $selected_subscription_id, '_subscrpt_user_cancel', $product->get_meta( '_subscrpt_user_cancel' ) ); |
| 98 | 110 | |
| 99 | 111 | // order related. |
| 100 | 112 | update_post_meta( $selected_subscription_id, '_subscrpt_order_id', $order_id ); |
| @@ -149,7 +161,60 @@ | ||
| 149 | 161 | */ |
| 150 | 162 | public function save_order_item_product_meta( $item, $cart_item_key, $cart_item ) { |
| 151 | 163 | if ( isset( $cart_item['renew_subscrpt'] ) ) { |
| 152 | 164 | $item->update_meta_data( '_renew_subscrpt', $cart_item['renew_subscrpt'] ); |
| 165 | + } | |
| 166 | + | |
| 167 | + if ( ! empty( $cart_item['wp_subs_switch'] ?? null ) && ! empty( $cart_item['switch_context'] ?? null ) ) { | |
| 168 | + $switch_context = $cart_item['switch_context']; | |
| 169 | + | |
| 170 | + // Add switch context data to order item meta. | |
| 171 | + $item->update_meta_data( '_wp_subs_switch', true, true ); | |
| 172 | + $item->update_meta_data( '_wp_subs_switch_context', $switch_context, true ); | |
| 173 | + } | |
| 174 | + } | |
| 175 | + | |
| 176 | + /** | |
| 177 | + * Trigger subscription switch order created store API. | |
| 178 | + * | |
| 179 | + * @param \WC_Order $order Order. | |
| 180 | + */ | |
| 181 | + public function trigger_subscription_switch_order_created_storeapi( $order ) { | |
| 182 | + $this->trigger_subscription_switch_order_created( $order->get_id() ?? 0 ); | |
| 183 | + } | |
| 184 | + | |
| 185 | + /** | |
| 186 | + * Trigger subscription switch order created. | |
| 187 | + * | |
| 188 | + * @param int $order_id Order ID. | |
| 189 | + */ | |
| 190 | + public function trigger_subscription_switch_order_created( $order_id ) { | |
| 191 | + if ( ! $order_id || ! subscrpt_pro_activated() ) { | |
| 192 | + return; | |
| 193 | + } | |
| 194 | + | |
| 195 | + $order = wc_get_order( $order_id ); | |
| 196 | + $order_items = $order->get_items(); | |
| 197 | + | |
| 198 | + foreach ( $order_items as $order_item ) { | |
| 199 | + $is_switch = in_array( $order_item->get_meta( '_wp_subs_switch' ), [ true, 1, '1' ], true ); | |
| 200 | + $switch_context = $order_item->get_meta( '_wp_subs_switch_context' ); | |
| 201 | + | |
| 202 | + if ( $is_switch ) { | |
| 203 | + $switch_type = $switch_context['switch_type'] ?? 'upgrade'; | |
| 204 | + | |
| 205 | + unset( $switch_context['nonce'] ); | |
| 206 | + unset( $switch_context['redirect_back_url'] ); | |
| 207 | + | |
| 208 | + /** | |
| 209 | + * Action fired when subscription switch order is created. | |
| 210 | + * | |
| 211 | + * @param string $switch_type Switch type (upgrade/downgrade). | |
| 212 | + * @param \WC_Order $order Order object. | |
| 213 | + * @param \WC_Order_Item_Product $order_item Order Item object. | |
| 214 | + * @param array $switch_context Switch context data. [ 'switch_type', 'subscription_id', 'order_id', 'product_id', 'old_variation_id', 'new_variation_id' ] | |
| 215 | + */ | |
| 216 | + do_action( 'subscrpt_switch_order_created', $switch_type, $order, $order_item, $switch_context ); | |
| 217 | + } | |
| 153 | 218 | } |
| 154 | 219 | } |
| 155 | 220 | } |