PluginProbe
SellKit – Funnel builder and checkout optimizer for WooCommerce to sell more, faster / trunk
SellKit – Funnel builder and checkout optimizer for WooCommerce to sell more, faster vtrunk
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 / elementor / modules / checkout / classes / helper.php

helper.php in SellKit – Funnel builder and checkout optimizer for WooCommerce to sell more, faster trunk, at includes/elementor/modules/checkout/classes/helper.php

755 lines 23.9 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 Elementor\Plugin as Elementor;
8
9 /**
10 * Helper class.
11 *
12 * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
13 * @SuppressWarnings(PHPMD.NPathComplexity)
14 * @since 1.1.0
15 */
16 class Helper {
17
18 /**
19 * Instance of this class.
20 *
21 * @since NEXT
22 * @access public
23 * @var Checkout
24 */
25 public static $instance;
26
27 /**
28 * Provides access to a single instance of a module using the singleton pattern.
29 *
30 * @since NEXT
31 * @return object
32 */
33 public static function instance() {
34 if ( null === self::$instance ) {
35 self::$instance = new self();
36 }
37
38 return self::$instance;
39 }
40
41 /**
42 * Default sellkit checkout widget billing fields.
43 *
44 * @return array
45 * @since 1.1.0
46 */
47 public function billing_fields() {
48 return [
49 'billing_first_name' => esc_html__( 'Billing First Name', 'sellkit' ),
50 'billing_last_name' => esc_html__( 'Billing Last Name', 'sellkit' ),
51 'billing_company' => esc_html__( 'Billing Company', 'sellkit' ),
52 'billing_address_1' => esc_html__( 'Billing Address 1', 'sellkit' ),
53 'billing_address_2' => esc_html__( 'Billing Address 2', 'sellkit' ),
54 'billing_city' => esc_html__( 'Billing City', 'sellkit' ),
55 'billing_postcode' => esc_html__( 'Billing Postal Code', 'sellkit' ),
56 'billing_country' => esc_html__( 'Billing Country', 'sellkit' ),
57 'billing_state' => esc_html__( 'Billing State', 'sellkit' ),
58 'billing_email' => esc_html__( 'Billing State', 'sellkit' ),
59 'billing_phone' => esc_html__( 'Billing Phone', 'sellkit' ),
60 ];
61 }
62
63 /**
64 * Default sellkit checkout widget shipping fields.
65 *
66 * @return array
67 * @since 1.1.0
68 */
69 public function shipping_fields() {
70 return [
71 'shipping_first_name' => esc_html__( 'shipping First Name', 'sellkit' ),
72 'shipping_last_name' => esc_html__( 'shipping Last Name', 'sellkit' ),
73 'shipping_address_1' => esc_html__( 'shipping Address 1', 'sellkit' ),
74 'shipping_address_2' => esc_html__( 'shipping Address 2', 'sellkit' ),
75 'shipping_city' => esc_html__( 'shipping City', 'sellkit' ),
76 'shipping_postcode' => esc_html__( 'shipping Postal Code', 'sellkit' ),
77 'shipping_country' => esc_html__( 'shipping Country', 'sellkit' ),
78 'shipping_state' => esc_html__( 'shipping State', 'sellkit' ),
79 ];
80 }
81
82 /**
83 * Gets user defined fields and return array of slug.
84 *
85 * @param array $user_defined_fields widget fields.
86 * @param string $type billing/shipping field.
87 * @return array
88 * @since 1.1.0
89 */
90 public function get_user_defined_fields_slug( $user_defined_fields, $type ) {
91 $fields = [];
92
93 foreach ( $user_defined_fields as $field ) {
94 if ( isset( $field[ $type ] ) ) {
95 $fields[] = $field[ $type ];
96 }
97 }
98
99 return $fields;
100 }
101
102 /**
103 * Assign user defined values to each field.
104 *
105 * @param array $default_fields : default woocommerce fields.
106 * @param array $widget_fields : fields get added by user from widget option.
107 * @param string $type : shipping / billing.
108 * @param array $settings : whole widget settings.
109 * @return array
110 * @since 1.1.0
111 * @SuppressWarnings(PHPMD.NPathComplexity)
112 */
113 public function assign_settings_per_field( $default_fields, $widget_fields, $type, $settings ) {
114 // Assign user properties.
115 foreach ( $widget_fields as $key => $field ) {
116 $field_slug = $field[ $type . '_list_field' ];
117 $is_custom = false;
118
119 // IF field is a custom field we replace key with id. So it will be unique.
120 // !important: user has to define id for each field using custom id field.
121 if ( 'custom_role' === $field_slug ) {
122 // Create billing_bla_bla & shipping_bla_bla for custom field.
123 $field_slug = $type . '_' . $field['_id'];
124
125 if ( ! empty( $field[ $type . '_custom_id' ] ) ) {
126 $field_slug = $type . '_' . $field[ $type . '_custom_id' ];
127 }
128
129 $is_custom = true;
130 }
131
132 $default_fields[ $field_slug ]['label'] = $field[ $type . '_list_placeholder' ];
133 $default_fields[ $field_slug ]['class'] = explode( ' ', $field[ $type . '_list_class' ] ); // phpcs:ignore
134 $default_fields[ $field_slug ]['class'][] = $field[ $type . '_width' ];
135 $default_fields[ $field_slug ]['class'][] = 'sellkit-widget-checkout-fields';
136 $default_fields[ $field_slug ]['class'][] = 'sellkit-checkout-fields-validation-' . $field[ $type . '_list_validation' ];
137 $default_fields[ $field_slug ]['required'] = ( 'yes' === $field[ $type . '_list_required' ] ) ? true : false;
138 $default_fields[ $field_slug ]['clear'] = ( 'yes' === $field[ $type . '_list_clear' ] ) ? true : false;
139 $default_fields[ $field_slug ]['priority'] = ( $key + 1 ) * 10;
140 // Widget defined fields are local. third party plugins's fields are not.
141 $default_fields[ $field_slug ]['local'] = true;
142
143 // Append postal code autocomplete class.
144 if (
145 array_key_exists( 'state_lookup_by_postcode', $settings )
146 && 'yes' === $settings['state_lookup_by_postcode']
147 && ( 'billing_postcode' === $field_slug || 'shipping_postcode' === $field_slug )
148 ) {
149 $default_fields[ $field_slug ]['class'][] = 'post_code_autocomplete';
150 }
151
152 // IF not custom field, go next.
153 if ( false === $is_custom ) {
154 continue;
155 }
156
157 $default_fields = $this->custom_field_setup( $field, $type, $field_slug, $default_fields );
158 }
159
160 foreach ( $default_fields as $key => $details ) {
161 if ( ! array_key_exists( 'local', $details ) || false === $details['local'] ) {
162 $default_fields[ $key ]['priority'] = 500;
163 }
164 }
165
166 return $default_fields;
167 }
168
169 /**
170 * Setup custom field options and assign required things to custom fields.
171 * also helps to reduce assign_settings_per_field method complexity.
172 *
173 * @param array $field html string of checkout fields.
174 * @param string $type type of checkout fields.
175 * @param string $field_slug unique sluf per field.
176 * @param array $default_fields default checkout fields.
177 * @return array
178 * @since 1.1.0
179 */
180 private function custom_field_setup( $field, $type, $field_slug, $default_fields ) {
181 $tag = $field[ $type . '_custom_type' ];
182
183 // Set default options.
184 $default_fields[ $field_slug ]['class'][] = ( $field[ $type . '_width' ] ) ? $field[ $type . '_width' ] : 'w-100';
185 $default_fields[ $field_slug ]['type'] = ( $field[ $type . '_custom_type' ] ) ? $field[ $type . '_custom_type' ] : 'text';
186 $default_fields[ $field_slug ]['default'] = $field[ $type . '_custom_value' ];
187
188 // Convert select to multiselect.
189 if ( 'multiselect' === $tag ) {
190 $default_fields[ $field_slug ]['type'] = 'multiselect';
191 }
192
193 // Assign one extra class to style radio group wrapper.
194 if ( 'radio' === $tag ) {
195 $default_fields[ $field_slug ]['type'] = 'radio';
196 $default_fields[ $field_slug ]['class'][] = 'radio-group-wrapper';
197 $default_fields[ $field_slug ]['mode'] = $field[ $type . '_radio_field_mode' ];
198 }
199
200 // Check if checkbox must be checked on default.
201 if ( 'checkbox' === $tag ) {
202 $default_fields[ $field_slug ]['checked'] = $field[ $type . '_checkbox_custom_value' ];
203 }
204
205 // Assign options.
206 $tags = [ 'select', 'multiselect', 'radio' ];
207 if ( in_array( $tag, $tags, true ) ) {
208 $options = $this->convert_value_to_array( $field[ $type . '_custom_options' ] );
209
210 $default_fields[ $field_slug ]['options'] = $options;
211 }
212
213 return $default_fields;
214 }
215
216 /**
217 * Gets widget options string and convert it to array to be used for select / radio and etc.
218 *
219 * @param string $value string of options.
220 * @return array
221 * @since 1.1.0
222 */
223 private function convert_value_to_array( $value ) {
224 $array = [];
225 $values = preg_split( '/\r\n|\r|\n/', $value );
226
227 foreach ( $values as $option ) {
228 $split = explode( ':', $option );
229 $array[ $split[0] ] = $split[1];
230 }
231
232 return $array;
233 }
234
235 /**
236 * Is used to validate user defined custom fields after pressing place order button at checkout page.
237 * Validate both custom shipping and billing fields at once if exists.
238 *
239 * @uses sellkit_Core\Raven\Modules\Checkout\Classes\Global_Hooks::validate_user_defined_fields
240 * @param array $shipping_fields custom shipping fields.
241 * @param array $billing_fields custom billing fields.
242 * @return void
243 * @since 1.1.0
244 * @SuppressWarnings(PHPMD.CyclomaticComplexity)
245 */
246 public function validate_user_defined_fields( $shipping_fields, $billing_fields ) {
247 $shipping_destination = get_option( 'woocommerce_ship_to_destination', true );
248
249 foreach ( $shipping_fields as $data ) {
250 // Escape all if cart does not need shipping information.
251 if ( ! WC()->cart->needs_shipping() ) {
252 continue;
253 }
254
255 // Escape all if shipping destination be billing only.
256 if ( 'billing_only' === $shipping_destination ) {
257 continue;
258 }
259
260 $final_name = isset( $data['shipping_list_field'] ) ? $data['shipping_list_field'] : '';
261
262 if ( 'custom_role' === $final_name ) {
263 $final_name = 'shipping_' . $data['_id'];
264
265 if ( ! empty( $data['shipping_custom_id'] ) ) {
266 $id = $data['shipping_custom_id'];
267 $final_name = "shipping_$id";
268 }
269 }
270
271 // Get $name variable from label or placeholder and/or id to be used in validate error.
272 $label = $this->create_name_for_errors( $data, __( 'Shipping', 'sellkit' ), 'shipping', $final_name );
273
274 // Field value.
275 $value = filter_input( INPUT_POST, $final_name, FILTER_DEFAULT );
276
277 // #1. Required validation.
278 $is_required = ( ! empty( $data['shipping_list_required'] ) && 'yes' === $data['shipping_list_required'] ) ? true : false;
279
280 if ( true === $is_required && ( ! array_key_exists( $final_name, $_POST ) || empty( $value ) ) ) { // phpcs:ignore
281 /* translators: %s field_name. */
282 wc_add_notice( sprintf( __( '%s is a required field.', 'sellkit' ), '<strong>' . $label . '</strong>' ), 'error' );
283 }
284
285 // #2. Phone validation.
286 $this->phone_validation( $data, $final_name, 'shipping', $label );
287
288 // #3. Postcode validation.
289 $this->postcode_validation( $data, $final_name, 'shipping', $label );
290 }
291
292 foreach ( $billing_fields as $data ) {
293 $final_name = isset( $data['billing_list_field'] ) ? $data['billing_list_field'] : '';
294
295 if ( 'custom_role' !== $final_name ) {
296 continue;
297 }
298
299 $final_name = 'billing_' . $data['_id'];
300
301 if ( ! empty( $data['billing_custom_id'] ) ) {
302 $id = $data['billing_custom_id'];
303 $final_name = "billing_$id";
304 }
305
306 // Get $name variable from label or placeholder and/or id to be used in validate error.
307 $label = $this->create_name_for_errors( $data, __( 'Billing', 'sellkit' ), 'billing', $final_name );
308
309 // Field value.
310 $value = filter_input( INPUT_POST, $final_name, FILTER_DEFAULT );
311
312 // #1. Required validation.
313 $is_required = ( ! empty( $data['billing_list_required'] ) && 'yes' === $data['billing_list_required'] ) ? true : false;
314
315 if ( true === $is_required && empty( $value ) ) { // phpcs:ignore
316 /* translators: %s field_name. */
317 wc_add_notice( sprintf( __( '%s is a required field.', 'sellkit' ), '<strong>' . $label . '</strong>' ), 'error' );
318 }
319
320 // #2. phone validation.
321 $this->phone_validation( $data, $final_name, 'billing', $label );
322
323 // #3. Postcode validation.
324 $this->postcode_validation( $data, $final_name, 'billing', $label );
325 }
326
327 // Validate main checkout email.
328 $email = filter_input( INPUT_POST, 'billing_email', FILTER_SANITIZE_EMAIL );
329 $valid = filter_var( $email, FILTER_VALIDATE_EMAIL );
330
331 if ( ! $email ) {
332 /* translators: %s field_name. */
333 wc_add_notice( sprintf( __( '%s is a required field.', 'sellkit' ), '<strong>' . __( 'Email address', 'sellkit' ) . '</strong>' ), 'error' );
334 return;
335 }
336
337 if ( ! $valid ) {
338 /* translators: %s field_name. */
339 wc_add_notice( sprintf( __( '%s is not a valid email.', 'sellkit' ), '<strong>' . __( 'Email address', 'sellkit' ) . '</strong>' ), 'error' );
340 }
341 }
342
343 /**
344 * Create name for each field to be used in errors text.
345 *
346 * @param array $data field data.
347 * @param string $display_type shipping / billing with text-domain.
348 * @param string $type shipping / billing.
349 * @param string $final_name field key.
350 * @return string
351 * @since 1.1.0
352 */
353 private function create_name_for_errors( $data, $display_type, $type, $final_name ) {
354 $name = $data[ $type . '_list_placeholder' ];
355
356 if ( empty( $data[ $type . '_list_placeholder' ] ) ) {
357 $name = $data[ $type . '_list_label' ];
358 }
359
360 $label = $display_type . ' ' . $name;
361
362 if ( empty( $name ) ) {
363 $label = $final_name;
364 }
365
366 return $label;
367 }
368
369 /**
370 * Validate phone number using woocommerce way.
371 *
372 * @see woocommerce/includes/class-wc-validation.php
373 * @param array $data widget field data.
374 * @param string $final_name key of field in checkout form.
375 * @param string $type shipping/billing.
376 * @param string $label field label for error.
377 * @return boolean
378 * @since 1.1.0
379 */
380 private function phone_validation( $data, $final_name, $type, $label ) {
381 if ( ! array_key_exists( $type . '_list_validation', $data ) || 'phone' !== $data[ $type . '_list_validation' ] ) {
382 return true;
383 }
384
385 $phone = filter_input( INPUT_POST, $final_name, FILTER_DEFAULT );
386 $valid = \WC_Validation::is_phone( $phone );
387
388 if ( ! $valid ) {
389 /* translators: %s field_name. */
390 wc_add_notice( sprintf( __( '%s is not a valid phone.', 'sellkit' ), '<strong>' . $label . '</strong>' ), 'error' );
391 }
392 }
393
394 /**
395 * Validate postcode using woocommerce way.
396 *
397 * @param array $data field data.
398 * @param string $final_name field key in checkout form.
399 * @param string $type shipping / billing.
400 * @param string $label field label to be used in error text.
401 * @return void
402 * @since 1.1.0
403 */
404 private function postcode_validation( $data, $final_name, $type, $label ) {
405 if ( ! array_key_exists( $type . '_list_validation', $data ) || 'postcode' !== $data[ $type . '_list_validation' ] ) {
406 return;
407 }
408
409 $postcode = filter_input( INPUT_POST, $final_name, FILTER_DEFAULT );
410 $country = filter_input( INPUT_POST, $type . '_country' );
411 $postcode = wc_format_postcode( $postcode, $country );
412 $valid = \WC_Validation::is_postcode( $postcode, $country );
413
414 if ( ! $valid ) {
415 /* translators: %s field_name. */
416 wc_add_notice( sprintf( __( '%s is not a valid postcode.', 'sellkit' ), '<strong>' . $label . '</strong>' ), 'error' );
417 }
418 }
419
420 /**
421 * Is used to save user defined custom fields in database for the current order id.
422 * save both billing and shipping custom fields at once if exists.
423 *
424 * @uses sellkit_Core\Raven\Modules\Checkout\Classes\Global_Hooks::save_user_defined_fields
425 * @param array $shipping_fields custom shipping fields.
426 * @param array $billing_fields custom billing fields.
427 * @param int $order_id order id.
428 * @return void
429 * @since 1.1.0
430 */
431 public function save_user_defined_fields( $shipping_fields, $billing_fields, $order_id ) {
432 // We store saved fields in this array and save keys as a meta for this order, to use it later.
433 $saved_fields = [];
434
435 foreach ( $shipping_fields as $field ) {
436 if ( empty( $field['shipping_custom_id'] ) ) {
437 continue;
438 }
439
440 $item = $this->prepare_custom_fields_to_save( $field, 'shipping' );
441 $final_name = $item['key_name'];
442
443 // Field value.
444 $value = sellkit_htmlspecialchars( INPUT_POST, $final_name );
445 if ( 'multiselect' === $field['shipping_custom_type'] ) {
446 $value = filter_input( INPUT_POST, $final_name, FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );
447 }
448
449 // Some user defined field might be not required ( & empty ). so again we check if field is has value save it.
450 if ( ! empty( $value ) ) { // phpcs:ignore
451 update_post_meta( $order_id, $final_name, sanitize_text_field( $value ) ); // phpcs:ignore
452 array_push( $saved_fields, $item );
453 }
454 }
455
456 foreach ( $billing_fields as $field ) {
457 if ( empty( $field['billing_custom_id'] ) ) {
458 continue;
459 }
460
461 $item = $this->prepare_custom_fields_to_save( $field, 'billing' );
462 $final_name = $item['key_name'];
463
464 // Field value.
465 $value = sellkit_htmlspecialchars( INPUT_POST, $final_name );
466 if ( 'multiselect' === $field['billing_custom_type'] ) {
467 $value = filter_input( INPUT_POST, $final_name, FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );
468 }
469
470 // Some user defined field might be not required ( & empty ). so again we check if field has value save it.
471 if ( ! empty( $value ) ) { // phpcs:ignore
472 update_post_meta( $order_id, $final_name, sanitize_text_field( $value ) ); // phpcs:ignore
473 array_push( $saved_fields, $item );
474 }
475 }
476
477 // Save id of those custom fields that are validate and has value as an meta for order to be used later.
478 if ( count( $saved_fields ) > 0 ) {
479 update_post_meta( $order_id, 'sellkit_checkout_widget_custom_field_of_order', $saved_fields );
480 }
481 }
482
483 /**
484 * The way to save custom fields names as array for order as meta to be used later.
485 *
486 * @param array $data sent data from checkout.
487 * @param string $type shippin/billing.
488 * @return array
489 * @since 1.1.0
490 */
491 private function prepare_custom_fields_to_save( $data, $type ) {
492 $id = $data[ $type . '_custom_id' ];
493 $final_name = $type . '_' . $id;
494 $item = [
495 'show_in_thank_you' => ( 'yes' === $data[ $type . '_show_in_thankyou' ] ) ? 'yes' : 'no',
496 'show_in_email' => ( 'yes' === $data[ $type . '_show_in_order_mail' ] ) ? 'yes' : 'no',
497 'key_name' => $final_name,
498 'label' => $data[ $type . '_list_placeholder' ],
499 ];
500
501 return $item;
502 }
503
504 /**
505 * Convert required fields to optional based on widget options.
506 * will be called after clicking place order button.
507 *
508 * @uses sellkit_Core\Raven\Modules\Checkout\Classes\Global_Hooks::validate_user_defined_fields
509 * @param array $widget_shipping_fields user defined fields in widget.
510 * @param array $widget_billing_fields user defined fields in widget.
511 * @return void
512 * @since 1.1.0
513 */
514 public function make_sure_to_convert_required_field_to_optional( $widget_shipping_fields, $widget_billing_fields ) {
515 add_filter( 'woocommerce_checkout_fields', function( $default_fields ) use ( $widget_shipping_fields, $widget_billing_fields ) {
516 // Make phone field optional at beginning.
517 $default_fields['billing']['billing_phone']['required'] = false;
518 unset( $default_fields['billing']['billing_email'] );
519
520 // Make it optional.
521 foreach ( $widget_billing_fields as $data ) {
522 $slug = isset( $data['billing_list_field'] ) ? $data['billing_list_field'] : '';
523 $is_required = false;
524
525 if ( 'custom_role' === $slug ) {
526 continue;
527 }
528
529 if ( ! empty( $data['billing_list_required'] ) && 'yes' === $data['billing_list_required'] ) {
530 $is_required = true;
531 }
532
533 $default_fields['billing'][ $slug ]['required'] = $is_required;
534 }
535
536 foreach ( $widget_shipping_fields as $data ) {
537 $slug = isset( $data['shipping_list_field'] ) ? $data['shipping_list_field'] : '';
538 $is_required = false;
539
540 if ( 'custom_role' === $slug ) {
541 continue;
542 }
543
544 if ( ! empty( $data['shipping_list_required'] ) && 'yes' === $data['shipping_list_required'] ) {
545 $is_required = true;
546 }
547
548 $default_fields['shipping'][ $slug ]['required'] = $is_required;
549 }
550
551 return $default_fields;
552 } );
553 }
554
555 /**
556 * Retrieve required widget settings of current checkout widget.
557 *
558 * @param int $post_id page id.
559 * @param string $form_id form id.
560 * @return array
561 * @since 1.1.0
562 */
563 public function retrieve_checkout_widget_settings( $post_id, $form_id ) {
564 $form_meta = Elementor::$instance->documents->get( $post_id )->get_elements_data();
565 $form = self::find_element_recursive( $form_meta, $form_id );
566
567 if ( ! is_array( $form ) || ! array_key_exists( 'settings', $form ) ) {
568 return [];
569 }
570
571 $settings = $form['settings'];
572
573 return $settings;
574 }
575
576 /**
577 * Find elementor element.
578 * Code block copied from sellkit-core directly.
579 *
580 * @param array $elements elements of elementor.
581 * @param string $form_id elementor form id.
582 * @return array
583 * @since 1.1.0
584 */
585 public static function find_element_recursive( $elements, $form_id ) {
586 foreach ( $elements as $element ) {
587 if ( $form_id === $element['id'] ) {
588 return $element;
589 }
590
591 if ( ! empty( $element['elements'] ) ) {
592 $element = self::find_element_recursive( $element['elements'], $form_id );
593
594 if ( $element ) {
595 return $element;
596 }
597 }
598 }
599
600 return false;
601 }
602
603 /**
604 * Hide checkout order product quantity input and show raw quantity.
605 *
606 * @param string $input_html default quantity input.
607 * @param int $quantity product quantity in cart.
608 * @since 1.1.0
609 * @return void
610 *
611 * @SuppressWarnings(PHPMD.UnusedFormalParameter)
612 */
613 public function checkout_order_hidden_quantity( $input_html, $quantity ) {
614 echo sprintf(
615 /** Translators: %s: product quantity */
616 '<strong class="product-quantity"> <i class="fa fa-times" aria-hidden="true"></i>%s</strong>',
617 esc_html( $quantity )
618 );
619 }
620
621 /**
622 * Calculate item discount.
623 *
624 * @param int $id product id.
625 * @param string $type discount type.
626 * @param int $value discount value.
627 * @return int|boolean
628 * @since 1.2.8
629 */
630 public static function calculate_discount( $id, $type, $value ) {
631 if ( false === $type && false === $value ) {
632 return false;
633 }
634
635 $product = wc_get_product( $id );
636 $regular = $product->get_regular_price();
637 $sale = $product->get_sale_price();
638 $price = false;
639
640 if ( strpos( $type, 'sale' ) !== false ) {
641 $discount = ( 'fixed-sale' === $type ) ? floatval( $value ) : ( floatval( $sale ) * floatval( $value ) ) / 100;
642 $discount = floatval( $sale ) - $discount;
643
644 return ( $discount > 0 ) ? $discount : 0;
645 }
646
647 if ( strpos( $type, 'sale' ) === false ) {
648 $discount = ( 'fixed' === $type ) ? floatval( $value ) : ( floatval( $regular ) * floatval( $value ) ) / 100;
649 $discount = floatval( $regular ) - $discount;
650
651 return ( $discount > 0 ) ? $discount : 0;
652 }
653
654 return $price;
655 }
656
657 /**
658 * Add extra js in editor mode.
659 *
660 * @since 1.1.0
661 * @return void
662 */
663 public function editor_mode_extra_js() {
664 ?>
665 <script>
666 jQuery( document ).on( 'mousemove', function() {
667 $( '.sellkit-coupon-toggle' ).off( 'click' ).on( 'click', function() {
668 let direction = 'row';
669 const status = $( '.sellkit-custom-coupon-form' ).css( 'display' );
670 let displayValue = '';
671
672 if ( $( window ).width() < 600 ) {
673 direction = 'column';
674 }
675
676 if ( 'none' === status ) {
677 displayValue = 'inline-flex';
678 } else {
679 displayValue = 'none';
680 }
681
682 $( '.sellkit-custom-coupon-form' ).css( {
683 display: displayValue,
684 flexDirection: direction,
685 } );
686 } );
687 } );
688 </script>
689 <?php
690 }
691
692 /**
693 * Assigning checkout ajax default shipping fields after ajax is sent.
694 *
695 * @param array $post post request.
696 * @param array $clear checkout form data.
697 * @return array
698 * @since 1.2.8
699 */
700 public function assigning_default_ajax_shipping_fields( $post, $clear ) {
701 if ( array_key_exists( 'billing_state', $clear ) ) {
702 $post['state'] = $clear['billing_state'];
703 }
704
705 if ( array_key_exists( 'shipping_country', $clear ) ) {
706 $post['s_country'] = $clear['shipping_country'];
707 }
708
709 if ( array_key_exists( 'shipping_state', $clear ) ) {
710 $post['s_state'] = $clear['shipping_state'];
711 }
712
713 if ( array_key_exists( 'shipping_postcode', $clear ) ) {
714 $post['s_postcode'] = $clear['shipping_postcode'];
715 }
716
717 if ( array_key_exists( 'shipping_city', $clear ) ) {
718 $post['s_city'] = $clear['shipping_city'];
719 }
720
721 if ( array_key_exists( 'shipping_address_1', $clear ) ) {
722 $post['s_address'] = $clear['shipping_address_1'];
723 }
724
725 if ( array_key_exists( 'shipping_address_2', $clear ) ) {
726 $post['s_address_2'] = $clear['shipping_address_2'];
727 }
728
729 return $post;
730 }
731
732 /**
733 * Check if product is in cart.
734 *
735 * @param int $product_id product id.
736 * @since 1.7.4
737 */
738 public function is_product_in_cart( $product_id ) {
739 // Get the WooCommerce cart.
740 $cart = WC()->cart;
741
742 foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
743 // Get the product ID for each cart item.
744 $item_product_id = $cart_item['product_id'];
745
746 // Check if the product ID matches the provided product ID.
747 if ( $item_product_id === $product_id ) {
748 return true;
749 }
750 }
751
752 return false;
753 }
754 }
755