PluginProbe
SellKit – Funnel builder and checkout optimizer for WooCommerce to sell more, faster / 1.6.2
SellKit – Funnel builder and checkout optimizer for WooCommerce to sell more, faster v1.6.2
2.6.0 trunk 1.1.0 1.1.4 1.2.1 1.2.2 1.2.3 1.2.5 1.2.9 1.3.1 1.3.2 1.5.0 1.5.1 1.5.4 1.5.7 1.5.8 1.5.9 1.6.2 1.6.5 1.6.8 1.7.2 1.7.4 1.7.5 1.7.9 1.8.1 All 42 releases
sellkit / includes / funnel / steps / checkout.php

checkout.php in SellKit – Funnel builder and checkout optimizer for WooCommerce to sell more, faster 1.6.2, at includes/funnel/steps/checkout.php

351 lines 8.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Sellkit\Funnel\Steps;
4
5 use Sellkit\Funnel\Analytics\Data_Updater;
6 use Sellkit\Funnel\Contacts\Base_Contacts;
7 use Sellkit\Database;
8 use Sellkit_Funnel;
9
10 defined( 'ABSPATH' ) || die();
11
12 /**
13 * Class Sellkit_Checkout.
14 *
15 * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
16 * @since 1.1.0
17 */
18 class Checkout {
19
20 /**
21 * Funnel instance.
22 *
23 * @var Sellkit_Funnel Funnel object.
24 * @since 1.1.0
25 */
26 public $funnel;
27
28 /**
29 * Checkout constructor.
30 *
31 * @since 1.1.0
32 */
33 public function __construct() {
34 $this->update_funnel_data();
35
36 if ( empty( $this->funnel->funnel_id ) ) {
37 return;
38 }
39
40 add_action( 'woocommerce_checkout_create_order', [ $this, 'save_order_custom_meta_data' ], 10 );
41 add_action( 'woocommerce_after_order_notes', [ $this, 'custom_checkout_hidden_fields' ], 10 );
42 add_action( 'wc_ajax_update_order_review', [ $this, 'do_actions' ] );
43 }
44
45 /**
46 * Adding items to the checkout page.
47 *
48 * @since 1.1.0
49 * @SuppressWarnings(PHPMD.NPathComplexity)
50 * @SuppressWarnings(PHPMD.CyclomaticComplexity)
51 */
52 public function do_actions() {
53 // These variables should be used in checkout builder widget.
54 $funnel_data = $this->funnel->current_step_data;
55 $optimization_data = ! empty( $funnel_data['data']['optimization'] ) ? $funnel_data['data']['optimization'] : '';
56 $redirect_url = ! empty( $optimization_data['closed_checkout_redirect_url'] ) ? $optimization_data['closed_checkout_redirect_url'] : site_url();
57
58 add_action( 'template_redirect', function () use ( $funnel_data ) {
59 $product_settings = ! empty( $funnel_data['data']['products']['settings'] ) ? $funnel_data['data']['products']['settings'] : '';
60 $bump_data = ! empty( $funnel_data['bump'] ) ? $funnel_data['bump'] : '';
61
62 if ( ! empty( $product_settings ) ) {
63 set_query_var( 'funnel_product_settings', $product_settings );
64 }
65
66 if ( ! empty( $bump_data ) ) {
67 $bump_data = $this->get_valid_bumps( $bump_data );
68
69 set_query_var( 'bump_data', $bump_data );
70 }
71 } );
72
73 if (
74 ! empty( $optimization_data['expiration_date'] ) &&
75 ! empty( $optimization_data['expire_checkout_coupons_switch'] ) &&
76 time() > $optimization_data['expiration_date'] &&
77 'on' === $optimization_data['expire_checkout_coupons_switch']
78 ) {
79 wp_redirect( $this->add_http_to_url( $redirect_url ) ); // phpcs:ignore
80 exit;
81 }
82
83 if ( empty( $funnel_data ) ) {
84 return;
85 }
86
87 if (
88 empty( $funnel_data['data']['products']['list'] ) ||
89 ! is_array( $funnel_data['data']['products']['list'] )
90 ) {
91 return;
92 }
93
94 $funnel_products = $funnel_data['data']['products']['list'];
95
96 if ( ! sellkit()->has_valid_dependencies() ) {
97 return;
98 }
99
100 $action = sellkit_htmlspecialchars( INPUT_GET, 'wc-ajax' );
101
102 if ( 'update_order_review' !== $action && 'checkout' !== $action ) {
103 wc()->cart->empty_cart();
104
105 foreach ( $funnel_products as $product_id => $product ) {
106 if ( empty( $product ) ) {
107 continue;
108 }
109
110 $quantity = ! empty( $product['quantity'] ) ? $product['quantity'] : 1;
111
112 wc()->cart->add_to_cart( $product_id, $quantity );
113 }
114 }
115
116 if ( empty( $optimization_data ) ) {
117 return;
118 }
119
120 if ( self::apply_coupon_validation( $optimization_data ) ) {
121 foreach ( $optimization_data['auto_apply_coupons'] as $auto_apply_coupon ) {
122 wc()->cart->add_discount( get_the_title( $auto_apply_coupon['value'] ) );
123 }
124
125 wc_clear_notices();
126 }
127 }
128
129 /**
130 * Adds http if it is needed.
131 *
132 * @since 1.5.0
133 * @param string $url Entered url.
134 * @return string|boolean
135 */
136 private function add_http_to_url( $url ) {
137 if ( ! preg_match( '~^(?:f|ht)tps?://~i', $url ) ) {
138 return 'http://' . $url;
139 }
140
141 return $url;
142 }
143
144 /**
145 * Saving the funnel data to the order.
146 *
147 * @since 1.1.0
148 * @param object $order Order object.
149 */
150 public function save_order_custom_meta_data( $order ) {
151 if ( empty( $this->funnel->next_step_data ) ) {
152 return;
153 }
154
155 Base_Contacts::step_is_passed();
156 $this->check_bump_acceptance( $order );
157
158 $analytics_updater = new Data_Updater();
159
160 $analytics_updater->set_funnel_id( $this->funnel->funnel_id );
161 $analytics_updater->add_new_order_log( $order );
162
163 $order->update_meta_data( 'sellkit_funnel_next_step_data', $this->funnel->next_step_data );
164 $order->update_meta_data( 'sellkit_funnel_id', $this->funnel->funnel_id );
165 }
166
167 /**
168 * Adding page id field to the inputs.
169 *
170 * @since 1.1.0
171 */
172 public function custom_checkout_hidden_fields() {
173 woocommerce_form_field( 'sellkit_current_page_id', [
174 'type' => 'hidden',
175 'class' => [ 'hidden form-row-wide' ],
176 ], get_the_ID() );
177 }
178
179 /**
180 * Check If a coupon should be applied.
181 *
182 * @since 1.1.0
183 * @param array $optimization_data Optimization data.
184 */
185 public static function apply_coupon_validation( $optimization_data ) {
186 if (
187 empty( $optimization_data['auto_apply_coupons_switch'] ) ||
188 'on' !== $optimization_data['auto_apply_coupons_switch']
189 ) {
190 return false;
191 }
192
193 if (
194 empty( $optimization_data['auto_apply_coupons'] ) ||
195 ! is_array( $optimization_data['auto_apply_coupons'] )
196 ) {
197 return false;
198 }
199
200 return true;
201 }
202
203 /**
204 * Calculate total discount.
205 *
206 * @since 1.1.0
207 * @param string $total Total.
208 * @param string $value Value.
209 * @param string $type Type.
210 * @return false|float|int|mixed
211 */
212 public function calculate_discount( $total, $value, $type ) {
213 if ( empty( $value ) || 1 > $value ) {
214 return 0;
215 }
216
217 if ( strpos( $type, 'fixed' ) !== false ) {
218 return $value;
219 }
220
221 if ( strpos( $type, 'percentage' ) !== false ) {
222 return ( floatval( $total ) * floatval( $value ) ) / 100;
223 }
224
225 return 0;
226 }
227
228 /**
229 * Gets extracted post data.
230 *
231 * @since 1.1.0
232 * @param string $post_data Post data.
233 */
234 private function get_current_page_id_by_post_data( $post_data ) {
235 $vars = explode( '&', $post_data );
236 $extracted_data = [];
237
238 foreach ( $vars as $value ) {
239 $result = explode( '=', urldecode( $value ) );
240 $extracted_data[ $result[0] ] = $result[1];
241 }
242
243 if ( empty( $extracted_data['sellkit_current_page_id'] ) ) {
244 return null;
245 }
246
247 return $extracted_data['sellkit_current_page_id'];
248 }
249
250 /**
251 * Checks all bumps and return data.
252 *
253 * @since 1.1.0
254 * @param array $bump_data Bump data.
255 */
256 public function get_valid_bumps( $bump_data ) {
257 $valid_bumps = [];
258
259 foreach ( $bump_data as $bump ) {
260 $conditions = ! empty( $bump['data']['conditions'] ) ? $bump['data']['conditions'] : '';
261
262 if ( ! empty( $conditions ) && empty( sellkit_conditions_validation( $conditions ) ) ) {
263 continue;
264 }
265
266 $valid_bumps[] = $bump;
267 }
268
269 return $valid_bumps;
270 }
271
272 /**
273 * Checks if bump is accepted during checkout or not and updates table accordingly.
274 *
275 * @param object $order WooCommerce order object.
276 * @return void
277 *
278 * @since 1.5.0
279 * @access private
280 */
281 private function check_bump_acceptance( $order ) {
282 if (
283 empty( $this->funnel->funnel_id ) ||
284 empty( $this->funnel->current_step_data['bump'] )
285 ) {
286 return;
287 }
288
289 $bump_product_ids = [];
290 foreach ( $this->funnel->current_step_data['bump'] as $bump ) {
291 if ( empty( $bump['data']['products'] ) ) {
292 continue;
293 }
294
295 $bump_product_ids = array_merge( $bump_product_ids, array_keys( $bump['data']['products']['list'] ) );
296 }
297
298 $bump_exists_in_order = false;
299
300 foreach ( $order->get_items() as $item ) {
301 $product_id = $item->get_changes()['product_id'];
302
303 if ( in_array( $product_id, $bump_product_ids, true ) ) {
304 $bump_exists_in_order = true;
305 break;
306 }
307 }
308
309 if ( ! $bump_exists_in_order ) {
310 return;
311 }
312
313 $database = new Database();
314 $old_values = [];
315
316 // Getting old data.
317 $result = $database->get( 'funnel_contact', [ 'id' => $_SESSION['entered_funnel_id'] ] );
318
319 if ( ! empty( $result[0]['order_bump'] ) ) {
320 $old_values = unserialize( $result[0]['order_bump'] ); // phpcs:ignore
321 }
322
323 $new_values = array_merge( $old_values, [ $this->funnel->current_step_data['page_id'] ] );
324
325 $database->update(
326 'funnel_contact',
327 [ 'order_bump' => $new_values ],
328 [ 'id' => $_SESSION['entered_funnel_id'] ]
329 );
330 }
331
332 /**
333 * Updates funnel data.
334 *
335 * @since 1.1.0
336 */
337 public function update_funnel_data() {
338 $action = sellkit_htmlspecialchars( INPUT_GET, 'wc-ajax' );
339
340 if ( 'update_order_review' === $action ) {
341 $post_data = sellkit_htmlspecialchars( INPUT_POST, 'post_data' );
342
343 $this->funnel = new Sellkit_Funnel( $this->get_current_page_id_by_post_data( $post_data ) );
344
345 return;
346 }
347
348 $this->funnel = Sellkit_Funnel::get_instance();
349 }
350 }
351