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 +365 -146 1.2.32.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
@@ -103,27 +133,17 @@
103 133 add_action( 'woocommerce_before_checkout_form', [ $this, 'order_bump' ] );
104 134
105 135 // Bundle products.
106 136 $this->bundled_products();
107 - }
108 137
109 - /**
110 - * Add custom notice if cart is empty.
111 - *
112 - * @return void
113 - * @since 1.1.0
114 - */
115 - public function empty_cart_notice() {
116 - global $woocommerce;
117 - $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' ] );
118 140
119 - if ( 0 === $count ) {
120 - /* translators: %s: Empty cart message. */
121 - echo sprintf(
122 - '<div class="elementor-alert elementor-alert-info">%s</div>',
123 - $this->settings['empty_cart']
124 - );
125 - }
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' ] );
126 146 }
127 147
128 148 /**
129 149 * Opens a wrapper around widget checkout form.
@@ -233,8 +253,11 @@
233 253 break;
234 254 case 'cart-item-data.php':
235 255 $template = $our_path . 'templates/cart-item-data.php';
236 256 break;
257 + case 'terms.php':
258 + $template = $our_path . 'templates/terms.php';
259 + break;
237 260 }
238 261
239 262 return $template;
240 263 }
@@ -323,9 +346,9 @@
323 346 $class = '\Sellkit\Elementor\Modules\Checkout\Fields\\' . ucfirst( $class );
324 347 $class = new $class();
325 348 $field = '';
326 349
327 - $class->final_html_structure( $field, $details, $key );
350 + $class->final_html_structure( $field, $details, $key, $checkout->get_value( $key ) );
328 351 }
329 352 }
330 353
331 354 /**
@@ -337,12 +360,13 @@
337 360 */
338 361 public function customize_billing_field( $default_fields ) {
339 362 $widget_billing_fields = $this->settings['billing_list'];
340 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() );
341 365
342 366 // Unset default fields.
343 367 foreach ( $default_fields as $key => $field ) {
344 - 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 ) {
345 369 unset( $default_fields[ $key ] );
346 370 }
347 371 }
348 372
@@ -411,9 +435,9 @@
411 435 $class = '\Sellkit\Elementor\Modules\Checkout\Fields\\' . ucfirst( $class );
412 436 $class = new $class();
413 437 $field = '';
414 438
415 - $field = $class->final_html_structure( $field, $details, $key );
439 + $field = $class->final_html_structure( $field, $details, $key, $checkout->get_value( $key ) );
416 440 }
417 441 }
418 442
419 443 /**
@@ -444,9 +468,9 @@
444 468 }
445 469 }
446 470
447 471 foreach ( $widget_shipping_fields as $data ) {
448 - $slug = $data['shipping_list_field'];
472 + $slug = isset( $data['shipping_list_field'] ) ? $data['shipping_list_field'] : '';
449 473
450 474 if ( 'yes' !== $data['shipping_list_required'] && array_key_exists( $slug, $default_fields['shipping'] ) ) {
451 475 $default_fields['shipping'][ $slug ]['required'] = false;
452 476 unset( $default_fields['shipping'][ $slug ]['required'] );
@@ -504,9 +528,9 @@
504 528 ?>
505 529 <section class="sellkit-checkout-widget-express-checkout sellkit-checkout-express-checkout-step-1">
506 530 <fieldset class="express-box sellkit-checkout-widget-divider">
507 531 <legend class="sellkit-express-checkout-legend heading">
508 - <?php echo __( 'Express Checkout', 'sellkit' ); ?>
532 + <?php echo esc_html__( 'Express Checkout', 'sellkit' ); ?>
509 533 </legend>
510 534 <div class="express-methods">
511 535 <?php do_action( 'sellkit-checkout-widget-express-methods' ); ?>
512 536 </div>
@@ -513,15 +537,15 @@
513 537 </fieldset>
514 538 </section>
515 539 <section class="sellkit-checkout-widget-express-checkout sellkit-checkout-express-checkout-step-2">
516 540 <fieldset id="sellkit-checkout-or-divider" class="divider-box sellkit-checkout-widget-divider">
517 - <legend class="heading"><?php echo __( 'OR', 'sellkit' ); ?></legend>
541 + <legend class="heading"><?php echo esc_html__( 'OR', 'sellkit' ); ?></legend>
518 542 </fieldset>
519 543 </section>
520 544 <?php
521 545 $express = ob_get_clean();
522 546 $express = apply_filters( 'sellkit-checkout-widget-express-checkout', $express );
523 - echo $express;
547 + echo wp_kses_post( $express );
524 548 }
525 549
526 550 /**
527 551 * Apply custom Messages.
@@ -541,9 +565,9 @@
541 565 add_action( 'sellkit_core/widgets/checkout/custom_message/create_website_account', function() {
542 566 $site = get_bloginfo( 'name' );
543 567 $text = $this->settings['create_website_account'];
544 568
545 - echo str_replace( '{{website}}', $site, $text );
569 + echo wp_kses_post( str_replace( '{{website}}', $site, $text ) );
546 570 } );
547 571
548 572 add_filter( 'sellkit_core/widgets/checkout/custom_message/secure_transaction_text', function() {
549 573 return $this->settings['secure_transaction_text'];
@@ -579,8 +603,23 @@
579 603 add_action( 'sellkit-checkout-widget-custom-coupon-form', function() use ( $settings ) {
580 604 Global_Hooks::instance()->coupon_form( $settings );
581 605 } );
582 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 +
583 622 return;
584 623 }
585 624
586 625 if ( wp_doing_ajax() ) {
@@ -602,9 +641,13 @@
602 641 } );
603 642
604 643 // Disable order item quantity input.
605 644 if ( array_key_exists( 'show_cart_edit', $settings ) || array_key_exists( 'bundle-products-force', $posted_data ) ) {
606 - 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 + } );
607 650 }
608 651
609 652 add_filter( 'woocommerce_shipping_package_name', function() {
610 653 return '<h4 id="shipping_header_title" class="shipping-method-header heading">' . esc_html__( 'Shipping Methods', 'sellkit' ) . '</h4>';
@@ -651,9 +694,9 @@
651 694 }, 10 );
652 695
653 696 // Disable order item quantity input.
654 697 if ( array_key_exists( 'show_cart_edit', $settings ) ) {
655 - 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 );
656 699
657 700 add_filter( 'sellkit/includes/elementor/modules/checkout/quanity/class', function( $classes ) {
658 701 return $classes .= ' sellkit-checkout-widget-d-block';
659 702 } );
@@ -658,8 +701,14 @@
658 701 return $classes .= ' sellkit-checkout-widget-d-block';
659 702 } );
660 703 }
661 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 +
662 711 add_filter( 'sellkit-checkout-place-order-btn-text', function( $place_order_btn ) {
663 712 if ( ! empty( $settings['place_order_btn_txt'] ) ) {
664 713 return $settings['place_order_btn_txt'];
665 714 }
@@ -719,14 +768,14 @@
719 768 }
720 769 ?>
721 770 <?php if ( array_key_exists( 'coupon_field_type', $settings ) && 'collapsible' === $settings['coupon_field_type'] ) : ?>
722 771 <span id="copoun_toggle" class="copoun_toggle sellkit-coupon-toggle sellkit-checkout-widget-links">
723 - <?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' ); ?>
724 773 </span>
725 774 <?php $class .= ' sellkit-checkout-collapsible'; ?>
726 775 <?php Helper::instance()->editor_mode_extra_js(); ?>
727 776 <?php endif; ?>
728 - <div class="sellkit-custom-coupon-form <?php echo $class; ?>">
777 + <div class="sellkit-custom-coupon-form <?php echo esc_attr( $class ); ?>">
729 778 <p class="jx-form-row-first">
730 779 <input class="jx-coupon" type="text" placeholder="<?php esc_attr_e( 'Enter Promo code', 'sellkit' ); ?>" />
731 780 </p>
732 781
@@ -747,15 +796,19 @@
747 796 */
748 797 public function bundled_products() {
749 798 global $wp_query;
750 799 $query = $wp_query->query_vars;
751 - $option = 'allow-buyers';
800 + $option = 'default';
752 801
753 - 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'] ) ) {
754 807 $option = $query['funnel_product_settings'];
755 808 }
756 809
757 - if ( 'allow-buyers' === $option ) {
810 + if ( 'default' === $option ) {
758 811 return;
759 812 }
760 813
761 814 add_action( 'sellkit_checkout_required_hidden_fields', function() use ( $option ) {
@@ -774,18 +827,25 @@
774 827 * @since 1.1.0
775 828 * return void
776 829 */
777 830 public static function bundle_product_action( $option ) {
778 - if ( 'force-products' === $option ) {
779 - 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 );
780 832
833 + if ( 'force-products' === $option || Elementor::$instance->editor->is_edit_mode() ) {
781 834 return;
782 835 }
783 836
784 - $products = WC()->cart->get_cart();
785 - $default = null;
786 - $default_q = null;
837 + $fields_type = 'radio';
838 + $products = WC()->cart->get_cart();
839 + $default = null;
840 + $default_q = null;
841 + $readonly = 'readonly';
787 842
843 + if ( 'allow-buyers' === $option ) {
844 + $fields_type = 'checkbox';
845 + $readonly = '';
846 + }
847 +
788 848 ob_start();
789 849 ?>
790 850 <section class="sellkit-checkout-bundled-products">
791 851 <div class="sellkit-checkout-bundled-inner-wrap">
@@ -800,31 +860,45 @@
800 860 </thead>
801 861 <tbody>
802 862 <?php foreach ( $products as $cart_item_key => $cart_item ) : ?>
803 863 <?php
864 + if ( in_array( $cart_item_key, self::$in_cart, true ) ) {
865 + continue;
866 + }
867 +
804 868 $_product = apply_filters( 'woocommerce_cart_item_product', $cart_item['data'], $cart_item, $cart_item_key );
805 869 $default = $_product->get_id();
806 870 $default_q = $cart_item['quantity'];
807 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 + }
808 881 ?>
809 882 <tr class="sellkit-checkout-bundled-products-item">
810 883 <td class="sellkit-checkout-bundled-title">
811 884 <input
812 - type="radio"
885 + type="<?php echo esc_attr( $fields_type ); ?>"
813 886 value="<?php echo esc_attr( $_product->get_id() ); ?>"
814 887 name="sellkit-checkout-bundle-item"
815 888 class="sellkit-checkout-bundle-item"
816 889 id="<?php echo esc_attr( $unique_id ); ?>"
890 + <?php echo esc_html( $checked ); ?>
817 891 >
818 892 <label for="<?php echo esc_attr( $unique_id ); ?>">
819 - <?php echo $_product->get_name(); ?>
893 + <?php echo esc_html( $_product->get_name() ); ?>
820 894 </label>
821 895 </td>
822 896 <td class="sellkit-checkout-bundled-quantity">
823 - <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" >
824 898 </td>
825 899 <td class="sellkit-checkout-bundled-price">
826 - <?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 ) ); ?>
827 901 </td>
828 902 <tr>
829 903 <?php if ( array_key_last( $products ) !== $cart_item_key ) : ?>
830 904 <tr>
@@ -841,17 +915,71 @@
841 915 <?php
842 916 $bundle_html = ob_get_clean();
843 917
844 918 add_action( 'sellkit-bundled-products-position', function() use ( $bundle_html ) {
845 - 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 );
846 966 } );
847 967
848 - if ( ! wp_doing_ajax() ) {
968 + if ( wp_doing_ajax() ) {
969 + return;
970 + }
971 +
972 + if ( 'radio' === $fields_type && null !== $default ) {
849 973 WC()->cart->empty_cart();
850 - if ( null !== $default ) {
851 - WC()->cart->add_to_cart( $default, $default_q );
852 - }
974 + WC()->cart->add_to_cart( $default, $default_q );
853 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() );
854 982 }
855 983
856 984 /**
857 985 * Trigger to activate order bumb or not for this checkout.
@@ -864,90 +992,8 @@
864 992 if ( 'woocommerce_before_checkout_form' === current_action() ) {
865 993 self::order_bump_frontend_manager();
866 994 return;
867 995 }
868 -
869 - if ( ! array_key_exists( 'sellkit_current_page_id', $data ) ) {
870 - return;
871 - }
872 -
873 - $bumps_in_cart = [];
874 - $simple_bumps = [];
875 - $page = $data['sellkit_current_page_id'];
876 - $funnel = new Sellkit_Funnel( $page );
877 -
878 - if ( ! array_key_exists( 'bump', $funnel->current_step_data ) ) {
879 - return;
880 - }
881 -
882 - $bumps = $funnel->current_step_data['bump'];
883 -
884 - // Get added bump products in cart.
885 - foreach ( $data as $key => $value ) {
886 - if ( strpos( $key, 'sellkit_bump_data' ) !== false ) {
887 - $bumps_in_cart[] = $value;
888 - }
889 - }
890 -
891 - if ( empty( $bumps_in_cart ) ) {
892 - return;
893 - }
894 -
895 - foreach ( $bumps as $bump ) {
896 - // Check if product is set for bump.
897 - if ( ! array_key_exists( 'products', $bump['data'] ) ) {
898 - continue;
899 - }
900 -
901 - $products = $bump['data']['products'];
902 - $product_id = array_key_first( $products['list'] );
903 - $product_details = current( $products['list'] );
904 -
905 - // Check if product has discount.
906 - if ( empty( $product_details['discount'] ) ) {
907 - continue;
908 - }
909 -
910 - $simple_bumps[ $product_id ] = [
911 - 'type' => $product_details['discountType'],
912 - 'discount' => $product_details['discount'],
913 - ];
914 - }
915 -
916 - if ( empty( $simple_bumps ) ) {
917 - return;
918 - }
919 -
920 - $fee = 0;
921 -
922 - foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
923 - $product_id = apply_filters( 'woocommerce_cart_item_product_id', $cart_item['product_id'], $cart_item, $cart_item_key );
924 -
925 - if ( ! array_key_exists( $product_id, $simple_bumps ) ) {
926 - continue;
927 - }
928 -
929 - $discount_data = $simple_bumps[ $product_id ];
930 - $quantity = $cart_item['quantity'];
931 - $price = $cart_item['data']->get_price();
932 - $total = $price * $quantity;
933 -
934 - if ( 'percentage' === $discount_data['type'] ) {
935 - $discount = ( $total * $discount_data['discount'] ) / 100;
936 - } else {
937 - $discount = $discount_data['discount'];
938 - }
939 -
940 - $fee = $fee + $discount;
941 - }
942 -
943 - if ( $fee <= 0 ) {
944 - return;
945 - }
946 -
947 - add_action( 'woocommerce_cart_calculate_fees', function() use ( $fee ) {
948 - WC()->cart->add_fee( esc_html__( 'Bump Discount', 'sellkit' ), -$fee, true, 'standard' );
949 - } );
950 996 }
951 997
952 998 /**
953 999 * Order bump to manage frontend.
@@ -955,8 +1001,12 @@
955 1001 * @since 1.1.0
956 1002 * @return void
957 1003 */
958 1004 private static function order_bump_frontend_manager() {
1005 + if ( self::$is_bumps_applied ) {
1006 + return;
1007 + }
1008 +
959 1009 global $wp_query;
960 1010 $query = $wp_query->query_vars;
961 1011
962 1012 if ( ! array_key_exists( 'bump_data', $query ) ) {
@@ -976,8 +1026,10 @@
976 1026 add_action( $design['sellkit_funnels_bump_position'], function() use ( $design, $products ) {
977 1027 self::bump_html( $design, $products );
978 1028 }, 5 );
979 1029 }
1030 +
1031 + self::$is_bumps_applied = true;
980 1032 }
981 1033
982 1034 /**
983 1035 * Order bump html.
@@ -987,9 +1039,9 @@
987 1039 * @since 1.1.0
988 1040 * @return void
989 1041 */
990 1042 public static function bump_html( $design, $products ) {
991 - $list = $products['list'];
1043 + $list = empty( $products['list'] ) ? [] : $products['list'];
992 1044 $ids = [];
993 1045
994 1046 foreach ( $list as $id => $details ) {
995 1047 $ids[] = $id;
@@ -1001,9 +1053,9 @@
1001 1053 $ids_string = implode( '|', $ids );
1002 1054 $product = wc_get_product( $ids_string );
1003 1055 $qty = ( empty( $qty ) ) ? 1 : $qty;
1004 1056
1005 - if ( empty( $product ) || ! $product->get_id() ) {
1057 + if ( empty( $product ) || ! $product->get_id() || ! $product->is_in_stock() ) {
1006 1058 return;
1007 1059 }
1008 1060
1009 1061 $unique_id = 'bump-title-' . $ids_string;
@@ -1014,8 +1066,10 @@
1014 1066 'sellkit-checkout-after-order-summary' === current_action()
1015 1067 ) {
1016 1068 $class = 'sellkit-bump-review-order';
1017 1069 }
1070 +
1071 + $checked = empty( WC()->cart->find_product_in_cart( WC()->cart->generate_cart_id( $product->get_id() ) ) ) ? false : true;
1018 1072 ?>
1019 1073 <div class="sellkit-checkout-step-bump-wrapper <?php echo esc_attr( $class ); ?>" >
1020 1074 <div class="sellkit-checkout-bump-order-header">
1021 1075 <div class="sellkit-bump-order-left-header">
@@ -1026,8 +1080,9 @@
1026 1080 class="sellkit-checkout-bump-order-products"
1027 1081 data-qty="<?php echo esc_attr( $qty ); ?>"
1028 1082 name="sellkit_bump_data_<?php echo esc_attr( $ids_string ); ?>"
1029 1083 id="<?php echo esc_html( $unique_id ); ?>"
1084 + <?php echo ( true === $checked ) ? 'checked="true"' : ''; ?>
1030 1085 >
1031 1086 <label
1032 1087 for="<?php echo esc_attr( $unique_id ); ?>"
1033 1088 class="sellkit-checkout-order-bump-title"
@@ -1037,32 +1092,29 @@
1037 1092 </div>
1038 1093 <div class="sellkit-bump-order-right-header">
1039 1094 <span class="sellkit-checkout-order-bump-price">
1040 1095 <?php
1041 - if ( ! empty( $discount ) ) {
1042 - $real_price = (float) $product->get_price();
1043 - $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;
1044 1100
1045 - if ( 'percentage' === $type ) {
1046 - $discount_value = ( $real_price * $discount ) / 100;
1047 - }
1048 -
1049 - $discount_price = $real_price - $discount_value;
1101 + if ( floatval( $main_price ) > floatval( $discounted_price ) ) {
1050 1102 ?>
1051 1103 <del aria-hidden="true">
1052 1104 <span class="woocommerce-Price-amount amount">
1053 1105 <bdi>
1054 1106 <span class="woocommerce-Price-currencySymbol">
1055 - <?php echo wc_price( $real_price ); ?>
1107 + <?php echo wp_kses_post( wc_price( $main_price ) ); ?>
1056 1108 </span>
1057 1109 </bdi>
1058 1110 </span>
1059 1111 </del>
1060 - <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>
1061 1113 <?php
1062 1114 } else {
1063 1115 ?>
1064 - <bdi><?php echo wc_price( $product->get_price() ); ?></bdi>
1116 + <bdi><?php echo wp_kses_post( wc_price( $main_price ) ); ?></bdi>
1065 1117 <?php
1066 1118 }
1067 1119 ?>
1068 1120 </span>
@@ -1069,16 +1121,183 @@
1069 1121 </div>
1070 1122 </div>
1071 1123 <div class="sellkit-checkout-bump-order-body" >
1072 1124 <div class="sellkit-bump-order-left-body">
1073 - <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; ?>
1074 1129 </div>
1075 1130 <div class="sellkit-bump-order-right-body">
1076 1131 <div class="sellkit-bump-order-description">
1077 - <?php echo $design['sellkit_content']; ?>
1132 + <?php echo wp_kses_post( $design['sellkit_content'] ); ?>
1078 1133 </div>
1079 1134 </div>
1080 1135 </div>
1081 1136 </div>
1082 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 + }
1083 1302 }
1084 1303 }