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 +184 -33 1.7.52.7.0 View file →
@@ -21,8 +21,39 @@
21 21 * @since 1.1.0
22 22 */
23 23 class Local_Hooks {
24 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 + /**
25 56 * Create instance of class without construct.
26 57 *
27 58 * @since 1.1.0
28 59 * @return object
@@ -108,8 +139,11 @@
108 139 add_action( 'sellkit_checkout_required_hidden_fields', [ $this, 'add_trigger_field_for_upsell_steps' ] );
109 140
110 141 // Add upsell templates at the end of page.
111 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' ] );
112 146 }
113 147
114 148 /**
115 149 * Opens a wrapper around widget checkout form.
@@ -312,9 +346,9 @@
312 346 $class = '\Sellkit\Elementor\Modules\Checkout\Fields\\' . ucfirst( $class );
313 347 $class = new $class();
314 348 $field = '';
315 349
316 - $class->final_html_structure( $field, $details, $key );
350 + $class->final_html_structure( $field, $details, $key, $checkout->get_value( $key ) );
317 351 }
318 352 }
319 353
320 354 /**
@@ -326,12 +360,13 @@
326 360 */
327 361 public function customize_billing_field( $default_fields ) {
328 362 $widget_billing_fields = $this->settings['billing_list'];
329 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() );
330 365
331 366 // Unset default fields.
332 367 foreach ( $default_fields as $key => $field ) {
333 - 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 ) {
334 369 unset( $default_fields[ $key ] );
335 370 }
336 371 }
337 372
@@ -400,9 +435,9 @@
400 435 $class = '\Sellkit\Elementor\Modules\Checkout\Fields\\' . ucfirst( $class );
401 436 $class = new $class();
402 437 $field = '';
403 438
404 - $field = $class->final_html_structure( $field, $details, $key );
439 + $field = $class->final_html_structure( $field, $details, $key, $checkout->get_value( $key ) );
405 440 }
406 441 }
407 442
408 443 /**
@@ -493,9 +528,9 @@
493 528 ?>
494 529 <section class="sellkit-checkout-widget-express-checkout sellkit-checkout-express-checkout-step-1">
495 530 <fieldset class="express-box sellkit-checkout-widget-divider">
496 531 <legend class="sellkit-express-checkout-legend heading">
497 - <?php echo __( 'Express Checkout', 'sellkit' ); ?>
532 + <?php echo esc_html__( 'Express Checkout', 'sellkit' ); ?>
498 533 </legend>
499 534 <div class="express-methods">
500 535 <?php do_action( 'sellkit-checkout-widget-express-methods' ); ?>
501 536 </div>
@@ -502,15 +537,15 @@
502 537 </fieldset>
503 538 </section>
504 539 <section class="sellkit-checkout-widget-express-checkout sellkit-checkout-express-checkout-step-2">
505 540 <fieldset id="sellkit-checkout-or-divider" class="divider-box sellkit-checkout-widget-divider">
506 - <legend class="heading"><?php echo __( 'OR', 'sellkit' ); ?></legend>
541 + <legend class="heading"><?php echo esc_html__( 'OR', 'sellkit' ); ?></legend>
507 542 </fieldset>
508 543 </section>
509 544 <?php
510 545 $express = ob_get_clean();
511 546 $express = apply_filters( 'sellkit-checkout-widget-express-checkout', $express );
512 - echo $express;
547 + echo wp_kses_post( $express );
513 548 }
514 549
515 550 /**
516 551 * Apply custom Messages.
@@ -530,9 +565,9 @@
530 565 add_action( 'sellkit_core/widgets/checkout/custom_message/create_website_account', function() {
531 566 $site = get_bloginfo( 'name' );
532 567 $text = $this->settings['create_website_account'];
533 568
534 - echo str_replace( '{{website}}', $site, $text );
569 + echo wp_kses_post( str_replace( '{{website}}', $site, $text ) );
535 570 } );
536 571
537 572 add_filter( 'sellkit_core/widgets/checkout/custom_message/secure_transaction_text', function() {
538 573 return $this->settings['secure_transaction_text'];
@@ -733,14 +768,14 @@
733 768 }
734 769 ?>
735 770 <?php if ( array_key_exists( 'coupon_field_type', $settings ) && 'collapsible' === $settings['coupon_field_type'] ) : ?>
736 771 <span id="copoun_toggle" class="copoun_toggle sellkit-coupon-toggle sellkit-checkout-widget-links">
737 - <?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' ); ?>
738 773 </span>
739 774 <?php $class .= ' sellkit-checkout-collapsible'; ?>
740 775 <?php Helper::instance()->editor_mode_extra_js(); ?>
741 776 <?php endif; ?>
742 - <div class="sellkit-custom-coupon-form <?php echo $class; ?>">
777 + <div class="sellkit-custom-coupon-form <?php echo esc_attr( $class ); ?>">
743 778 <p class="jx-form-row-first">
744 779 <input class="jx-coupon" type="text" placeholder="<?php esc_attr_e( 'Enter Promo code', 'sellkit' ); ?>" />
745 780 </p>
746 781
@@ -825,12 +860,25 @@
825 860 </thead>
826 861 <tbody>
827 862 <?php foreach ( $products as $cart_item_key => $cart_item ) : ?>
828 863 <?php
864 + if ( in_array( $cart_item_key, self::$in_cart, true ) ) {
865 + continue;
866 + }
867 +
829 868 $_product = apply_filters( 'woocommerce_cart_item_product', $cart_item['data'], $cart_item, $cart_item_key );
830 869 $default = $_product->get_id();
831 870 $default_q = $cart_item['quantity'];
832 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 + }
833 881 ?>
834 882 <tr class="sellkit-checkout-bundled-products-item">
835 883 <td class="sellkit-checkout-bundled-title">
836 884 <input
@@ -838,12 +886,12 @@
838 886 value="<?php echo esc_attr( $_product->get_id() ); ?>"
839 887 name="sellkit-checkout-bundle-item"
840 888 class="sellkit-checkout-bundle-item"
841 889 id="<?php echo esc_attr( $unique_id ); ?>"
842 - <?php echo ( array_key_last( $products ) === $cart_item_key ) ? 'checked' : ''; ?>
890 + <?php echo esc_html( $checked ); ?>
843 891 >
844 892 <label for="<?php echo esc_attr( $unique_id ); ?>">
845 - <?php echo $_product->get_name(); ?>
893 + <?php echo esc_html( $_product->get_name() ); ?>
846 894 </label>
847 895 </td>
848 896 <td class="sellkit-checkout-bundled-quantity">
849 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" >
@@ -848,9 +896,9 @@
848 896 <td class="sellkit-checkout-bundled-quantity">
849 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" >
850 898 </td>
851 899 <td class="sellkit-checkout-bundled-price">
852 - <?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 ) ); ?>
853 901 </td>
854 902 <tr>
855 903 <?php if ( array_key_last( $products ) !== $cart_item_key ) : ?>
856 904 <tr>
@@ -867,24 +915,71 @@
867 915 <?php
868 916 $bundle_html = ob_get_clean();
869 917
870 918 add_action( 'sellkit-bundled-products-position', function() use ( $bundle_html ) {
871 - 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 );
872 966 } );
873 967
874 - if ( ! wp_doing_ajax() ) {
968 + if ( wp_doing_ajax() ) {
969 + return;
970 + }
971 +
972 + if ( 'radio' === $fields_type && null !== $default ) {
875 973 WC()->cart->empty_cart();
974 + WC()->cart->add_to_cart( $default, $default_q );
975 + }
876 976
877 - if ( null !== $default ) {
878 - WC()->cart->add_to_cart( $default, $default_q );
977 + if ( ! WC()->cart->needs_shipping() ) {
978 + wp_add_inline_script( 'sellkit-initialize-widgets', 'var sellkitCheckoutShipping = true', 'before' );
979 + }
879 980
880 - if ( ! WC()->cart->needs_shipping() ) {
881 - wp_add_inline_script( 'sellkit-initialize-widgets', 'var sellkitCheckoutShipping = true', 'before' );
882 - }
883 - }
884 -
885 - Global_Hooks::make_changes_after_cart_item_edit( get_the_id() );
886 - }
981 + Global_Hooks::make_changes_after_cart_item_edit( get_the_id() );
887 982 }
888 983
889 984 /**
890 985 * Trigger to activate order bumb or not for this checkout.
@@ -906,8 +1001,12 @@
906 1001 * @since 1.1.0
907 1002 * @return void
908 1003 */
909 1004 private static function order_bump_frontend_manager() {
1005 + if ( self::$is_bumps_applied ) {
1006 + return;
1007 + }
1008 +
910 1009 global $wp_query;
911 1010 $query = $wp_query->query_vars;
912 1011
913 1012 if ( ! array_key_exists( 'bump_data', $query ) ) {
@@ -927,8 +1026,10 @@
927 1026 add_action( $design['sellkit_funnels_bump_position'], function() use ( $design, $products ) {
928 1027 self::bump_html( $design, $products );
929 1028 }, 5 );
930 1029 }
1030 +
1031 + self::$is_bumps_applied = true;
931 1032 }
932 1033
933 1034 /**
934 1035 * Order bump html.
@@ -938,9 +1039,9 @@
938 1039 * @since 1.1.0
939 1040 * @return void
940 1041 */
941 1042 public static function bump_html( $design, $products ) {
942 - $list = $products['list'];
1043 + $list = empty( $products['list'] ) ? [] : $products['list'];
943 1044 $ids = [];
944 1045
945 1046 foreach ( $list as $id => $details ) {
946 1047 $ids[] = $id;
@@ -952,9 +1053,9 @@
952 1053 $ids_string = implode( '|', $ids );
953 1054 $product = wc_get_product( $ids_string );
954 1055 $qty = ( empty( $qty ) ) ? 1 : $qty;
955 1056
956 - if ( empty( $product ) || ! $product->get_id() ) {
1057 + if ( empty( $product ) || ! $product->get_id() || ! $product->is_in_stock() ) {
957 1058 return;
958 1059 }
959 1060
960 1061 $unique_id = 'bump-title-' . $ids_string;
@@ -965,8 +1066,10 @@
965 1066 'sellkit-checkout-after-order-summary' === current_action()
966 1067 ) {
967 1068 $class = 'sellkit-bump-review-order';
968 1069 }
1070 +
1071 + $checked = empty( WC()->cart->find_product_in_cart( WC()->cart->generate_cart_id( $product->get_id() ) ) ) ? false : true;
969 1072 ?>
970 1073 <div class="sellkit-checkout-step-bump-wrapper <?php echo esc_attr( $class ); ?>" >
971 1074 <div class="sellkit-checkout-bump-order-header">
972 1075 <div class="sellkit-bump-order-left-header">
@@ -977,8 +1080,9 @@
977 1080 class="sellkit-checkout-bump-order-products"
978 1081 data-qty="<?php echo esc_attr( $qty ); ?>"
979 1082 name="sellkit_bump_data_<?php echo esc_attr( $ids_string ); ?>"
980 1083 id="<?php echo esc_html( $unique_id ); ?>"
1084 + <?php echo ( true === $checked ) ? 'checked="true"' : ''; ?>
981 1085 >
982 1086 <label
983 1087 for="<?php echo esc_attr( $unique_id ); ?>"
984 1088 class="sellkit-checkout-order-bump-title"
@@ -999,18 +1103,18 @@
999 1103 <del aria-hidden="true">
1000 1104 <span class="woocommerce-Price-amount amount">
1001 1105 <bdi>
1002 1106 <span class="woocommerce-Price-currencySymbol">
1003 - <?php echo wc_price( $main_price ); ?>
1107 + <?php echo wp_kses_post( wc_price( $main_price ) ); ?>
1004 1108 </span>
1005 1109 </bdi>
1006 1110 </span>
1007 1111 </del>
1008 - <bdi class="bump-price-bolded"><?php echo wc_price( $discounted_price ); ?></bdi>
1112 + <bdi class="bump-price-bolded"><?php echo wp_kses_post( wc_price( $discounted_price ) ); ?></bdi>
1009 1113 <?php
1010 1114 } else {
1011 1115 ?>
1012 - <bdi><?php echo wc_price( $main_price ); ?></bdi>
1116 + <bdi><?php echo wp_kses_post( wc_price( $main_price ) ); ?></bdi>
1013 1117 <?php
1014 1118 }
1015 1119 ?>
1016 1120 </span>
@@ -1019,14 +1123,14 @@
1019 1123 <div class="sellkit-checkout-bump-order-body" >
1020 1124 <div class="sellkit-bump-order-left-body">
1021 1125 <?php $image = wp_get_attachment_image_src( $product->get_image_id() ); ?>
1022 1126 <?php if ( 'true' === $design['sellkit_funnels_bump_product_image'] && ! empty( $image[0] ) ) : ?>
1023 - <img src="<?php echo esc_attr( $image[0] ); ?>" >
1127 + <img src="<?php echo esc_url( $image[0] ); ?>" >
1024 1128 <?php endif; ?>
1025 1129 </div>
1026 1130 <div class="sellkit-bump-order-right-body">
1027 1131 <div class="sellkit-bump-order-description">
1028 - <?php echo $design['sellkit_content']; ?>
1132 + <?php echo wp_kses_post( $design['sellkit_content'] ); ?>
1029 1133 </div>
1030 1134 </div>
1031 1135 </div>
1032 1136 </div>
@@ -1082,8 +1186,20 @@
1082 1186
1083 1187 $popups = [ 'downsell', 'upsell' ];
1084 1188
1085 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 +
1086 1202 $step['type'] = (array) $step['type'];
1087 1203
1088 1204 if ( in_array( $step['type']['key'], $popups, true ) ) {
1089 1205 $include_upsell = true;
@@ -1138,15 +1254,50 @@
1138 1254 }
1139 1255
1140 1256 foreach ( $upsell_data as $data ) {
1141 1257 $id = 'sellkit_funnel_upsell_popup_' . $i;
1142 - $class = 'sellkit_funnel_upsell_popup sellkit_funnel_upsell_popup_' . $data['page_id'];
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.
1143 1259 ?>
1144 1260 <div class="<?php echo esc_attr( $class ); ?>" id="<?php echo esc_attr( $id ); ?>">
1145 - <?php echo Elementor::instance()->frontend->get_builder_content_for_display( $data['page_id'] ); ?>
1146 - <input type="hidden" class="identify" value="<?php echo esc_attr( $data['page_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. ?>" >
1147 1263 </div>
1148 1264 <?php
1149 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
1150 1301 }
1151 1302 }
1152 1303 }