PluginProbe
SellKit – Funnel builder and checkout optimizer for WooCommerce to sell more, faster / 1.5.9
SellKit – Funnel builder and checkout optimizer for WooCommerce to sell more, faster v1.5.9
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 / local-hooks.php

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

1,002 lines 29.8 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\{ Helper, Global_Hooks };
8 use Elementor\Plugin as Elementor;
9
10 /**
11 * Local hooks.
12 * Applies before widget.
13 *
14 * @SuppressWarnings(PHPMD.UnusedFormalParameter)
15 * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
16 * @SuppressWarnings(PHPMD.TooManyMethods)
17 * @SuppressWarnings(PHPMD.NPathComplexity)
18 * @since 1.1.0
19 */
20 class Local_Hooks {
21 /**
22 * Create instance of class without construct.
23 *
24 * @since 1.1.0
25 * @return object
26 */
27 public static function instance() {
28 $class = new \ReflectionClass( __CLASS__ );
29 return $class->newInstanceWithoutConstructor();
30 }
31
32 /**
33 * Class construct.
34 *
35 * @param array $settings widget settings.
36 * @param array $widget widget object.
37 * @since 1.1.0
38 */
39 public function __construct( $settings, $widget ) {
40 $this->settings = $settings;
41 $this->widget = $widget;
42 $this->actions();
43 }
44
45 /**
46 * Actions.
47 * required actions to apply changes to woocommerce checkout shortcode.
48 *
49 * @return void
50 * @since 1.1.0
51 */
52 private function actions() {
53 // sellkit wrapper for checkout widget.
54 add_action( 'woocommerce_before_checkout_form', [ $this, 'open_multistep_wrap' ] );
55 add_action( 'woocommerce_after_checkout_form', [ $this, 'close_multistep_wrap' ], 999 );
56
57 // Add express section to widget.
58 $this->add_express_checkout();
59
60 // Replace Woocommerce templates that require huge changes.
61 add_filter( 'woocommerce_locate_template', [ $this, 'template_replace' ], 1, 3 );
62
63 // Remove coupon from it's default location. will add custom coupon form based on design at desired location.
64 remove_action( 'woocommerce_before_checkout_form', 'woocommerce_checkout_coupon_form', 10, 1 );
65
66 // Filter all woocommerce field right before printing them in our widget.
67 add_filter( 'woocommerce_checkout_fields', [ $this, 'woocommerce_checkout_fields' ] );
68
69 // Hide shipping fields section title.
70 add_filter( 'sellkit-checkout-disable-shipping-fields-title', [ $this, 'check_to_disable_shipping_title' ] );
71
72 // Customize shipping fields based on user desire.
73 add_action( 'sellkit_checkout_shipping_fields', [ $this, 'sellkit_checkout_shipping_field' ], 10, 2 );
74
75 // Customize billing fields based on user desire.
76 add_action( 'sellkit_checkout_billing_fields', [ $this, 'sellkit_checkout_billing_field' ], 10, 2 );
77
78 // Rename Shipping text to Shipping Method.
79 add_filter( 'woocommerce_shipping_package_name', [ $this, 'rename_shipping_text' ] );
80
81 // Remove login form from default location.
82 remove_action( 'woocommerce_before_checkout_form', 'woocommerce_checkout_login_form', 10 );
83
84 // Append widget settings to checkout form 2 hidden fields form_id post_id.
85 add_action( 'woocommerce_checkout_before_customer_details', [ $this, 'widget_settings' ] );
86
87 // Apply custom messages.
88 $this->custom_messages();
89
90 // Enable or Disable Sections based on user selection.
91 add_action( 'woocommerce_before_checkout_form', function() {
92 self::enable_disable_sections( $this->settings, [] );
93 } );
94
95 // Inject required scripts for google address autocomplete.
96 add_action( 'sellkit-after-checkout-content', [ $this, 'inject_google_autocomplete' ] );
97
98 // Order bump html.
99 add_action( 'woocommerce_before_checkout_form', [ $this, 'order_bump' ] );
100
101 // Bundle products.
102 $this->bundled_products();
103 }
104
105 /**
106 * Opens a wrapper around widget checkout form.
107 *
108 * @return void
109 * @since 1.1.0
110 */
111 public function open_multistep_wrap() {
112 ?>
113 <div id="sellkit-checkout-widget-id" class="sellkit-multistep-checkout-wrap sellkit-mobile-design-checkout-widget">
114 <?php
115 }
116
117 /**
118 * Close opened wrapper around checkout form.
119 *
120 * @return void
121 * @since 1.1.0
122 */
123 public function close_multistep_wrap() {
124 echo '</div>';
125 }
126
127 /**
128 * Inject express checkout section into the checkout form based on layout.
129 *
130 * @return void
131 * @since 1.1.0
132 */
133 private function add_express_checkout() {
134 if ( ! sellkit()->has_pro ) {
135 return;
136 }
137
138 $show_express = true;
139
140 // Disable express checkout.
141 if ( 'yes' !== $this->settings['show_express_checkout'] ) {
142 $show_express = false;
143 }
144
145 $gateways = [
146 'Paypal_For_Woocommerce',
147 'Woo_Payment_Gateway',
148 'Stripe_For_Woocommerce',
149 'Klarma_Checkout_Woocommerce',
150 'Amazon_Pay_Woocommerce',
151 'Stripe_Woocommerce_Official',
152 ];
153
154 foreach ( $gateways as $gateway ) {
155 $class = 'Sellkit\Elementor\Modules\Checkout\Integrations\\' . $gateway;
156 $class = new $class();
157 $class->run();
158 }
159
160 if ( false === $show_express ) {
161 return;
162 }
163
164 if ( 'one-page' === $this->settings['layout-type'] ) {
165 add_action( 'sellkit_checkout_one_page_express_methods', [ $this, 'express_checkout_html' ] );
166 return;
167 }
168
169 add_action( 'sellkit-checkout-step-a-begins', [ $this, 'express_checkout_html' ], 20 );
170 }
171
172 /**
173 * Replace Woocommerce templates that needs to be changed, locally.
174 * this template_replace does not affect default checkout page.
175 *
176 * @param string $template template name.
177 * @param string $template_name name.
178 * @param string $template_path path of template.
179 * @return string
180 * @since 1.1.0
181 */
182 public function template_replace( $template, $template_name, $template_path ) {
183 $basename = basename( $template );
184 $our_path = sellkit()->plugin_dir() . 'includes/elementor/modules/checkout/';
185
186 switch ( $basename ) {
187 case 'form-checkout.php':
188 $template = $our_path . 'templates/form-checkout.php';
189 break;
190 case 'form-login.php':
191 $template = $our_path . 'templates/form-login.php';
192 break;
193 case 'form-shipping.php':
194 $template = $our_path . 'templates/form-shipping.php';
195 break;
196 case 'form-billing.php':
197 $template = $our_path . 'templates/form-billing.php';
198 break;
199 case 'payment.php':
200 $template = $our_path . 'templates/payment.php';
201 break;
202 case 'payment-method.php':
203 $template = $our_path . 'templates/payment-method.php';
204 break;
205 case 'review-order.php':
206 $template = $our_path . 'templates/review-order.php';
207 break;
208 case 'cart-shipping.php':
209 $template = $our_path . 'templates/cart-shipping.php';
210 break;
211 case 'cart-item-data.php':
212 $template = $our_path . 'templates/cart-item-data.php';
213 break;
214 case 'terms.php':
215 $template = $our_path . 'templates/terms.php';
216 break;
217 }
218
219 return $template;
220 }
221
222 /**
223 * Customize shipping fields parameters based on user needs through widget options.
224 *
225 * @param array $default_fields woocommerce fields.
226 * @return array
227 * @since 1.1.0
228 */
229 public function customize_shipping_field( $default_fields ) {
230 $widget_shipping_fields = $this->settings['shipping_list'];
231 $widget_field_slug = Helper::instance()->get_user_defined_fields_slug( $widget_shipping_fields, 'shipping_list_field' );
232
233 // Unset default fields.
234 foreach ( $default_fields as $key => $field ) {
235 if ( ! in_array( $key, $widget_field_slug, true ) ) {
236 unset( $default_fields[ $key ] );
237 }
238 }
239
240 return $default_fields;
241 }
242
243 /**
244 * Check to disable shipping fields section title.
245 *
246 * @since 1.2.1
247 */
248 public function check_to_disable_shipping_title() {
249 $widget_shipping_fields = $this->settings['shipping_list'];
250
251 if ( 0 === count( $widget_shipping_fields ) ) {
252 return false;
253 }
254
255 return true;
256 }
257
258 /**
259 * Print shipping field in frontend using our customized fields.
260 *
261 * @param array $fields : shipping fields.
262 * @param object $checkout : checkout object.
263 * @since 1.1.0
264 */
265 public function sellkit_checkout_shipping_field( $fields, $checkout ) {
266 $default_text = [
267 'shipping_first_name',
268 'shipping_last_name',
269 'shipping_company',
270 'shipping_address_1',
271 'shipping_address_2',
272 'shipping_postcode',
273 'shipping_city',
274 ];
275
276 $default_select = [
277 'shipping_country',
278 'shipping_state',
279 ];
280
281 foreach ( $fields as $key => $details ) {
282 if ( in_array( $key, $default_text, true ) ) {
283 $fields[ $key ]['type'] = 'text';
284 }
285
286 if ( in_array( $key, $default_select, true ) ) {
287 $fields[ $key ]['type'] = 'select';
288 }
289 }
290
291 $widget_shipping_fields = $this->settings['shipping_list'];
292 $default_fields = Helper::instance()->assign_settings_per_field( $fields, $widget_shipping_fields, 'shipping', $this->settings );
293
294 $priority = array_column( $default_fields, 'priority' );
295 array_multisort( $priority, SORT_ASC, $default_fields );
296
297 foreach ( $default_fields as $key => $details ) {
298 if ( ! array_key_exists( 'type', $details ) ) {
299 continue;
300 }
301
302 $class = $details['type'];
303 $class = '\Sellkit\Elementor\Modules\Checkout\Fields\\' . ucfirst( $class );
304 $class = new $class();
305 $field = '';
306
307 $class->final_html_structure( $field, $details, $key );
308 }
309 }
310
311 /**
312 * Customize billing fields parameters based on user needs through widget options.
313 *
314 * @param array $default_fields woocommerce fields.
315 * @return array
316 * @since 1.1.0
317 */
318 public function customize_billing_field( $default_fields ) {
319 $widget_billing_fields = $this->settings['billing_list'];
320 $widget_field_slug = Helper::instance()->get_user_defined_fields_slug( $widget_billing_fields, 'billing_list_field' );
321
322 // Unset default fields.
323 foreach ( $default_fields as $key => $field ) {
324 if ( ! in_array( $key, $widget_field_slug, true ) && 'billing_email' !== $field ) {
325 unset( $default_fields[ $key ] );
326 }
327 }
328
329 return $default_fields;
330 }
331
332 /**
333 * Print billing fields in frontend using our customized fields.
334 *
335 * @param array $fields : billing fields.
336 * @param object $checkout : checkout object.
337 * @since 1.1.0
338 */
339 public function sellkit_checkout_billing_field( $fields, $checkout ) {
340 $default_text = [
341 'billing_first_name',
342 'billing_last_name',
343 'billing_company',
344 'billing_address_1',
345 'billing_address_2',
346 'billing_postcode',
347 'billing_city',
348 ];
349
350 $default_select = [
351 'billing_country',
352 'billing_state',
353 ];
354
355 $default_tel = [
356 'billing_phone',
357 ];
358
359 foreach ( $fields as $key => $details ) {
360 if ( in_array( $key, $default_text, true ) ) {
361 $fields[ $key ]['type'] = 'text';
362 }
363
364 if ( in_array( $key, $default_select, true ) ) {
365 $fields[ $key ]['type'] = 'select';
366 }
367
368 if ( in_array( $key, $default_tel, true ) ) {
369 $fields[ $key ]['type'] = 'tel';
370 }
371 }
372
373 $widget_billing_fields = $this->settings['billing_list'];
374 $default_fields = Helper::instance()->assign_settings_per_field( $fields, $widget_billing_fields, 'billing', $this->settings );
375
376 $priority = array_column( $default_fields, 'priority' );
377 array_multisort( $priority, SORT_ASC, $default_fields );
378
379 foreach ( $default_fields as $key => $details ) {
380 // Never shot field that it's type is not defined.
381 if ( ! array_key_exists( 'type', $details ) ) {
382 continue;
383 }
384
385 // Billing email is already defined at top of page.
386 if ( 'billing_email' === $key ) {
387 continue;
388 }
389
390 $class = $details['type'];
391 $class = '\Sellkit\Elementor\Modules\Checkout\Fields\\' . ucfirst( $class );
392 $class = new $class();
393 $field = '';
394
395 $field = $class->final_html_structure( $field, $details, $key );
396 }
397 }
398
399 /**
400 * Hook to fields before shortcode.
401 *
402 * @param array $default_fields woocommerce fields.
403 * @return array
404 * @since 1.1.0
405 */
406 public function woocommerce_checkout_fields( $default_fields ) {
407 $widget_billing_fields = $this->settings['billing_list'];
408 $widget_shipping_fields = $this->settings['shipping_list'];
409
410 // Unset fields.
411 $default_shipping_fields = $default_fields['shipping'];
412 $default_fields['shipping'] = $this->customize_shipping_field( $default_shipping_fields );
413
414 // Unset fields.
415 $default_billing_fields = $default_fields['billing'];
416 $default_fields['billing'] = $this->customize_billing_field( $default_billing_fields );
417
418 foreach ( $widget_billing_fields as $data ) {
419 $slug = $data['billing_list_field'];
420
421 if ( 'yes' !== $data['billing_list_required'] && array_key_exists( $slug, $default_fields['billing'] ) ) {
422 $default_fields['billing'][ $slug ]['required'] = false;
423 unset( $default_fields['billing'][ $slug ]['required'] );
424 }
425 }
426
427 foreach ( $widget_shipping_fields as $data ) {
428 $slug = $data['shipping_list_field'];
429
430 if ( 'yes' !== $data['shipping_list_required'] && array_key_exists( $slug, $default_fields['shipping'] ) ) {
431 $default_fields['shipping'][ $slug ]['required'] = false;
432 unset( $default_fields['shipping'][ $slug ]['required'] );
433 }
434 }
435
436 return $default_fields;
437 }
438
439 /**
440 * Rename Shipping text
441 *
442 * @param string $name title of shipping methods.
443 * @return string
444 * @since 1.1.0
445 */
446 public function rename_shipping_text( $name ) {
447 return '<h4 id="shipping_header_title" class="shipping-method-header heading">' . __( 'Shipping Methods', 'sellkit' ) . '</h4>';
448 }
449
450 /**
451 * Adds widget settings as hidden input to checkout form, to be used in various places.
452 *
453 * @return void
454 * @since 1.1.0
455 */
456 public function widget_settings() {
457 ?>
458 <input type="hidden" name="post_id" value="<?php echo esc_attr( self::get_current_post_id() ); ?>" />
459 <input type="hidden" name="form_id" value="<?php echo esc_attr( $this->widget->get_id() ); ?>" />
460 <?php
461 }
462
463 /**
464 * Get post ID based on document.
465 *
466 * @since 1.1.0
467 */
468 public static function get_current_post_id() {
469 if ( isset( Elementor::$instance->documents ) && ! empty( Elementor::$instance->documents->get_current() ) ) {
470 return Elementor::$instance->documents->get_current()->get_main_id();
471 }
472
473 return get_the_ID();
474 }
475
476 /**
477 * Express checkout html.
478 *
479 * @return void
480 * @since 1.1.0
481 */
482 public function express_checkout_html() {
483 ob_start();
484 ?>
485 <section class="sellkit-checkout-widget-express-checkout sellkit-checkout-express-checkout-step-1">
486 <fieldset class="express-box sellkit-checkout-widget-divider">
487 <legend class="sellkit-express-checkout-legend heading">
488 <?php echo __( 'Express Checkout', 'sellkit' ); ?>
489 </legend>
490 <div class="express-methods">
491 <?php do_action( 'sellkit-checkout-widget-express-methods' ); ?>
492 </div>
493 </fieldset>
494 </section>
495 <section class="sellkit-checkout-widget-express-checkout sellkit-checkout-express-checkout-step-2">
496 <fieldset id="sellkit-checkout-or-divider" class="divider-box sellkit-checkout-widget-divider">
497 <legend class="heading"><?php echo __( 'OR', 'sellkit' ); ?></legend>
498 </fieldset>
499 </section>
500 <?php
501 $express = ob_get_clean();
502 $express = apply_filters( 'sellkit-checkout-widget-express-checkout', $express );
503 echo $express;
504 }
505
506 /**
507 * Apply custom Messages.
508 *
509 * @return void
510 * @since 1.1.0
511 */
512 private function custom_messages() {
513 add_filter( 'sellkit_core/widgets/checkout/custom_message/already_have_account_text', function() {
514 return $this->settings['already_have_account_text'];
515 } );
516
517 add_filter( 'sellkit_core/widgets/checkout/custom_message/login_toggle_text', function() {
518 return $this->settings['login_toggle_text'];
519 } );
520
521 add_action( 'sellkit_core/widgets/checkout/custom_message/create_website_account', function() {
522 $site = get_bloginfo( 'name' );
523 $text = $this->settings['create_website_account'];
524
525 echo str_replace( '{{website}}', $site, $text );
526 } );
527
528 add_filter( 'sellkit_core/widgets/checkout/custom_message/secure_transaction_text', function() {
529 return $this->settings['secure_transaction_text'];
530 } );
531
532 add_filter( 'sellkit_core/widgets/checkout/custom_message/select_address_text', function() {
533 return $this->settings['select_address_text'];
534 } );
535
536 add_filter( 'sellkit-checkout-place-order-btn-text', function( $default ) {
537 if ( ! empty( $this->settings['place_order_btn_txt'] ) ) {
538 return $this->settings['place_order_btn_txt'];
539 }
540
541 return $default;
542 }, 10 );
543 }
544
545 /**
546 * Enable or disable some of checkout sections.
547 *
548 * @param array $settings widget settings.
549 * @param array $posted_data checkout form data.
550 * @return void
551 * @since 1.1.0
552 */
553 public static function enable_disable_sections( $settings, $posted_data = [] ) {
554 if ( Elementor::$instance->editor->is_edit_mode() || array_key_exists( 'sellkit-elementor-editor-mode', $posted_data ) ) {
555
556 add_action( 'sellkit-checkout-after-coupon-form-ajax', [ Helper::instance(), 'editor_mode_extra_js' ] );
557
558 // Let coupon form to be viewable in editor mode.
559 add_action( 'sellkit-checkout-widget-custom-coupon-form', function() use ( $settings ) {
560 Global_Hooks::instance()->coupon_form( $settings );
561 } );
562
563 return;
564 }
565
566 if ( wp_doing_ajax() ) {
567 // Hide order item images.
568 add_filter( 'sellkit/includes/elementor/modules/checkout/product-image', function( $img_html ) use ( $settings ) {
569 if ( ! array_key_exists( 'order_summary_show_image', $settings ) ) {
570 return $img_html;
571 }
572
573 return '';
574 } );
575
576 add_filter( 'sellkit-checkout-cart-item', function( $cart_item ) use ( $settings ) {
577 if ( ! array_key_exists( 'show_cart_items', $settings ) ) {
578 return $cart_item;
579 }
580
581 return '';
582 } );
583
584 // Disable order item quantity input.
585 if ( array_key_exists( 'show_cart_edit', $settings ) || array_key_exists( 'bundle-products-force', $posted_data ) ) {
586 add_action( 'sellkit-checkout-widget-disable-quantity', [ Helper::instance(), 'checkout_order_hidden_quantity' ], 10, 2 );
587 }
588
589 add_filter( 'woocommerce_shipping_package_name', function() {
590 return '<h4 id="shipping_header_title" class="shipping-method-header heading">' . esc_html__( 'Shipping Methods', 'sellkit' ) . '</h4>';
591 } );
592
593 add_filter( 'woocommerce_cart_ready_to_calc_shipping', function() use ( $settings ) {
594 if ( ! array_key_exists( 'show_shipping_method', $settings ) ) {
595 return true;
596 }
597
598 return false;
599 } );
600
601 add_action( 'sellkit-checkout-widget-custom-coupon-form', function() use ( $settings ) {
602 Global_Hooks::instance()->coupon_form( $settings );
603 } );
604
605 return;
606 }
607
608 // Normal mode when page is loading.
609 add_filter( 'woocommerce_cart_ready_to_calc_shipping', function() use ( $settings ) {
610 if ( 'yes' === $settings['show_shipping_method'] ) {
611 return true;
612 }
613
614 return false;
615 }, 10 );
616
617 add_filter( 'sellkit/includes/elementor/modules/checkout/product-image', function( $img_html ) use ( $settings ) {
618 if ( 'yes' === $settings['order_summary_show_image'] ) {
619 return $img_html;
620 }
621
622 return '';
623 } );
624
625 add_filter( 'sellkit-checkout-cart-item', function( $cart_item ) use ( $settings ) {
626 if ( 'yes' === $settings['show_cart_items'] ) {
627 return $cart_item;
628 }
629
630 return '';
631 }, 10 );
632
633 // Disable order item quantity input.
634 if ( array_key_exists( 'show_cart_edit', $settings ) ) {
635 add_action( 'sellkit-checkout-widget-disable-quantity', [ Helper::instance(), 'checkout_order_hidden_quantity' ], 10, 2 );
636
637 add_filter( 'sellkit/includes/elementor/modules/checkout/quanity/class', function( $classes ) {
638 return $classes .= ' sellkit-checkout-widget-d-block';
639 } );
640 }
641
642 add_filter( 'sellkit-checkout-place-order-btn-text', function( $place_order_btn ) {
643 if ( ! empty( $settings['place_order_btn_txt'] ) ) {
644 return $settings['place_order_btn_txt'];
645 }
646
647 return $place_order_btn;
648 }, 10 );
649
650 add_action( 'sellkit-checkout-widget-custom-coupon-form', function() use ( $settings ) {
651 if ( 'yes' !== $settings['show_coupon_field'] ) {
652 return;
653 }
654
655 self::coupon_form( $settings );
656 } );
657 }
658
659 /**
660 * Inject google autocomplete address script if enabled for shipping/billing section.
661 *
662 * @return void
663 * @since 1.1.0
664 */
665 public function inject_google_autocomplete() {
666 if ( ! sellkit()->has_pro ) {
667 return;
668 }
669
670 \Sellkit_Elementor_Checkout_Pro_Module::checkout_google_autocomplete_address( $this->settings );
671 }
672
673 /**
674 * Place custom coupon form in checkout order-review based design.
675 * ! we have used same form in Global_Hooks. but this one for first load of page.
676 *
677 * @param array $settings widget settings.
678 * @see sellkit_Core\Raven\Modules\Checkout\Classes\Global_Hooks::coupon_form.
679 * @return void
680 * @since 1.1.0
681 */
682 public static function coupon_form( $settings ) {
683 echo '<tr class="coupon-form border-none"><td colspan="2">';
684 self::form( $settings );
685 echo '</td></tr>';
686 }
687
688 /**
689 * New custom coupon form HTML.
690 *
691 * @param array $settings widget settings.
692 * @return void
693 * @since 1.1.0
694 */
695 public static function form( $settings ) {
696 $class = 'sellkit-custom-coupon-form-d-none';
697 if ( ! array_key_exists( 'coupon_field_type', $settings ) || 'normal' === $settings['coupon_field_type'] ) {
698 $class = 'sellkit-normal-coupon-form';
699 }
700 ?>
701 <?php if ( array_key_exists( 'coupon_field_type', $settings ) && 'collapsible' === $settings['coupon_field_type'] ) : ?>
702 <span id="copoun_toggle" class="copoun_toggle sellkit-coupon-toggle sellkit-checkout-widget-links">
703 <?php echo __( 'Have a coupon? Click here to enter your code', 'sellkit' ); ?>
704 </span>
705 <?php $class .= ' sellkit-checkout-collapsible'; ?>
706 <?php Helper::instance()->editor_mode_extra_js(); ?>
707 <?php endif; ?>
708 <div class="sellkit-custom-coupon-form <?php echo $class; ?>">
709 <p class="jx-form-row-first">
710 <input class="jx-coupon" type="text" placeholder="<?php esc_attr_e( 'Enter Promo code', 'sellkit' ); ?>" />
711 </p>
712
713 <p class="jx-form-row-last">
714 <span class="sellkit-checkout-widget-secondary-button jx-apply-coupon sellkit-apply-coupon" >
715 <?php esc_html_e( 'Apply', 'sellkit' ); ?>
716 </span>
717 </p>
718 </div>
719 <?php
720 }
721
722 /**
723 * Insert bundled product.
724 *
725 * @since 1.1.0
726 * @return void
727 */
728 public function bundled_products() {
729 global $wp_query;
730 $query = $wp_query->query_vars;
731 $option = 'default';
732
733 if ( ! array_key_exists( 'funnel_product_settings', $query ) ) {
734 return;
735 }
736
737 if ( ! empty( $query['funnel_product_settings'] ) ) {
738 $option = $query['funnel_product_settings'];
739 }
740
741 if ( 'default' === $option ) {
742 return;
743 }
744
745 add_action( 'sellkit_checkout_required_hidden_fields', function() use ( $option ) {
746 ?>
747 <input type="hidden" name="sellkit-bundle-products" value="<?php echo esc_attr( $option ); ?>" >
748 <?php
749 }, 10 );
750
751 self::bundle_product_action( $option );
752 }
753
754 /**
755 * Display bundle products.
756 *
757 * @param string $option bundle products type.
758 * @since 1.1.0
759 * return void
760 */
761 public static function bundle_product_action( $option ) {
762 add_action( 'sellkit-checkout-widget-disable-quantity', [ Helper::instance(), 'checkout_order_hidden_quantity' ], 10, 2 );
763
764 if ( 'force-products' === $option || Elementor::$instance->editor->is_edit_mode() ) {
765 return;
766 }
767
768 $fields_type = 'radio';
769 $products = WC()->cart->get_cart();
770 $default = null;
771 $default_q = null;
772 $readonly = 'readonly';
773
774 if ( 'allow-buyers' === $option ) {
775 $fields_type = 'checkbox';
776 $readonly = '';
777 }
778
779 ob_start();
780 ?>
781 <section class="sellkit-checkout-bundled-products">
782 <div class="sellkit-checkout-bundled-inner-wrap">
783 <span class="sellkit-checkout-bundled-header heading"><?php echo esc_html__( 'Your Products', 'sellkit' ); ?></span>
784 <table class="sellkit-checkout-bundled-products-table">
785 <thead>
786 <tr class="sellkit-checkout-bundled-products-head-row">
787 <th class="sellkit-head-row-title"><?php echo esc_html__( 'Product', 'sellkit' ); ?></th>
788 <th class="sellkit-head-row-quantity"><?php echo esc_html__( 'Quantity', 'sellkit' ); ?></th>
789 <th class="sellkit-head-row-price"><?php echo esc_html__( 'Price', 'sellkit' ); ?></th>
790 </tr>
791 </thead>
792 <tbody>
793 <?php foreach ( $products as $cart_item_key => $cart_item ) : ?>
794 <?php
795 $_product = apply_filters( 'woocommerce_cart_item_product', $cart_item['data'], $cart_item, $cart_item_key );
796 $default = $_product->get_id();
797 $default_q = $cart_item['quantity'];
798 $unique_id = 'bundle-unique-id-' . $default;
799 ?>
800 <tr class="sellkit-checkout-bundled-products-item">
801 <td class="sellkit-checkout-bundled-title">
802 <input
803 type="<?php echo esc_attr( $fields_type ); ?>"
804 value="<?php echo esc_attr( $_product->get_id() ); ?>"
805 name="sellkit-checkout-bundle-item"
806 class="sellkit-checkout-bundle-item"
807 id="<?php echo esc_attr( $unique_id ); ?>"
808 <?php echo ( array_key_last( $products ) === $cart_item_key ) ? 'checked' : ''; ?>
809 >
810 <label for="<?php echo esc_attr( $unique_id ); ?>">
811 <?php echo $_product->get_name(); ?>
812 </label>
813 </td>
814 <td class="sellkit-checkout-bundled-quantity">
815 <input type="number" <?php echo esc_attr( $readonly ); ?> min="1" value="<?php echo esc_attr( $cart_item['quantity'] ); ?>" data-id="<?php echo esc_attr( $cart_item_key ); ?>" class="sellkit-checkout-single-bundle-item-quantity" >
816 </td>
817 <td class="sellkit-checkout-bundled-price">
818 <?php echo apply_filters( 'woocommerce_cart_item_subtotal', WC()->cart->get_product_subtotal( $_product, $cart_item['quantity'] ), $cart_item, $cart_item_key ); ?>
819 </td>
820 <tr>
821 <?php if ( array_key_last( $products ) !== $cart_item_key ) : ?>
822 <tr>
823 <td colspan="3" class="sellkit-checkout-bundled-spacer-row">
824 <hr>
825 </td>
826 </tr>
827 <?php endif; ?>
828 <?php endforeach; ?>
829 </tbody>
830 </table>
831 </div>
832 </section>
833 <?php
834 $bundle_html = ob_get_clean();
835
836 add_action( 'sellkit-bundled-products-position', function() use ( $bundle_html ) {
837 echo $bundle_html;
838 } );
839
840 if ( ! wp_doing_ajax() ) {
841 WC()->cart->empty_cart();
842
843 if ( null !== $default ) {
844 WC()->cart->add_to_cart( $default, $default_q );
845
846 if ( ! WC()->cart->needs_shipping() ) {
847 wp_add_inline_script( 'sellkit-initialize-widgets', 'var sellkitCheckoutShipping = true', 'before' );
848 }
849 }
850
851 Global_Hooks::make_changes_after_cart_item_edit( get_the_id() );
852 }
853 }
854
855 /**
856 * Trigger to activate order bumb or not for this checkout.
857 *
858 * @param array $data checkout form data.
859 * @since 1.1.0
860 * @return void
861 */
862 public static function order_bump( $data = [] ) {
863 if ( 'woocommerce_before_checkout_form' === current_action() ) {
864 self::order_bump_frontend_manager();
865 return;
866 }
867 }
868
869 /**
870 * Order bump to manage frontend.
871 *
872 * @since 1.1.0
873 * @return void
874 */
875 private static function order_bump_frontend_manager() {
876 global $wp_query;
877 $query = $wp_query->query_vars;
878
879 if ( ! array_key_exists( 'bump_data', $query ) ) {
880 return;
881 }
882
883 $bumps = $query['bump_data'];
884
885 foreach ( $bumps as $bump ) {
886 if ( ! array_key_exists( 'products', $bump['data'] ) ) {
887 continue;
888 }
889
890 $design = $bump['data']['design'];
891 $products = $bump['data']['products'];
892
893 add_action( $design['sellkit_funnels_bump_position'], function() use ( $design, $products ) {
894 self::bump_html( $design, $products );
895 }, 5 );
896 }
897 }
898
899 /**
900 * Order bump html.
901 *
902 * @param array $design design properties.
903 * @param array $products products details.
904 * @since 1.1.0
905 * @return void
906 */
907 public static function bump_html( $design, $products ) {
908 $list = $products['list'];
909 $ids = [];
910
911 foreach ( $list as $id => $details ) {
912 $ids[] = $id;
913 $qty = $details['quantity'];
914 $discount = $details['discount'];
915 $type = $details['discountType'];
916 }
917
918 $ids_string = implode( '|', $ids );
919 $product = wc_get_product( $ids_string );
920 $qty = ( empty( $qty ) ) ? 1 : $qty;
921
922 if ( empty( $product ) || ! $product->get_id() ) {
923 return;
924 }
925
926 $unique_id = 'bump-title-' . $ids_string;
927
928 $class = '';
929 if (
930 'sellkit-checkout-before-order-summary' === current_action() ||
931 'sellkit-checkout-after-order-summary' === current_action()
932 ) {
933 $class = 'sellkit-bump-review-order';
934 }
935 ?>
936 <div class="sellkit-checkout-step-bump-wrapper <?php echo esc_attr( $class ); ?>" >
937 <div class="sellkit-checkout-bump-order-header">
938 <div class="sellkit-bump-order-left-header">
939 <img src="<?php echo esc_attr( sellkit()->plugin_assets_url() . 'img/right-arrow.svg' ); ?>" >
940 <input
941 type="checkbox"
942 value="<?php echo esc_attr( $ids_string ); ?>"
943 class="sellkit-checkout-bump-order-products"
944 data-qty="<?php echo esc_attr( $qty ); ?>"
945 name="sellkit_bump_data_<?php echo esc_attr( $ids_string ); ?>"
946 id="<?php echo esc_html( $unique_id ); ?>"
947 >
948 <label
949 for="<?php echo esc_attr( $unique_id ); ?>"
950 class="sellkit-checkout-order-bump-title"
951 >
952 <?php echo esc_html( $design['sellkit_funnels_bump_checkbox_label'] ); ?>
953 </label>
954 </div>
955 <div class="sellkit-bump-order-right-header">
956 <span class="sellkit-checkout-order-bump-price">
957 <?php
958 $discounted_price = Helper::calculate_discount( (int) $ids_string, $type, $discount );
959 $sale_price = $product->get_sale_price();
960 $regular_price = $product->get_regular_price();
961 $main_price = ( strpos( $type, 'sale' ) !== false ) ? $sale_price : $regular_price;
962
963 if ( floatval( $main_price ) > floatval( $discounted_price ) ) {
964 ?>
965 <del aria-hidden="true">
966 <span class="woocommerce-Price-amount amount">
967 <bdi>
968 <span class="woocommerce-Price-currencySymbol">
969 <?php echo wc_price( $main_price ); ?>
970 </span>
971 </bdi>
972 </span>
973 </del>
974 <bdi class="bump-price-bolded"><?php echo wc_price( $discounted_price ); ?></bdi>
975 <?php
976 } else {
977 ?>
978 <bdi><?php echo wc_price( $main_price ); ?></bdi>
979 <?php
980 }
981 ?>
982 </span>
983 </div>
984 </div>
985 <div class="sellkit-checkout-bump-order-body" >
986 <div class="sellkit-bump-order-left-body">
987 <?php $image = wp_get_attachment_image_src( $product->get_image_id() ); ?>
988 <?php if ( 'true' === $design['sellkit_funnels_bump_product_image'] && ! empty( $image[0] ) ) : ?>
989 <img src="<?php echo esc_attr( $image[0] ); ?>" >
990 <?php endif; ?>
991 </div>
992 <div class="sellkit-bump-order-right-body">
993 <div class="sellkit-bump-order-description">
994 <?php echo $design['sellkit_content']; ?>
995 </div>
996 </div>
997 </div>
998 </div>
999 <?php
1000 }
1001 }
1002