PluginProbe
Subscriptions for WooCommerce with Stripe Recurring Payments / 1.10.2
Subscriptions for WooCommerce with Stripe Recurring Payments v1.10.2
2.0.0 1.11.2 1.11.1 1.11.0 1.10.9 1.10.8 1.10.7 1.10.6 1.10.5 1.10.4 1.10.3 1.10.2 1.10.1 1.10.0 1.9.6 1.9.5 trunk 1.3.0 1.3.1 1.3.2 1.4.0 1.4.1 1.4.2 1.5.0 1.5.1 All 61 releases
subscription / includes / Admin / OnboardingAjax.php

OnboardingAjax.php in Subscriptions for WooCommerce with Stripe Recurring Payments 1.10.2, at includes/Admin/OnboardingAjax.php

231 lines 9.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace SpringDevs\Subscription\Admin;
4
5 /**
6 * AJAX handlers for the onboarding wizard.
7 *
8 * Handles page-2 save (product create/update), variation fetch, and wizard reset.
9 *
10 * @package SpringDevs\Subscription\Admin
11 */
12 class OnboardingAjax {
13
14 /**
15 * Initialize the class.
16 */
17 public function __construct() {
18 add_action( 'wp_ajax_subscrpt_save_wizard_page2', array( $this, 'save_wizard_page2' ) );
19 add_action( 'wp_ajax_subscrpt_reset_wizard', array( $this, 'reset_wizard' ) );
20 add_action( 'wp_ajax_subscrpt_get_product_variations', array( $this, 'get_product_variations' ) );
21 }
22
23 /**
24 * Save wizard Page 2 data to session and create/update product.
25 *
26 * @return void Sends JSON.
27 */
28 public function save_wizard_page2() {
29 check_ajax_referer( 'subscrpt_onboarding_wizard', 'nonce' );
30
31 if ( ! current_user_can( 'manage_options' ) ) {
32 wp_send_json_error( array( 'message' => __( 'Permission denied.', 'subscription' ) ), 403 );
33 }
34
35 if ( ! session_id() ) {
36 session_start();
37 }
38
39 $product_mode = isset( $_POST['product_mode'] ) ? sanitize_text_field( wp_unslash( $_POST['product_mode'] ) ) : 'new';
40 $product_name = isset( $_POST['product_name'] ) ? sanitize_text_field( wp_unslash( $_POST['product_name'] ) ) : '';
41 $product_price = isset( $_POST['product_price'] ) ? sanitize_text_field( wp_unslash( $_POST['product_price'] ) ) : '';
42 $existing_product = isset( $_POST['existing_product_id'] ) ? absint( $_POST['existing_product_id'] ) : 0;
43 $variation_id = isset( $_POST['variation_id'] ) ? absint( $_POST['variation_id'] ) : 0;
44 $timing_option = isset( $_POST['timing_option'] ) ? sanitize_text_field( wp_unslash( $_POST['timing_option'] ) ) : 'never';
45 $billing_per = isset( $_POST['billing_per'] ) ? absint( $_POST['billing_per'] ) : 1;
46 $billing_period = isset( $_POST['billing_period'] ) ? sanitize_text_field( wp_unslash( $_POST['billing_period'] ) ) : 'months';
47 $trial_timing_per = isset( $_POST['trial_timing_per'] ) ? absint( $_POST['trial_timing_per'] ) : 0;
48 $signup_fee = isset( $_POST['signup_fee'] ) ? sanitize_text_field( wp_unslash( $_POST['signup_fee'] ) ) : '';
49 $trial_enabled = isset( $_POST['trial_enabled'] ) ? (int) $_POST['trial_enabled'] : 0;
50 $trial_timing_opt = isset( $_POST['trial_timing_option'] ) ? sanitize_text_field( wp_unslash( $_POST['trial_timing_option'] ) ) : 'days';
51 $length_enabled = isset( $_POST['length_enabled'] ) ? (int) $_POST['length_enabled'] : 0;
52 $length_per = isset( $_POST['length_per'] ) ? absint( $_POST['length_per'] ) : 0;
53 $length_option = isset( $_POST['length_option'] ) ? sanitize_text_field( wp_unslash( $_POST['length_option'] ) ) : 'months';
54
55 $result_product_id = 0;
56
57 if ( 'new' === $product_mode ) {
58 $wc_product = new \WC_Product_Simple();
59 $wc_product->set_name( $product_name );
60 $wc_product->set_regular_price( wc_format_decimal( $product_price ) );
61 $wc_product->set_status( 'publish' );
62 $this->apply_subscription_meta( $wc_product, $billing_period, $billing_per, $trial_timing_per, $trial_timing_opt, $signup_fee );
63 $result_product_id = $wc_product->save();
64
65 if ( ! $result_product_id ) {
66 wp_send_json_error( array( 'message' => __( 'Failed to create product. Please try again.', 'subscription' ) ) );
67 }
68 } elseif ( 'existing' === $product_mode && $existing_product > 0 ) {
69 $parent = wc_get_product( $existing_product );
70
71 if ( ! $parent ) {
72 wp_send_json_error( array( 'message' => __( 'Product not found.', 'subscription' ) ) );
73 }
74
75 if ( $variation_id > 0 ) {
76 // Variable product: update parent name only; apply meta + price on the variation.
77 $parent->set_name( $product_name );
78 $parent->save();
79
80 $variation = wc_get_product( $variation_id );
81 if ( $variation ) {
82 $variation->set_regular_price( wc_format_decimal( $product_price ) );
83 $this->apply_subscription_meta( $variation, $billing_period, $billing_per, $trial_timing_per, $trial_timing_opt, $signup_fee );
84 $variation->save();
85 }
86 } else {
87 // Simple product: update name, price, and subscription meta in one save.
88 $parent->set_name( $product_name );
89 $parent->set_regular_price( wc_format_decimal( $product_price ) );
90 $this->apply_subscription_meta( $parent, $billing_period, $billing_per, $trial_timing_per, $trial_timing_opt, $signup_fee );
91 $parent->save();
92 }
93
94 $result_product_id = $existing_product;
95 }
96
97 $_SESSION['subscrpt_onboarding_wizard'] = array(
98 'page' => 3,
99 'product_id' => $result_product_id,
100 'product_mode' => $product_mode,
101 'product_name' => $product_name,
102 'product_price' => $product_price,
103 'existing_product' => $existing_product,
104 'variation_id' => $variation_id,
105 'timing_option' => $timing_option,
106 'billing_per' => $billing_per,
107 'billing_period' => $billing_period,
108 'trial_timing_per' => $trial_timing_per,
109 'signup_fee' => $signup_fee,
110 'trial_enabled' => $trial_enabled,
111 'trial_timing_option' => $trial_timing_opt,
112 'length_enabled' => $length_enabled,
113 'length_per' => $length_per,
114 'length_option' => $length_option,
115 );
116
117 wp_send_json_success( array( 'product_id' => $result_product_id ) );
118 }
119
120 /**
121 * Stage subscription meta on a WC product object via the WC meta layer.
122 * Does NOT call save() — the caller must save the object after calling this method.
123 *
124 * @param \WC_Product $product Product or variation object.
125 * @param string $billing_period Billing period unit (days/weeks/months/years).
126 * @param int $billing_per Billing interval count.
127 * @param int $trial_per Free trial length.
128 * @param string $trial_option Free trial period unit.
129 * @param string $signup_fee One-time sign-up fee (pro only).
130 *
131 * @return void
132 */
133 private function apply_subscription_meta( $product, $billing_period, $billing_per, $trial_per, $trial_option, $signup_fee ) {
134 $product->update_meta_data( '_subscrpt_enabled', true );
135 $product->update_meta_data( '_subscrpt_timing_option', $billing_period );
136 $product->update_meta_data( '_subscrpt_timing_per', $billing_per );
137 $product->update_meta_data( '_subscrpt_trial_timing_per', $trial_per );
138 $product->update_meta_data( '_subscrpt_trial_timing_option', $trial_option );
139 $product->update_meta_data( '_subscrpt_payment_type', 'recurring' );
140
141 if ( function_exists( 'subscrpt_pro_activated' ) && subscrpt_pro_activated() && '' !== $signup_fee ) {
142 $product->update_meta_data( '_subscrpt_signup_fee', wc_format_decimal( $signup_fee ) );
143 }
144 }
145
146 /**
147 * Return available variations for a variable product (wizard use).
148 *
149 * @return void Sends JSON.
150 */
151 public function get_product_variations() {
152 check_ajax_referer( 'subscrpt_onboarding_wizard', 'nonce' );
153
154 if ( ! current_user_can( 'manage_options' ) ) {
155 wp_send_json_error( array( 'message' => __( 'Permission denied.', 'subscription' ) ), 403 );
156 }
157
158 $product_id = isset( $_POST['product_id'] ) ? absint( $_POST['product_id'] ) : 0;
159 if ( ! $product_id ) {
160 wp_send_json_error( array( 'message' => __( 'Invalid product.', 'subscription' ) ) );
161 }
162
163 $product = wc_get_product( $product_id );
164 if ( ! $product || 'variable' !== $product->get_type() ) {
165 wp_send_json_error( array( 'message' => __( 'Not a variable product.', 'subscription' ) ) );
166 }
167
168 $available = $product->get_available_variations();
169 $result = array();
170
171 foreach ( $available as $variation ) {
172 $v_id = $variation['variation_id'];
173
174 // Build human-readable attribute label.
175 $attr_labels = array();
176 foreach ( $variation['attributes'] as $attr_key => $attr_value ) {
177 if ( '' === $attr_value ) {
178 $attr_labels[] = __( 'Any', 'subscription' );
179 continue;
180 }
181 $taxonomy = str_replace( 'attribute_', '', $attr_key );
182 if ( taxonomy_exists( $taxonomy ) ) {
183 $term = get_term_by( 'slug', $attr_value, $taxonomy );
184 $attr_labels[] = $term ? $term->name : ucfirst( str_replace( '-', ' ', $attr_value ) );
185 } else {
186 $attr_labels[] = ucfirst( str_replace( '-', ' ', $attr_value ) );
187 }
188 }
189 $label = implode( ' / ', $attr_labels );
190 if ( ! $label ) {
191 /* translators: %d: variation ID */
192 $label = sprintf( __( 'Variation #%d', 'subscription' ), $v_id );
193 }
194
195 $result[] = array(
196 'id' => $v_id,
197 'label' => $label,
198 'price' => $variation['display_price'],
199 'sku' => $variation['sku'],
200 'billing_period' => get_post_meta( $v_id, '_subscrpt_timing_option', true ),
201 'billing_per' => get_post_meta( $v_id, '_subscrpt_timing_per', true ) ?: 1,
202 'trial_per' => get_post_meta( $v_id, '_subscrpt_trial_timing_per', true ),
203 'signup_fee' => get_post_meta( $v_id, '_subscrpt_signup_fee', true ),
204 );
205 }
206
207 wp_send_json_success( $result );
208 }
209
210 /**
211 * Reset wizard session (for "Add another" action).
212 *
213 * @return void Sends JSON.
214 */
215 public function reset_wizard() {
216 check_ajax_referer( 'subscrpt_onboarding_wizard', 'nonce' );
217
218 if ( ! current_user_can( 'manage_options' ) ) {
219 wp_send_json_error( array( 'message' => __( 'Permission denied.', 'subscription' ) ), 403 );
220 }
221
222 if ( ! session_id() ) {
223 session_start();
224 }
225
226 unset( $_SESSION['subscrpt_onboarding_wizard'] );
227
228 wp_send_json_success();
229 }
230 }
231