PluginProbe
SellKit – Funnel builder and checkout optimizer for WooCommerce to sell more, faster / 2.7.0
SellKit – Funnel builder and checkout optimizer for WooCommerce to sell more, faster v2.7.0
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
← All changes | includes/elementor/modules/checkout/classes/local-hooks.php +383 -146 1.1.42.7.0 View file →
@@ -6,8 +6,9 @@
6 6
7 7 use Sellkit\Elementor\Modules\Checkout\Classes\{ Helper, Global_Hooks };
8 8 use Elementor\Plugin as Elementor;
9 9 use Sellkit_Funnel;
10 +use Sellkit\Global_Checkout\Checkout;
10 11
11 12 /**
12 13 * Local hooks.
13 14 * Applies before widget.
@@ -15,12 +16,44 @@
15 16 * @SuppressWarnings(PHPMD.UnusedFormalParameter)
16 17 * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
17 18 * @SuppressWarnings(PHPMD.TooManyMethods)
18 19 * @SuppressWarnings(PHPMD.NPathComplexity)
20 + * @SuppressWarnings(PHPMD.CyclomaticComplexity)
19 21 * @since 1.1.0
20 22 */
21 23 class Local_Hooks {
22 24 /**
25 + * Checkout widget settings.
26 + *
27 + * @since 1.8.6
28 + * @var array
29 + */
30 + public $settings;
31 +
32 + /**
33 + * Checkout widget.
34 + *
35 + * @since 1.8.6
36 + * @var object
37 + */
38 + public $widget;
39 +
40 + /** Array of added products to cart.
41 + *
42 + * @since 1.7.9
43 + * @var array
44 + */
45 + public static $in_cart = [];
46 +
47 + /**
48 + * Checks if bumps applied.
49 + *
50 + * @since 1.8.1
51 + * @var bool
52 + */
53 + public static $is_bumps_applied = false;
54 +
55 + /**
23 56 * Create instance of class without construct.
24 57 *
25 58 * @since 1.1.0
26 59 * @return object
@@ -50,11 +83,8 @@
50 83 * @return void
51 84 * @since 1.1.0
52 85 */
53 86 private function actions() {
54 - // Empty cart notice.
55 - add_action( 'woocommerce_before_checkout_form_cart_notices', [ $this, 'empty_cart_notice' ] );
56 -
57 87 // sellkit wrapper for checkout widget.
58 88 add_action( 'woocommerce_before_checkout_form', [ $this, 'open_multistep_wrap' ] );
59 89 add_action( 'woocommerce_after_checkout_form', [ $this, 'close_multistep_wrap' ], 999 );
60 90
@@ -69,8 +99,11 @@
69 99
70 100 // Filter all woocommerce field right before printing them in our widget.
71 101 add_filter( 'woocommerce_checkout_fields', [ $this, 'woocommerce_checkout_fields' ] );
72 102
103 + // Hide shipping fields section title.
104 + add_filter( 'sellkit-checkout-disable-shipping-fields-title', [ $this, 'check_to_disable_shipping_title' ] );
105 +
73 106 // Customize shipping fields based on user desire.
74 107 add_action( 'sellkit_checkout_shipping_fields', [ $this, 'sellkit_checkout_shipping_field' ], 10, 2 );
75 108
76 109 // Customize billing fields based on user desire.
@@ -100,27 +133,17 @@
100 133 add_action( 'woocommerce_before_checkout_form', [ $this, 'order_bump' ] );
101 134
102 135 // Bundle products.
103 136 $this->bundled_products();
104 - }
105 137
106 - /**
107 - * Add custom notice if cart is empty.
108 - *
109 - * @return void
110 - * @since 1.1.0
111 - */
112 - public function empty_cart_notice() {
113 - global $woocommerce;
114 - $count = $woocommerce->cart->get_cart_contents_count();
138 + // Trigger for upsell steps popup.
139 + add_action( 'sellkit_checkout_required_hidden_fields', [ $this, 'add_trigger_field_for_upsell_steps' ] );
115 140
116 - if ( 0 === $count ) {
117 - /* translators: %s: Empty cart message. */
118 - echo sprintf(
119 - '<div class="elementor-alert elementor-alert-info">%s</div>',
120 - $this->settings['empty_cart']
121 - );
122 - }
141 + // Add upsell templates at the end of page.
142 + add_action( 'wp_footer', [ $this, 'sellkit_funnel_display_upsell_as_popup' ] );
143 +
144 + // Add order notes to checkout form to desired location.
145 + add_action( 'sellkit_checkout_after_term_and_condition', [ $this, 'order_notes' ] );
123 146 }
124 147
125 148 /**
126 149 * Opens a wrapper around widget checkout form.
@@ -230,8 +253,11 @@
230 253 break;
231 254 case 'cart-item-data.php':
232 255 $template = $our_path . 'templates/cart-item-data.php';
233 256 break;
257 + case 'terms.php':
258 + $template = $our_path . 'templates/terms.php';
259 + break;
234 260 }
235 261
236 262 return $template;
237 263 }
@@ -257,8 +283,23 @@
257 283 return $default_fields;
258 284 }
259 285
260 286 /**
287 + * Check to disable shipping fields section title.
288 + *
289 + * @since 1.2.1
290 + */
291 + public function check_to_disable_shipping_title() {
292 + $widget_shipping_fields = $this->settings['shipping_list'];
293 +
294 + if ( 0 === count( $widget_shipping_fields ) ) {
295 + return false;
296 + }
297 +
298 + return true;
299 + }
300 +
301 + /**
261 302 * Print shipping field in frontend using our customized fields.
262 303 *
263 304 * @param array $fields : shipping fields.
264 305 * @param object $checkout : checkout object.
@@ -305,9 +346,9 @@
305 346 $class = '\Sellkit\Elementor\Modules\Checkout\Fields\\' . ucfirst( $class );
306 347 $class = new $class();
307 348 $field = '';
308 349
309 - $class->final_html_structure( $field, $details, $key );
350 + $class->final_html_structure( $field, $details, $key, $checkout->get_value( $key ) );
310 351 }
311 352 }
312 353
313 354 /**
@@ -319,12 +360,13 @@
319 360 */
320 361 public function customize_billing_field( $default_fields ) {
321 362 $widget_billing_fields = $this->settings['billing_list'];
322 363 $widget_field_slug = Helper::instance()->get_user_defined_fields_slug( $widget_billing_fields, 'billing_list_field' );
364 + $core_billing_fields = array_keys( Helper::instance()->billing_fields() );
323 365
324 366 // Unset default fields.
325 367 foreach ( $default_fields as $key => $field ) {
326 - if ( ! in_array( $key, $widget_field_slug, true ) && 'billing_email' !== $field ) {
368 + if ( in_array( $key, $core_billing_fields, true ) && ! in_array( $key, $widget_field_slug, true ) && 'billing_email' !== $key ) {
327 369 unset( $default_fields[ $key ] );
328 370 }
329 371 }
330 372
@@ -393,9 +435,9 @@
393 435 $class = '\Sellkit\Elementor\Modules\Checkout\Fields\\' . ucfirst( $class );
394 436 $class = new $class();
395 437 $field = '';
396 438
397 - $field = $class->final_html_structure( $field, $details, $key );
439 + $field = $class->final_html_structure( $field, $details, $key, $checkout->get_value( $key ) );
398 440 }
399 441 }
400 442
401 443 /**
@@ -426,9 +468,9 @@
426 468 }
427 469 }
428 470
429 471 foreach ( $widget_shipping_fields as $data ) {
430 - $slug = $data['shipping_list_field'];
472 + $slug = isset( $data['shipping_list_field'] ) ? $data['shipping_list_field'] : '';
431 473
432 474 if ( 'yes' !== $data['shipping_list_required'] && array_key_exists( $slug, $default_fields['shipping'] ) ) {
433 475 $default_fields['shipping'][ $slug ]['required'] = false;
434 476 unset( $default_fields['shipping'][ $slug ]['required'] );
@@ -486,9 +528,9 @@
486 528 ?>
487 529 <section class="sellkit-checkout-widget-express-checkout sellkit-checkout-express-checkout-step-1">
488 530 <fieldset class="express-box sellkit-checkout-widget-divider">
489 531 <legend class="sellkit-express-checkout-legend heading">
490 - <?php echo __( 'Express Checkout', 'sellkit' ); ?>
532 + <?php echo esc_html__( 'Express Checkout', 'sellkit' ); ?>
491 533 </legend>
492 534 <div class="express-methods">
493 535 <?php do_action( 'sellkit-checkout-widget-express-methods' ); ?>
494 536 </div>
@@ -495,15 +537,15 @@
495 537 </fieldset>
496 538 </section>
497 539 <section class="sellkit-checkout-widget-express-checkout sellkit-checkout-express-checkout-step-2">
498 540 <fieldset id="sellkit-checkout-or-divider" class="divider-box sellkit-checkout-widget-divider">
499 - <legend class="heading"><?php echo __( 'OR', 'sellkit' ); ?></legend>
541 + <legend class="heading"><?php echo esc_html__( 'OR', 'sellkit' ); ?></legend>
500 542 </fieldset>
501 543 </section>
502 544 <?php
503 545 $express = ob_get_clean();
504 546 $express = apply_filters( 'sellkit-checkout-widget-express-checkout', $express );
505 - echo $express;
547 + echo wp_kses_post( $express );
506 548 }
507 549
508 550 /**
509 551 * Apply custom Messages.
@@ -523,9 +565,9 @@
523 565 add_action( 'sellkit_core/widgets/checkout/custom_message/create_website_account', function() {
524 566 $site = get_bloginfo( 'name' );
525 567 $text = $this->settings['create_website_account'];
526 568
527 - echo str_replace( '{{website}}', $site, $text );
569 + echo wp_kses_post( str_replace( '{{website}}', $site, $text ) );
528 570 } );
529 571
530 572 add_filter( 'sellkit_core/widgets/checkout/custom_message/secure_transaction_text', function() {
531 573 return $this->settings['secure_transaction_text'];
@@ -561,8 +603,23 @@
561 603 add_action( 'sellkit-checkout-widget-custom-coupon-form', function() use ( $settings ) {
562 604 Global_Hooks::instance()->coupon_form( $settings );
563 605 } );
564 606
607 + // Improve UI issue in the editor for the order summary input.
608 + add_filter( 'woocommerce_cart_item_class', function( $default ) use ( $settings, $posted_data ) {
609 + $default = str_replace( 'product-title-one-row', '', $default );
610 +
611 + if (
612 + ! array_key_exists( 'show_cart_edit', $settings ) ||
613 + array_key_exists( 'bundle-products-force', $posted_data ) ||
614 + empty( $settings['show_cart_edit'] )
615 + ) {
616 + $default .= ' product-title-one-row';
617 + }
618 +
619 + return $default;
620 + } );
621 +
565 622 return;
566 623 }
567 624
568 625 if ( wp_doing_ajax() ) {
@@ -584,9 +641,13 @@
584 641 } );
585 642
586 643 // Disable order item quantity input.
587 644 if ( array_key_exists( 'show_cart_edit', $settings ) || array_key_exists( 'bundle-products-force', $posted_data ) ) {
588 - add_action( 'sellkit-checkout-widget-disable-quantity', [ Helper::instance(), 'checkout_order_hidden_quantity' ], 10, 2 );
645 + add_filter( 'sellkit-checkout-widget-disable-quantity', [ Helper::instance(), 'checkout_order_hidden_quantity' ], 10, 2 );
646 +
647 + add_filter( 'woocommerce_cart_item_class', function( $default ) {
648 + return $default . ' product-title-one-row';
649 + } );
589 650 }
590 651
591 652 add_filter( 'woocommerce_shipping_package_name', function() {
592 653 return '<h4 id="shipping_header_title" class="shipping-method-header heading">' . esc_html__( 'Shipping Methods', 'sellkit' ) . '</h4>';
@@ -633,9 +694,9 @@
633 694 }, 10 );
634 695
635 696 // Disable order item quantity input.
636 697 if ( array_key_exists( 'show_cart_edit', $settings ) ) {
637 - add_action( 'sellkit-checkout-widget-disable-quantity', [ Helper::instance(), 'checkout_order_hidden_quantity' ], 10, 2 );
698 + add_filter( 'sellkit-checkout-widget-disable-quantity', [ Helper::instance(), 'checkout_order_hidden_quantity' ], 10, 2 );
638 699
639 700 add_filter( 'sellkit/includes/elementor/modules/checkout/quanity/class', function( $classes ) {
640 701 return $classes .= ' sellkit-checkout-widget-d-block';
641 702 } );
@@ -640,8 +701,14 @@
640 701 return $classes .= ' sellkit-checkout-widget-d-block';
641 702 } );
642 703 }
643 704
705 + if ( array_key_exists( 'show_cart_edit', $settings ) || array_key_exists( 'bundle-products-force', $posted_data ) ) {
706 + add_filter( 'woocommerce_cart_item_class', function( $default ) {
707 + return $default . ' product-title-one-row';
708 + } );
709 + }
710 +
644 711 add_filter( 'sellkit-checkout-place-order-btn-text', function( $place_order_btn ) {
645 712 if ( ! empty( $settings['place_order_btn_txt'] ) ) {
646 713 return $settings['place_order_btn_txt'];
647 714 }
@@ -701,14 +768,14 @@
701 768 }
702 769 ?>
703 770 <?php if ( array_key_exists( 'coupon_field_type', $settings ) && 'collapsible' === $settings['coupon_field_type'] ) : ?>
704 771 <span id="copoun_toggle" class="copoun_toggle sellkit-coupon-toggle sellkit-checkout-widget-links">
705 - <?php echo __( 'Have a coupon? Click here to enter your code', 'sellkit' ); ?>
772 + <?php echo esc_html__( 'Have a coupon? Click here to enter your code', 'sellkit' ); ?>
706 773 </span>
707 774 <?php $class .= ' sellkit-checkout-collapsible'; ?>
708 775 <?php Helper::instance()->editor_mode_extra_js(); ?>
709 776 <?php endif; ?>
710 - <div class="sellkit-custom-coupon-form <?php echo $class; ?>">
777 + <div class="sellkit-custom-coupon-form <?php echo esc_attr( $class ); ?>">
711 778 <p class="jx-form-row-first">
712 779 <input class="jx-coupon" type="text" placeholder="<?php esc_attr_e( 'Enter Promo code', 'sellkit' ); ?>" />
713 780 </p>
714 781
@@ -729,15 +796,19 @@
729 796 */
730 797 public function bundled_products() {
731 798 global $wp_query;
732 799 $query = $wp_query->query_vars;
733 - $option = 'allow-buyers';
800 + $option = 'default';
734 801
735 - if ( array_key_exists( 'funnel_product_settings', $query ) ) {
802 + if ( ! array_key_exists( 'funnel_product_settings', $query ) ) {
803 + return;
804 + }
805 +
806 + if ( ! empty( $query['funnel_product_settings'] ) ) {
736 807 $option = $query['funnel_product_settings'];
737 808 }
738 809
739 - if ( 'allow-buyers' === $option ) {
810 + if ( 'default' === $option ) {
740 811 return;
741 812 }
742 813
743 814 add_action( 'sellkit_checkout_required_hidden_fields', function() use ( $option ) {
@@ -756,18 +827,25 @@
756 827 * @since 1.1.0
757 828 * return void
758 829 */
759 830 public static function bundle_product_action( $option ) {
760 - if ( 'force-products' === $option ) {
761 - add_action( 'sellkit-checkout-widget-disable-quantity', [ Helper::instance(), 'checkout_order_hidden_quantity' ], 10, 2 );
831 + add_filter( 'sellkit-checkout-widget-disable-quantity', [ Helper::instance(), 'checkout_order_hidden_quantity' ], 10, 2 );
762 832
833 + if ( 'force-products' === $option || Elementor::$instance->editor->is_edit_mode() ) {
763 834 return;
764 835 }
765 836
766 - $products = WC()->cart->get_cart();
767 - $default = null;
768 - $default_q = null;
837 + $fields_type = 'radio';
838 + $products = WC()->cart->get_cart();
839 + $default = null;
840 + $default_q = null;
841 + $readonly = 'readonly';
769 842
843 + if ( 'allow-buyers' === $option ) {
844 + $fields_type = 'checkbox';
845 + $readonly = '';
846 + }
847 +
770 848 ob_start();
771 849 ?>
772 850 <section class="sellkit-checkout-bundled-products">
773 851 <div class="sellkit-checkout-bundled-inner-wrap">
@@ -782,31 +860,45 @@
782 860 </thead>
783 861 <tbody>
784 862 <?php foreach ( $products as $cart_item_key => $cart_item ) : ?>
785 863 <?php
864 + if ( in_array( $cart_item_key, self::$in_cart, true ) ) {
865 + continue;
866 + }
867 +
786 868 $_product = apply_filters( 'woocommerce_cart_item_product', $cart_item['data'], $cart_item, $cart_item_key );
787 869 $default = $_product->get_id();
788 870 $default_q = $cart_item['quantity'];
789 871 $unique_id = 'bundle-unique-id-' . $default;
872 + $checked = '';
873 +
874 + if ( 'checkbox' === $fields_type ) {
875 + $checked = 'checked';
876 + }
877 +
878 + if ( 'radio' === $fields_type && array_key_last( $products ) === $cart_item_key ) {
879 + $checked = 'checked';
880 + }
790 881 ?>
791 882 <tr class="sellkit-checkout-bundled-products-item">
792 883 <td class="sellkit-checkout-bundled-title">
793 884 <input
794 - type="radio"
885 + type="<?php echo esc_attr( $fields_type ); ?>"
795 886 value="<?php echo esc_attr( $_product->get_id() ); ?>"
796 887 name="sellkit-checkout-bundle-item"
797 888 class="sellkit-checkout-bundle-item"
798 889 id="<?php echo esc_attr( $unique_id ); ?>"
890 + <?php echo esc_html( $checked ); ?>
799 891 >
800 892 <label for="<?php echo esc_attr( $unique_id ); ?>">
801 - <?php echo $_product->get_name(); ?>
893 + <?php echo esc_html( $_product->get_name() ); ?>
802 894 </label>
803 895 </td>
804 896 <td class="sellkit-checkout-bundled-quantity">
805 - <input type="number" 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" >
897 + <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" >
806 898 </td>
807 899 <td class="sellkit-checkout-bundled-price">
808 - <?php echo apply_filters( 'woocommerce_cart_item_subtotal', WC()->cart->get_product_subtotal( $_product, $cart_item['quantity'] ), $cart_item, $cart_item_key ); ?>
900 + <?php echo wp_kses_post( apply_filters( 'woocommerce_cart_item_subtotal', WC()->cart->get_product_subtotal( $_product, $cart_item['quantity'] ), $cart_item, $cart_item_key ) ); ?>
809 901 </td>
810 902 <tr>
811 903 <?php if ( array_key_last( $products ) !== $cart_item_key ) : ?>
812 904 <tr>
@@ -823,17 +915,71 @@
823 915 <?php
824 916 $bundle_html = ob_get_clean();
825 917
826 918 add_action( 'sellkit-bundled-products-position', function() use ( $bundle_html ) {
827 - echo $bundle_html;
919 + $allowed_html = [
920 + 'section' => [
921 + 'class' => true,
922 + ],
923 + 'div' => [
924 + 'class' => true,
925 + ],
926 + 'span' => [
927 + 'class' => true,
928 + ],
929 + 'table' => [
930 + 'class' => true,
931 + ],
932 + 'thead' => [
933 + 'class' => true,
934 + ],
935 + 'tr' => [
936 + 'class' => true,
937 + ],
938 + 'th' => [
939 + 'class' => true,
940 + ],
941 + 'tbody' => [
942 + 'class' => true,
943 + ],
944 + 'td' => [
945 + 'class' => true,
946 + 'colspan' => true,
947 + ],
948 + 'input' => [
949 + 'type' => true,
950 + 'value' => true,
951 + 'name' => true,
952 + 'class' => true,
953 + 'id' => true,
954 + 'checked' => true,
955 + 'readonly' => true,
956 + 'min' => true,
957 + 'data-id' => true,
958 + ],
959 + 'label' => [
960 + 'for' => true,
961 + ],
962 + 'hr' => [],
963 + ];
964 +
965 + echo wp_kses( $bundle_html, $allowed_html );
828 966 } );
829 967
830 - if ( ! wp_doing_ajax() ) {
968 + if ( wp_doing_ajax() ) {
969 + return;
970 + }
971 +
972 + if ( 'radio' === $fields_type && null !== $default ) {
831 973 WC()->cart->empty_cart();
832 - if ( null !== $default ) {
833 - WC()->cart->add_to_cart( $default, $default_q );
834 - }
974 + WC()->cart->add_to_cart( $default, $default_q );
835 975 }
976 +
977 + if ( ! WC()->cart->needs_shipping() ) {
978 + wp_add_inline_script( 'sellkit-initialize-widgets', 'var sellkitCheckoutShipping = true', 'before' );
979 + }
980 +
981 + Global_Hooks::make_changes_after_cart_item_edit( get_the_id() );
836 982 }
837 983
838 984 /**
839 985 * Trigger to activate order bumb or not for this checkout.
@@ -846,90 +992,8 @@
846 992 if ( 'woocommerce_before_checkout_form' === current_action() ) {
847 993 self::order_bump_frontend_manager();
848 994 return;
849 995 }
850 -
851 - if ( ! array_key_exists( 'sellkit_current_page_id', $data ) ) {
852 - return;
853 - }
854 -
855 - $bumps_in_cart = [];
856 - $simple_bumps = [];
857 - $page = $data['sellkit_current_page_id'];
858 - $funnel = new Sellkit_Funnel( $page );
859 -
860 - if ( ! array_key_exists( 'bump', $funnel->current_step_data ) ) {
861 - return;
862 - }
863 -
864 - $bumps = $funnel->current_step_data['bump'];
865 -
866 - // Get added bump products in cart.
867 - foreach ( $data as $key => $value ) {
868 - if ( strpos( $key, 'sellkit_bump_data' ) !== false ) {
869 - $bumps_in_cart[] = $value;
870 - }
871 - }
872 -
873 - if ( empty( $bumps_in_cart ) ) {
874 - return;
875 - }
876 -
877 - foreach ( $bumps as $bump ) {
878 - // Check if product is set for bump.
879 - if ( ! array_key_exists( 'products', $bump['data'] ) ) {
880 - continue;
881 - }
882 -
883 - $products = $bump['data']['products'];
884 - $product_id = array_key_first( $products['list'] );
885 - $product_details = current( $products['list'] );
886 -
887 - // Check if product has discount.
888 - if ( empty( $product_details['discount'] ) ) {
889 - continue;
890 - }
891 -
892 - $simple_bumps[ $product_id ] = [
893 - 'type' => $product_details['discountType'],
894 - 'discount' => $product_details['discount'],
895 - ];
896 - }
897 -
898 - if ( empty( $simple_bumps ) ) {
899 - return;
900 - }
901 -
902 - $fee = 0;
903 -
904 - foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
905 - $product_id = apply_filters( 'woocommerce_cart_item_product_id', $cart_item['product_id'], $cart_item, $cart_item_key );
906 -
907 - if ( ! array_key_exists( $product_id, $simple_bumps ) ) {
908 - continue;
909 - }
910 -
911 - $discount_data = $simple_bumps[ $product_id ];
912 - $quantity = $cart_item['quantity'];
913 - $price = $cart_item['data']->get_price();
914 - $total = $price * $quantity;
915 -
916 - if ( 'percentage' === $discount_data['type'] ) {
917 - $discount = ( $total * $discount_data['discount'] ) / 100;
918 - } else {
919 - $discount = $discount_data['discount'];
920 - }
921 -
922 - $fee = $fee + $discount;
923 - }
924 -
925 - if ( $fee <= 0 ) {
926 - return;
927 - }
928 -
929 - add_action( 'woocommerce_cart_calculate_fees', function() use ( $fee ) {
930 - WC()->cart->add_fee( esc_html__( 'Bump Discount', 'sellkit' ), -$fee, true, 'standard' );
931 - } );
932 996 }
933 997
934 998 /**
935 999 * Order bump to manage frontend.
@@ -937,8 +1001,12 @@
937 1001 * @since 1.1.0
938 1002 * @return void
939 1003 */
940 1004 private static function order_bump_frontend_manager() {
1005 + if ( self::$is_bumps_applied ) {
1006 + return;
1007 + }
1008 +
941 1009 global $wp_query;
942 1010 $query = $wp_query->query_vars;
943 1011
944 1012 if ( ! array_key_exists( 'bump_data', $query ) ) {
@@ -958,8 +1026,10 @@
958 1026 add_action( $design['sellkit_funnels_bump_position'], function() use ( $design, $products ) {
959 1027 self::bump_html( $design, $products );
960 1028 }, 5 );
961 1029 }
1030 +
1031 + self::$is_bumps_applied = true;
962 1032 }
963 1033
964 1034 /**
965 1035 * Order bump html.
@@ -969,9 +1039,9 @@
969 1039 * @since 1.1.0
970 1040 * @return void
971 1041 */
972 1042 public static function bump_html( $design, $products ) {
973 - $list = $products['list'];
1043 + $list = empty( $products['list'] ) ? [] : $products['list'];
974 1044 $ids = [];
975 1045
976 1046 foreach ( $list as $id => $details ) {
977 1047 $ids[] = $id;
@@ -983,9 +1053,9 @@
983 1053 $ids_string = implode( '|', $ids );
984 1054 $product = wc_get_product( $ids_string );
985 1055 $qty = ( empty( $qty ) ) ? 1 : $qty;
986 1056
987 - if ( empty( $product ) || ! $product->get_id() ) {
1057 + if ( empty( $product ) || ! $product->get_id() || ! $product->is_in_stock() ) {
988 1058 return;
989 1059 }
990 1060
991 1061 $unique_id = 'bump-title-' . $ids_string;
@@ -996,8 +1066,10 @@
996 1066 'sellkit-checkout-after-order-summary' === current_action()
997 1067 ) {
998 1068 $class = 'sellkit-bump-review-order';
999 1069 }
1070 +
1071 + $checked = empty( WC()->cart->find_product_in_cart( WC()->cart->generate_cart_id( $product->get_id() ) ) ) ? false : true;
1000 1072 ?>
1001 1073 <div class="sellkit-checkout-step-bump-wrapper <?php echo esc_attr( $class ); ?>" >
1002 1074 <div class="sellkit-checkout-bump-order-header">
1003 1075 <div class="sellkit-bump-order-left-header">
@@ -1008,8 +1080,9 @@
1008 1080 class="sellkit-checkout-bump-order-products"
1009 1081 data-qty="<?php echo esc_attr( $qty ); ?>"
1010 1082 name="sellkit_bump_data_<?php echo esc_attr( $ids_string ); ?>"
1011 1083 id="<?php echo esc_html( $unique_id ); ?>"
1084 + <?php echo ( true === $checked ) ? 'checked="true"' : ''; ?>
1012 1085 >
1013 1086 <label
1014 1087 for="<?php echo esc_attr( $unique_id ); ?>"
1015 1088 class="sellkit-checkout-order-bump-title"
@@ -1019,32 +1092,29 @@
1019 1092 </div>
1020 1093 <div class="sellkit-bump-order-right-header">
1021 1094 <span class="sellkit-checkout-order-bump-price">
1022 1095 <?php
1023 - if ( ! empty( $discount ) ) {
1024 - $real_price = (float) $product->get_price();
1025 - $discount_value = $discount;
1096 + $discounted_price = Helper::calculate_discount( (int) $ids_string, $type, $discount );
1097 + $sale_price = $product->get_sale_price();
1098 + $regular_price = $product->get_regular_price();
1099 + $main_price = ( strpos( $type, 'sale' ) !== false ) ? $sale_price : $regular_price;
1026 1100
1027 - if ( 'percentage' === $type ) {
1028 - $discount_value = ( $real_price * $discount ) / 100;
1029 - }
1030 -
1031 - $discount_price = $real_price - $discount_value;
1101 + if ( floatval( $main_price ) > floatval( $discounted_price ) ) {
1032 1102 ?>
1033 1103 <del aria-hidden="true">
1034 1104 <span class="woocommerce-Price-amount amount">
1035 1105 <bdi>
1036 1106 <span class="woocommerce-Price-currencySymbol">
1037 - <?php echo wc_price( $real_price ); ?>
1107 + <?php echo wp_kses_post( wc_price( $main_price ) ); ?>
1038 1108 </span>
1039 1109 </bdi>
1040 1110 </span>
1041 1111 </del>
1042 - <bdi class="bump-price-bolded"><?php echo wc_price( $discount_price ); ?></bdi>
1112 + <bdi class="bump-price-bolded"><?php echo wp_kses_post( wc_price( $discounted_price ) ); ?></bdi>
1043 1113 <?php
1044 1114 } else {
1045 1115 ?>
1046 - <bdi><?php echo wc_price( $product->get_price() ); ?></bdi>
1116 + <bdi><?php echo wp_kses_post( wc_price( $main_price ) ); ?></bdi>
1047 1117 <?php
1048 1118 }
1049 1119 ?>
1050 1120 </span>
@@ -1051,16 +1121,183 @@
1051 1121 </div>
1052 1122 </div>
1053 1123 <div class="sellkit-checkout-bump-order-body" >
1054 1124 <div class="sellkit-bump-order-left-body">
1055 - <img src="<?php echo esc_attr( wp_get_attachment_image_src( $product->get_image_id() )[0] ); ?>" >
1125 + <?php $image = wp_get_attachment_image_src( $product->get_image_id() ); ?>
1126 + <?php if ( 'true' === $design['sellkit_funnels_bump_product_image'] && ! empty( $image[0] ) ) : ?>
1127 + <img src="<?php echo esc_url( $image[0] ); ?>" >
1128 + <?php endif; ?>
1056 1129 </div>
1057 1130 <div class="sellkit-bump-order-right-body">
1058 1131 <div class="sellkit-bump-order-description">
1059 - <?php echo $design['sellkit_content']; ?>
1132 + <?php echo wp_kses_post( $design['sellkit_content'] ); ?>
1060 1133 </div>
1061 1134 </div>
1062 1135 </div>
1063 1136 </div>
1064 1137 <?php
1138 + }
1139 +
1140 + /**
1141 + * Checks if funnel includes upsell step.
1142 + *
1143 + * @param string $goal customize return value.
1144 + * @param int $ajax_id upsell id through ajax.
1145 + * @since 1.6.2
1146 + */
1147 + public static function is_funnel_includes_upsell( $goal = 'is_upsell', $ajax_id = null ) {
1148 + $id = get_queried_object_id();
1149 +
1150 + if ( wp_doing_ajax() ) {
1151 + $id = $ajax_id;
1152 + }
1153 +
1154 + $step_data = get_post_meta( $id, 'step_data', true );
1155 + $include_upsell = false;
1156 + $upsell_steps = [];
1157 + $upsell_ids = [];
1158 + $global_checkout_id = get_option( Checkout::SELLKIT_GLOBAL_CHECKOUT_OPTION, 0 );
1159 +
1160 + // We are in default WooCommerce checkout page.
1161 + if ( empty( $step_data ) && $global_checkout_id > 0 && 'publish' === get_post_status( $global_checkout_id ) ) {
1162 + $steps = get_post_meta( $global_checkout_id, 'nodes', true );
1163 + $checkout_id = 0;
1164 +
1165 + foreach ( $steps as $step ) {
1166 + $step['type'] = (array) $step['type'];
1167 +
1168 + if ( 'checkout' === $step['type']['key'] ) {
1169 + $checkout_id = $step['page_id'];
1170 + }
1171 + }
1172 +
1173 + $step_data = get_post_meta( $checkout_id, 'step_data', true );
1174 + }
1175 +
1176 + if ( empty( $step_data ) ) {
1177 + return $include_upsell;
1178 + }
1179 +
1180 + $funnel_id = intval( $step_data['funnel_id'] );
1181 + $funnel_data = get_post_meta( $funnel_id, 'nodes', true );
1182 +
1183 + if ( empty( $funnel_data ) ) {
1184 + return $include_upsell;
1185 + }
1186 +
1187 + $popups = [ 'downsell', 'upsell' ];
1188 +
1189 + foreach ( $funnel_data as $step ) {
1190 + if ( isset( $step['data'] ) && isset( $step['data']['products'] ) && isset( $step['data']['products']['list'] ) ) {
1191 + $product_id = array_keys( $step['data']['products']['list'] )[0] ?? 0;
1192 +
1193 + if ( $product_id ) {
1194 + $product = wc_get_product( $product_id );
1195 +
1196 + if ( $product && ! $product->is_in_stock() ) {
1197 + return $include_upsell;
1198 + }
1199 + }
1200 + }
1201 +
1202 + $step['type'] = (array) $step['type'];
1203 +
1204 + if ( in_array( $step['type']['key'], $popups, true ) ) {
1205 + $include_upsell = true;
1206 + $upsell_steps[] = $step;
1207 + $upsell_ids[] = $step['page_id'];
1208 + }
1209 + }
1210 +
1211 + if ( 'get_ids' === $goal ) {
1212 + return $upsell_ids;
1213 + }
1214 +
1215 + // Send data to the filter that keeps steps data to prepare popup.
1216 + add_filter( 'sellkit_upsell_steps_popup_information', function( $default ) use ( $upsell_steps ) {
1217 + if ( ! empty( $upsell_steps ) ) {
1218 + return $upsell_steps;
1219 + }
1220 +
1221 + return $default;
1222 + } );
1223 +
1224 + return $include_upsell;
1225 + }
1226 +
1227 + /**
1228 + * Add an extra hidden field to checkout form if funnel includes upsell step.
1229 + *
1230 + * @since 1.6.2
1231 + */
1232 + public function add_trigger_field_for_upsell_steps() {
1233 + $include_upsell = self::is_funnel_includes_upsell();
1234 +
1235 + if ( false === $include_upsell ) {
1236 + return;
1237 + }
1238 +
1239 + echo '<input type="hidden" id="sellkit_funnel_has_upsell" value="upsell" >';
1240 + echo '<input type="hidden" id="sellkit_funnel_popup_step_id" value="0" >';
1241 + }
1242 +
1243 + /**
1244 + * Display sellkit upsell steps as popup.
1245 + *
1246 + * @since 1.6.2
1247 + */
1248 + public function sellkit_funnel_display_upsell_as_popup() {
1249 + $upsell_data = apply_filters( 'sellkit_upsell_steps_popup_information', [] );
1250 + $i = 1;
1251 +
1252 + if ( empty( $upsell_data ) ) {
1253 + return;
1254 + }
1255 +
1256 + foreach ( $upsell_data as $data ) {
1257 + $id = 'sellkit_funnel_upsell_popup_' . $i;
1258 + $class = 'sellkit_funnel_upsell_popup sellkit_funnel_upsell_popup_' . apply_filters( 'wpml_object_id', $data['page_id'], 'sellkit_step', true ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- WPML API.
1259 + ?>
1260 + <div class="<?php echo esc_attr( $class ); ?>" id="<?php echo esc_attr( $id ); ?>">
1261 + <?php echo wp_kses_post( Elementor::instance()->frontend->get_builder_content_for_display( apply_filters( 'wpml_object_id', $data['page_id'], 'sellkit_step', true ) ) ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- WPML API. ?>
1262 + <input type="hidden" class="identify" value="<?php echo esc_attr( apply_filters( 'wpml_object_id', $data['page_id'], 'sellkit_step', true ) ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- WPML API. ?>" >
1263 + </div>
1264 + <?php
1265 + $i++;
1266 + }
1267 + }
1268 +
1269 + /**
1270 + * Display checkout order notes field.
1271 + *
1272 + * @since 1.8.9
1273 + */
1274 + public function order_notes() {
1275 + // Get woocommerce order notes field.
1276 + $notes = WC()->checkout()->get_checkout_fields( 'order' );
1277 +
1278 + // print notes field.
1279 + foreach ( $notes as $key => $field ) {
1280 + ?>
1281 + <div class="sellkit-checkout-order-fields sellkit-widget-checkout-fields">
1282 + <?php
1283 + if ( 'order_comments' === $key ) {
1284 + ?>
1285 + <div class="sellkit-checkout-order-notes">
1286 + <div class="sellkit-order-note-field-wrapper">
1287 + <input id="sellkit-add-notes-to-order-box" type="checkbox">
1288 + <label for="sellkit-add-notes-to-order-box">
1289 + <?php echo esc_html__( 'Add a note to your order', 'sellkit' ); ?>
1290 + </label>
1291 + </div>
1292 + <?php
1293 + woocommerce_form_field( $key, $field, WC()->checkout()->get_value( $key ) );
1294 + ?>
1295 + </div>
1296 + <?php
1297 + }
1298 + ?>
1299 + </div>
1300 + <?php
1301 + }
1065 1302 }
1066 1303 }