PluginProbe
SellKit – Funnel builder and checkout optimizer for WooCommerce to sell more, faster / 1.2.5
SellKit – Funnel builder and checkout optimizer for WooCommerce to sell more, faster v1.2.5
2.7.0 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 All 43 releases
sellkit / includes / elementor / modules / checkout / classes / global-hooks.php

global-hooks.php in SellKit – Funnel builder and checkout optimizer for WooCommerce to sell more, faster 1.2.5, at includes/elementor/modules/checkout/classes/global-hooks.php

800 lines 23.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Sellkit\Elementor\Modules\Checkout\Classes;
4
5 defined( 'ABSPATH' ) || exit;
6
7 use Sellkit\Elementor\Modules\Checkout\Classes\Local_Hooks;
8 use Sellkit\Funnel\Steps\Checkout;
9
10 /**
11 * Global hooks.
12 *
13 * @SuppressWarnings(PHPMD.UnusedFormalParameter)
14 * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
15 * @SuppressWarnings(PHPMD.TooManyMethods)
16 * @since 1.1.0
17 */
18 class Global_Hooks {
19 /**
20 * Create instance of class without construct.
21 *
22 * @since 1.1.0
23 * @return object
24 */
25 public static function instance() {
26 $class = new \ReflectionClass( __CLASS__ );
27 return $class->newInstanceWithoutConstructor();
28 }
29
30 /**
31 * Class construct.
32 * required actions that affects woocommerce global checkout shortcode / page.
33 *
34 * @since 1.1.0
35 */
36 public function __construct() {
37 // Create empty shortcode to simulate our widget page as checkout page.
38 add_shortcode( 'sellkit_checkout_widget_simulated', function() {
39 return '';
40 } );
41
42 add_action( 'wp_ajax_sellkit_checkout_ajax_handler', [ $this, 'ajax_handler' ] );
43 add_action( 'wp_ajax_nopriv_sellkit_checkout_ajax_handler', [ $this, 'ajax_handler' ] );
44
45 // Add shipping total to review order by custom hook.
46 add_action( 'sellkit-checkout-widget-display-shipping-price', [ $this, 'add_shipping_total_to_review_order' ] );
47
48 // Modify checkout order-review item.
49 add_action( 'sellkit-one-page-checkout-custom-order-item', [ $this, 'modify_checkout_order_item' ], 1, 4 );
50
51 // Modify sent data before processing & validate order.
52 add_filter( 'woocommerce_checkout_posted_data', [ $this, 'modify_order_data_before_validate' ], 10, 1 );
53
54 // Validate user defined fields.
55 add_action( 'woocommerce_checkout_process', [ $this, 'validate_user_defined_fields' ] );
56
57 // Save user defined fields.
58 add_action( 'woocommerce_checkout_update_order_meta', [ $this, 'save_user_defined_fields' ] );
59
60 // Add custom shipping field to email.
61 add_filter( 'woocommerce_order_get_formatted_shipping_address', [ $this, 'attach_user_shipping_fields_to_order_email' ], 10, 3 );
62
63 // Add custom billing field to email.
64 add_filter( 'woocommerce_order_get_formatted_billing_address', [ $this, 'attach_user_billing_fields_to_order_email' ], 10, 3 );
65
66 // Filter checkout ajax fragment.
67 add_filter( 'woocommerce_update_order_review_fragments', [ $this, 'checkout_fragment' ] );
68
69 // Simulate checkout page for our widget.
70 add_action( 'wp', [ $this, 'simulate_our_widget_page_as_checkout' ] );
71
72 // Fix shipping method price change on ajax.
73 // Manage bump order discounts.
74 // Template replacement.
75 add_action( 'woocommerce_checkout_update_order_review', [ $this, 'sellkit_checkout_during_ajax' ], 10, 1 );
76 }
77
78 /**
79 * Handle ajax calls.
80 *
81 * @since 1.1.0
82 * @return void
83 */
84 public function ajax_handler() {
85 check_ajax_referer( 'sellkit_elementor', 'nonce' );
86
87 $sub_action = filter_input( INPUT_POST, 'sub_action', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
88
89 if ( method_exists( $this, $sub_action ) ) {
90 call_user_func( [ $this, $sub_action ] );
91 return;
92 }
93
94 wp_send_json_error();
95 }
96
97 /**
98 * Modify checkout ajax response HTML.
99 *
100 * @param array $response woocommerce checkout page ajax response.
101 * @return array
102 * @since 1.1.0
103 */
104 public function checkout_fragment( $response ) {
105 // Get posted data and identify if it's been sent by jupiter widget or not.
106 $checkout_form_data = filter_input( INPUT_POST, 'post_data', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
107 $checkout_form_data = explode( '&', $checkout_form_data );
108 $posted_data = [];
109
110 foreach ( $checkout_form_data as $input ) {
111 $item = explode( '=', urldecode( $input ) );
112
113 $posted_data[ $item[0] ] = $item[1];
114 }
115
116 // Identify if it's been sent by jupiter checkout widget or not.
117 if ( ! array_key_exists( 'form_id', $posted_data ) && ! array_key_exists( 'post_id', $posted_data ) ) {
118 // Default woocommerce checkout.
119 return $response;
120 }
121
122 // Get widget settings.
123 $widget_settings = Helper::instance()->retrieve_checkout_widget_settings( $posted_data['post_id'], $posted_data['form_id'] );
124
125 // Order review fragment.
126 ob_start();
127 woocommerce_order_review();
128 $order_review = ob_get_clean();
129
130 // Payment fragment.
131 ob_start();
132 woocommerce_checkout_payment();
133 $payment = ob_get_clean();
134
135 // Shipping method fragment.
136 ob_start();
137 echo '<section class="sellkit-one-page-shipping-methods">';
138 wc_cart_totals_shipping_html();
139 echo '</section>';
140 $shipping_method = ob_get_clean();
141
142 $response['.woocommerce-checkout-review-order-table'] = $order_review;
143 $response['.woocommerce-checkout-payment'] = $payment;
144 $response['.sellkit-one-page-shipping-methods'] = '';
145
146 if ( ! array_key_exists( 'show_shipping_method', $widget_settings ) ) {
147 $response['.sellkit-one-page-shipping-methods'] = $shipping_method;
148 }
149
150 return $response;
151 }
152
153 /**
154 * Apply coupon code using ajax.
155 *
156 * @return void
157 * @since 1.1.0
158 */
159 public function apply_coupon() {
160 $code = filter_input( INPUT_POST, 'code', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
161
162 if ( empty( $code ) ) {
163 wp_send_json_error();
164 }
165
166 $result = WC()->cart->add_discount( $code );
167 wp_send_json_success( $result );
168 }
169
170 /**
171 * Update cart item quantity in checkout page by ajax.
172 *
173 * @return void
174 * @since 1.1.0
175 */
176 public function change_cart_item_qty() {
177 $qty = filter_input( INPUT_POST, 'qty', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
178 $id = filter_input( INPUT_POST, 'id', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
179 $action = filter_input( INPUT_POST, 'mode', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
180 $funnel_id = filter_input( INPUT_POST, 'related_checkout', FILTER_SANITIZE_NUMBER_INT );
181
182 $this->make_changes_after_cart_item_edit( $funnel_id );
183
184 if ( 'add' === $action ) {
185 WC()->cart->add_to_cart( $id, $qty );
186 $this->make_changes_after_cart_item_edit( $funnel_id );
187 wp_send_json_success();
188 }
189
190 if ( 'remove' === $action ) {
191 $product_cart_id = WC()->cart->generate_cart_id( $id );
192 $cart_item_key = WC()->cart->find_product_in_cart( $product_cart_id );
193
194 if ( $cart_item_key ) {
195 WC()->cart->remove_cart_item( $cart_item_key );
196 }
197
198 $this->make_changes_after_cart_item_edit( $funnel_id );
199
200 wp_send_json_success();
201 }
202
203 ( $qty > 0 ) ? WC()->cart->set_quantity( $id, $qty ) : WC()->cart->remove_cart_item( $id );
204
205 $this->make_changes_after_cart_item_edit( $funnel_id );
206
207 wp_send_json_success();
208 }
209
210 /**
211 * Apply changes after editing cart items.
212 *
213 * @since 1.2.5
214 * @param int $funnel_id funnel step id.
215 */
216 private function make_changes_after_cart_item_edit( $funnel_id ) {
217 if ( empty( $funnel_id ) ) {
218 return;
219 }
220
221 $funnel_data = get_post_meta( $funnel_id, 'step_data', true );
222 $optimization_data = ! empty( $funnel_data['data']['optimization'] ) ? $funnel_data['data']['optimization'] : '';
223
224 if ( empty( $optimization_data ) ) {
225 return;
226 }
227
228 if ( Checkout::apply_coupon_validation( $optimization_data ) ) {
229 WC()->cart->remove_coupons();
230
231 foreach ( $optimization_data['auto_apply_coupons'] as $auto_apply_coupon ) {
232 wc()->cart->add_discount( get_the_title( $auto_apply_coupon['value'] ) );
233 }
234
235 wc_clear_notices();
236 }
237 }
238
239 /**
240 * Place shipping price based on design to checkout order-review.
241 *
242 * @return void
243 * @since 1.1.0
244 */
245 public function add_shipping_total_to_review_order() {
246 ?>
247 <tr class="sellkit-shipping-total">
248 <th><?php echo __( 'Shipping', 'sellkit' ); ?></th>
249 <td><?php echo wc_price( WC()->cart->get_shipping_total() ); ?></td>
250 </tr>
251 <?php
252 }
253
254 /**
255 * Modify checkout review-order based on design.
256 *
257 * @return void
258 * @param string $row html string of cart row.
259 * @param object $product product object.
260 * @param array $cart_item cart item information.
261 * @param string $cart_item_key cart item unique key.
262 * @since 1.1.0
263 */
264 public function modify_checkout_order_item( $row, $product, $cart_item, $cart_item_key ) {
265 $cart_items = WC()->cart->get_cart();
266
267 //phpcs:disable
268 ob_start();
269 ?>
270 <div style="display: inline-block" class="sellkit-checkout-widget-item-image">
271 <?php echo $product->get_image(); ?>
272 </div>
273 <?php
274 $img_html = ob_get_clean();
275 $img_html = apply_filters( 'sellkit/includes/elementor/modules/checkout/product-image', $img_html, $product, $cart_item_key );
276
277 ob_start();
278
279 $extra_class = '';
280 if ( $cart_items[ $cart_item_key ] === end( $cart_items ) ) {
281 $extra_class = ' last-cart-item';
282 }
283 ?>
284 <tr class="<?php echo esc_attr( apply_filters( 'woocommerce_cart_item_class', 'cart_item', $cart_item, $cart_item_key ) ) . $extra_class; ?>">
285
286 <td class="product-name sellkit-one-page-checkout-product-name">
287 <?php
288 echo $img_html;
289
290 $fix_style = '';
291
292 if ( '' === $img_html ) {
293 $fix_style = 'margin-left: 0px;';
294 }
295 ?>
296
297 <div class="name-price" style="<?php echo esc_attr( $fix_style ); ?>">
298 <span style="display:inline-block">
299 <?php echo wp_kses_post( apply_filters( 'woocommerce_cart_item_name', $product->get_name(), $cart_item, $cart_item_key ) ) . '&nbsp;'; ?>
300 </span>
301 <span class="sellkit-checkout-variations">
302 <?php echo wc_get_formatted_cart_item_data( $cart_item ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
303 </span>
304 <?php echo apply_filters( 'sellkit-checkout-widget-disable-quantity', '<input type="number" data-id="' . esc_attr( $cart_item_key ) . '" value="' . esc_attr( $cart_item['quantity'] ) . '" class="sellkit-one-page-checkout-product-qty" >', $cart_item['quantity'] ); ?>
305 <?php do_action( 'sellkit-checkout-editor-mode-quantity', $cart_item['quantity'] ); ?>
306 </div>
307 </td>
308 <td class="product-total sellkit-one-page-checkout-product-price">
309 <?php echo apply_filters( 'woocommerce_cart_item_subtotal', WC()->cart->get_product_subtotal( $product, $cart_item['quantity'] ), $cart_item, $cart_item_key ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
310 </td>
311 </tr>
312 <?php
313 $cart_item = ob_get_clean();
314
315 echo apply_filters( 'sellkit-checkout-cart-item' , $cart_item );
316 //phpcs:enable
317 }
318
319 /**
320 * Modify fields after pressing place order button.
321 * we hooked here because some removed fields still get checked and have not removed by previous hooks.
322 *
323 * @param array $data checkout form data.
324 * @return array $data data of woocommerce checkout form.
325 * @since 1.1.0
326 */
327 public function modify_order_data_before_validate( $data ) {
328 $post_id = filter_input( INPUT_POST, 'post_id', FILTER_SANITIZE_NUMBER_INT );
329 $form_id = filter_input( INPUT_POST, 'form_id', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
330
331 if ( empty( $post_id ) && empty( $form_id ) ) {
332 return $data;
333 }
334
335 $settings = Helper::instance()->retrieve_checkout_widget_settings( $post_id, $form_id );
336
337 if ( empty( $settings ) ) {
338 return $data;
339 }
340
341 $widget_shipping_field = Helper::instance()->get_user_defined_fields_slug( $settings['shipping_list'], 'shipping_list_field' );
342 $widget_billing_field = Helper::instance()->get_user_defined_fields_slug( $settings['billing_list'], 'billing_list_field' );
343
344 $default_shipping_fields = Helper::instance()->shipping_fields();
345 $default_billing_fields = Helper::instance()->billing_fields();
346
347 // Unset removed shipping fields.
348 foreach ( $default_shipping_fields as $field => $details ) {
349 if ( ! in_array( $field, $widget_shipping_field, true ) ) {
350 unset( $data[ $field ] );
351 }
352 }
353
354 // Unset removed billing fields.
355 foreach ( $default_billing_fields as $field => $details ) {
356 if ( ! in_array( $field, $widget_billing_field, true ) && 'billing_email' !== $field ) {
357 unset( $data[ $field ] );
358 }
359 }
360
361 return $data;
362 }
363
364 /**
365 * Login user by ajax.
366 * sign user in by using form included in widget.
367 *
368 * @return void
369 * @since 1.1.0
370 */
371 public function auth_user() {
372 $email = filter_input( INPUT_POST, 'email', FILTER_SANITIZE_EMAIL );
373 $pass = filter_input( INPUT_POST, 'pass', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
374 $verify = filter_var( $email, FILTER_VALIDATE_EMAIL );
375
376 if ( ! $verify || empty( $email ) || empty( $pass ) ) {
377 wp_send_json_error( __( 'Email or password field is not valid.', 'sellkit' ) );
378 }
379
380 $result = wp_authenticate( $email, $pass );
381
382 if ( is_wp_error( $result ) ) {
383 wp_send_json_error( $result->get_error_message() );
384 }
385
386 wp_clear_auth_cookie();
387 wp_set_current_user( $result->ID );
388 wp_set_auth_cookie( $result->ID );
389
390 wp_send_json_success( $result );
391 }
392
393 /**
394 * Get widget settings in ajax calls using form and post id.
395 *
396 * @return void
397 * @since 1.1.0
398 */
399 private function widget_settings() {
400 $form_id = filter_input( INPUT_POST, 'form_id', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
401 $post_id = filter_input( INPUT_POST, 'post_id', FILTER_SANITIZE_NUMBER_INT );
402
403 if ( empty( $form_id ) && empty( $post_id ) ) {
404 return;
405 }
406
407 $widget_settings = Helper::instance()->retrieve_checkout_widget_settings( $post_id, $form_id );
408
409 return $widget_settings;
410 }
411
412 /**
413 * Validate user defined custom value.
414 *
415 * @return void
416 * @since 1.1.0
417 */
418 public function validate_user_defined_fields() {
419 $widget_settings = $this->widget_settings();
420
421 if ( empty( $widget_settings ) ) {
422 return;
423 }
424
425 $widget_shipping_fields = $widget_settings['shipping_list'];
426 $widget_billing_fields = $widget_settings['billing_list'];
427
428 Helper::instance()->validate_user_defined_fields( $widget_shipping_fields, $widget_billing_fields );
429 Helper::instance()->make_sure_to_convert_required_field_to_optional( $widget_shipping_fields, $widget_billing_fields );
430 }
431
432 /**
433 * Save user defined custom fields value to database.
434 *
435 * @param int $order_id id of woocommerce order.
436 * @return void
437 * @since 1.1.0
438 */
439 public function save_user_defined_fields( $order_id ) {
440 $widget_settings = $this->widget_settings();
441
442 if ( empty( $widget_settings ) ) {
443 return;
444 }
445
446 $widget_shipping_fields = $widget_settings['shipping_list'];
447 $widget_billing_fields = $widget_settings['billing_list'];
448
449 Helper::instance()->save_user_defined_fields( $widget_shipping_fields, $widget_billing_fields, $order_id );
450 }
451
452 /**
453 * Attach user defined shipping field values to order emails.
454 *
455 * @param string $address address.
456 * @param string $raw_address raw address.
457 * @param object $order woocommerce order object.
458 * @return string
459 * @since 1.1.0
460 */
461 public function attach_user_shipping_fields_to_order_email( $address, $raw_address, $order ) {
462 $order_id = $order->get_id();
463 $custom_fields = get_post_meta( $order_id, 'sellkit_checkout_widget_custom_field_of_order', true );
464
465 if ( empty( $custom_fields ) || ! is_array( $custom_fields ) ) {
466 return $address;
467 }
468
469 foreach ( $custom_fields as $field ) {
470 if ( 'yes' !== $field['show_in_email'] ) {
471 continue;
472 }
473
474 $key = $field['key_name'];
475 $value = get_post_meta( $order_id, $key, true );
476
477 if ( strpos( $key, 'shipping' ) !== false ) {
478 $address .= '<br>' . $value;
479 }
480 }
481
482 return $address;
483 }
484
485 /**
486 * Attach user defined billing field values to order emails.
487 *
488 * @param string $address address.
489 * @param string $raw_address raw address.
490 * @param object $order woocommerce order object.
491 * @return string
492 * @since 1.1.0
493 */
494 public function attach_user_billing_fields_to_order_email( $address, $raw_address, $order ) {
495 $order_id = $order->get_id();
496 $custom_fields = get_post_meta( $order_id, 'sellkit_checkout_widget_custom_field_of_order', true );
497
498 if ( empty( $custom_fields ) || ! is_array( $custom_fields ) ) {
499 return $address;
500 }
501
502 foreach ( $custom_fields as $field ) {
503 if ( 'yes' !== $field['show_in_email'] ) {
504 continue;
505 }
506
507 $key = $field['key_name'];
508 $value = get_post_meta( $order_id, $key, true );
509
510 if ( strpos( $key, 'billing' ) !== false ) {
511 $address .= '<br>' . $value;
512 }
513 }
514
515 return $address;
516 }
517
518 /**
519 * Place custom coupon form in checkout order-review based design.
520 * We have used same form in Local_Hooks. but this one is for ajax response.
521 *
522 * @see sellkit_Core\Raven\Modules\Checkout\Classes\Local_Hooks::coupon_form.
523 * @param array $settings widget settings.
524 * @return void
525 * @since 1.1.0
526 */
527 public function coupon_form( $settings ) {
528 if ( array_key_exists( 'show_coupon_field', $settings ) ) {
529 return;
530 }
531
532 echo '<tr class="coupon-form border-none"><td colspan="2">';
533 Local_Hooks::form( $settings );
534 echo '</td></tr>';
535
536 do_action( 'sellkit-checkout-after-coupon-form-ajax' );
537 }
538
539 /**
540 * Look for an email if exists or not.
541 * Is used for login process.
542 *
543 * @return void
544 * @since 1.1.0
545 */
546 public function search_for_email() {
547 $email = filter_input( INPUT_POST, 'email', FILTER_SANITIZE_EMAIL );
548 $valid = filter_var( $email, FILTER_VALIDATE_EMAIL );
549
550 if ( ! $valid || empty( $email ) ) {
551 wp_send_json_error();
552 }
553
554 $check = email_exists( $email );
555
556 if ( false === $check ) {
557 wp_send_json_error();
558 }
559
560 wp_send_json_success();
561 }
562
563 /**
564 * Look for an username if exists or not.
565 * Is used for register process.
566 *
567 * @return void
568 * @since 1.1.0
569 */
570 public function search_for_username() {
571 $username = filter_input( INPUT_POST, 'user', FILTER_SANITIZE_EMAIL );
572
573 if ( empty( $username ) ) {
574 wp_send_json_error();
575 }
576
577 $username = sanitize_user( $username );
578 $check = username_exists( $username );
579
580 if ( false !== $check ) {
581 wp_send_json_error();
582 }
583
584 wp_send_json_success();
585 }
586
587 /**
588 * Validate postcode via ajax.
589 *
590 * @since 1.1.0
591 * @return void
592 */
593 public function validate_postcode() {
594 $country = filter_input( INPUT_POST, 'country_code', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
595 $postcode = filter_input( INPUT_POST, 'post_code', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
596 $parent = filter_input( INPUT_POST, 'parent', FILTER_DEFAULT );
597
598 $postcode = wc_format_postcode( $postcode, $country );
599 $valid = \WC_Validation::is_postcode( $postcode, $country );
600
601 if ( ! $valid ) {
602 wp_send_json_error( $parent );
603 }
604
605 wp_send_json_success( $parent );
606 }
607
608 /**
609 * Validate phone number via ajax.
610 *
611 * @since 1.1.0
612 * @return void
613 */
614 public function validate_phone_number() {
615 $phone = filter_input( INPUT_POST, 'phone_number', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
616 $parent = filter_input( INPUT_POST, 'parent', FILTER_DEFAULT );
617
618 $valid = \WC_Validation::is_phone( $phone );
619
620 if ( ! $valid ) {
621 wp_send_json_error( $parent );
622 }
623
624 wp_send_json_success( $parent );
625 }
626
627 /**
628 * Simulate checkout page where our widget is present. using empty shortcode [sellkit_checkout_widget_simulated].
629 *
630 * @since 1.1.0
631 * @return void
632 */
633 public function simulate_our_widget_page_as_checkout() {
634 $page_id = get_the_ID();
635 $content = get_post_field( 'post_content', $page_id );
636
637 if ( false === strpos( $content, 'woocommerce_checkout' ) ) {
638 return;
639 }
640
641 add_filter( 'woocommerce_is_checkout', function() {
642 return true;
643 } );
644
645 if ( false === strpos( $content, 'sellkit_checkout_widget_simulated' ) ) {
646 return;
647 }
648
649 add_filter( 'theme_mod_jupiterx_jupiterx_checkout_cart_elements', function() {
650 return [];
651 }, 10 );
652 }
653
654 /**
655 * Integrate user country with our widget.
656 *
657 * @since 1.1.0
658 * @return void
659 */
660 public function set_customer_details_ajax() {
661 $country = filter_input( INPUT_POST, 'country', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
662 $state = filter_input( INPUT_POST, 'state', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
663 $shipping_country = filter_input( INPUT_POST, 'shipping_country', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
664 $shipping_state = filter_input( INPUT_POST, 'shipping_state', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
665
666 if ( ! empty( $country ) ) {
667 setcookie( 'sellkit-checkout-billing-cc', $country, time() + ( 86400 * 3 ), '/' );
668 setcookie( 'sellkit-checkout-billing-state', $state, time() + ( 86400 * 3 ), '/' );
669 }
670
671 if ( ! empty( $shipping_country ) ) {
672 setcookie( 'sellkit-checkout-shipping-cc', $shipping_country, time() + ( 86400 * 3 ), '/' );
673 setcookie( 'sellkit-checkout-shipping-state', $shipping_state, time() + ( 86400 * 3 ), '/' );
674 }
675
676 wp_send_json_success();
677 }
678
679 /**
680 * State lookup using postcode and country.
681 *
682 * @since 1.1.0
683 * @return void
684 */
685 public function sellkit_state_lookup_by_postcode() {
686 $country = filter_input( INPUT_POST, 'country_value', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
687 $postcode = filter_input( INPUT_POST, 'postcode_value', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
688 $api = 'https://api.zippopotam.us/' . $country . '/' . $postcode;
689
690 if ( empty( $country ) || empty( $postcode ) ) {
691 wp_send_json_error( esc_html__( 'Not valid inputs', 'sellkit' ) );
692 }
693
694 $response = wp_remote_get( $api );
695
696 if ( is_wp_error( $response ) || ! is_array( $response ) ) {
697 wp_send_json_error( esc_html__( 'Server error.', 'sellkit' ) );
698 }
699
700 if ( '{}' === $response['body'] ) {
701 wp_send_json_error( esc_html__( 'Selected country or postcode is not supported.', 'sellkit' ) );
702 }
703
704 $body = json_decode( $response['body'], true );
705
706 wp_send_json_success( $body );
707 }
708
709 /**
710 * Modify cart contents using bundled products.
711 *
712 * @since 1.1.0
713 * @return void
714 */
715 public function sellkit_checkout_modify_cart_by_bundle_products() {
716 $qty = filter_input( INPUT_POST, 'qty', FILTER_SANITIZE_NUMBER_INT );
717 $id = filter_input( INPUT_POST, 'id', FILTER_SANITIZE_NUMBER_INT );
718 $type = filter_input( INPUT_POST, 'type', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
719
720 WC()->cart->empty_cart();
721
722 if ( 'radio' === $type ) {
723 WC()->cart->add_to_cart( $id, $qty );
724 }
725
726 wp_send_json_success();
727 }
728
729 /**
730 * Fix shipping method price on checkout ajax state change.
731 *
732 * @param string $data checkout form data.
733 * @since 1.1.0
734 * @return void
735 */
736 public function sellkit_checkout_during_ajax( $data ) {
737 $data = explode( '&', $data );
738 $clear = [];
739
740 foreach ( $data as $key => $input ) {
741 $input = explode( '=', $input );
742 $clear[ $input[0] ] = $input[1];
743 }
744
745 if ( ! array_key_exists( 'form_id', $clear ) ) {
746 return;
747 }
748
749 $this->apply_template_replacement_during_ajax( $clear );
750
751 if ( array_key_exists( 'shipping_state', $clear ) ) {
752 $_POST['s_state'] = $clear['shipping_state'];
753 }
754
755 if ( array_key_exists( 'billing_state', $clear ) ) {
756 $_POST['state'] = $clear['billing_state'];
757 }
758
759 Local_Hooks::order_bump( $clear );
760
761 if ( array_key_exists( 'sellkit-bundle-products', $clear ) ) {
762 $option = $clear['sellkit-bundle-products'];
763
764 Local_Hooks::bundle_product_action( $option );
765 }
766 }
767
768 /**
769 * Template replacement during ajax call.
770 *
771 * @param array $data checkout form data.
772 * @since 1.2.1
773 */
774 private function apply_template_replacement_during_ajax( $data ) {
775 $widget_settings = Helper::instance()->retrieve_checkout_widget_settings( $data['post_id'], $data['form_id'] );
776
777 Local_Hooks::enable_disable_sections( $widget_settings, $data );
778
779 add_filter( 'wc_get_template', function( $located, $template_name ) {
780 $our_path = sellkit()->plugin_dir() . 'includes/elementor/modules/checkout/templates/';
781 $files = [
782 'review-order.php',
783 'payment-method.php',
784 'payment.php',
785 'form-checkout.php',
786 'cart-item-data.php',
787 'cart-shipping.php',
788 ];
789 $template = str_replace( 'checkout/', '', $template_name );
790 $template = str_replace( 'cart/', '', $template );
791
792 if ( in_array( $template, $files, true ) ) {
793 $located = $our_path . $template;
794 }
795
796 return $located;
797 }, 10, 2 );
798 }
799 }
800