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/global-hooks.php +308 -29 1.7.22.7.0 View file →
@@ -4,8 +4,10 @@
4 4
5 5 defined( 'ABSPATH' ) || exit;
6 6
7 7 use Sellkit\Elementor\Modules\Checkout\Classes\{ Local_Hooks, Helper };
8 +use Sellkit\Funnel\Analytics\Data_Updater;
9 +use Sellkit\Funnel\Contacts\Base_Contacts;
8 10 use Sellkit\Funnel\Steps\Checkout;
9 11 use Sellkit_Funnel;
10 12
11 13 /**
@@ -14,12 +16,27 @@
14 16 * @SuppressWarnings(PHPMD.UnusedFormalParameter)
15 17 * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
16 18 * @SuppressWarnings(PHPMD.TooManyMethods)
17 19 * @SuppressWarnings(PHPMD.NPathComplexity)
20 + * @SuppressWarnings(PHPMD.ExcessiveClassLength)
18 21 * @since 1.1.0
19 22 */
20 23 class Global_Hooks {
21 24 /**
25 + * Helper id during checkout process.
26 + *
27 + * @var int
28 + */
29 + private $helper_id = 0;
30 +
31 + /**
32 + * List of upsell product with price
33 + *
34 + * @var array
35 + */
36 + private static $sellkit_upsell_products;
37 +
38 + /**
22 39 * Create instance of class without construct.
23 40 *
24 41 * @since 1.1.0
25 42 * @return object
@@ -58,8 +75,12 @@
58 75
59 76 // Save user defined fields.
60 77 add_action( 'woocommerce_checkout_update_order_meta', [ $this, 'save_user_defined_fields' ] );
61 78
79 + // Display user defined fields in order edit page.
80 + add_action( 'woocommerce_admin_order_data_after_billing_address', [ $this, 'add_item_to_order_details' ], 10, 1 );
81 + add_action( 'woocommerce_admin_order_data_after_shipping_address', [ $this, 'add_item_to_order_details' ], 10, 1 );
82 +
62 83 // Add custom shipping field to email.
63 84 add_filter( 'woocommerce_order_get_formatted_shipping_address', [ $this, 'attach_user_shipping_fields_to_order_email' ], 10, 3 );
64 85
65 86 // Add custom billing field to email.
@@ -79,8 +100,20 @@
79 100 add_filter( 'sellkit-shipping-methods-choosen-method', [ $this, 'sellkit_default_shipping_method' ], 10, 1 );
80 101
81 102 // Modify discounted products.
82 103 add_action( 'woocommerce_before_calculate_totals', [ $this, 'before_cart_calculate' ], 999 );
104 +
105 + // Allow viewing of Checkout page in the Editor with an empty cart.
106 + $action = isset( $_REQUEST['action'] ) ? filter_var( $_REQUEST['action'], FILTER_SANITIZE_FULL_SPECIAL_CHARS ) : ''; // phpcs:ignore
107 + $elementor_preview = isset( $_REQUEST['elementor-preview'] ) ? filter_var( $_REQUEST['elementor-preview'], FILTER_SANITIZE_FULL_SPECIAL_CHARS ) : ''; // phpcs:ignore
108 +
109 + if (
110 + ( 'elementor' === $action && is_admin() ) // Elementor Editor.
111 + || 'elementor_ajax' === $action // Elementor Editor Preview - Ajax Render Widget.
112 + || ! empty( $elementor_preview ) // Elementor Editor Preview.
113 + ) {
114 + add_filter( 'woocommerce_checkout_redirect_empty_cart', '__return_false', 5 );
115 + }
83 116 }
84 117
85 118 /**
86 119 * Handle ajax calls.
@@ -246,8 +279,16 @@
246 279 if ( empty( $optimization_data ) ) {
247 280 return;
248 281 }
249 282
283 + $auto_apply_coupon_cookie_value = null;
284 +
285 + if ( isset( $_COOKIE['sellkit_rejected_coupon'] ) ) {
286 + // Get the value of the cookie.
287 + $auto_apply_coupon_cookie_value = sanitize_text_field( wp_unslash( $_COOKIE['sellkit_rejected_coupon'] ) );
288 + $auto_apply_coupon_cookie_value = explode( ',', $auto_apply_coupon_cookie_value );
289 + }
290 +
250 291 // Help to apply funnel discount prices and coupons when changing product quantity.
251 292 self::apply_discounted_prices( wc()->cart, $funnel_id );
252 293 self::apply_discounted_prices( wc()->cart, $funnel_id, 'bumps' );
253 294
@@ -254,8 +295,11 @@
254 295 if ( Checkout::apply_coupon_validation( $optimization_data ) ) {
255 296 WC()->cart->remove_coupons();
256 297
257 298 foreach ( $optimization_data['auto_apply_coupons'] as $auto_apply_coupon ) {
299 + if ( ! empty( $auto_apply_coupon_cookie_value ) && in_array( $auto_apply_coupon['label'], $auto_apply_coupon_cookie_value, true ) ) {
300 + continue;
301 + }
258 302 wc()->cart->add_discount( get_the_title( $auto_apply_coupon['value'] ) );
259 303 }
260 304
261 305 wc_clear_notices();
@@ -270,9 +314,9 @@
270 314 */
271 315 public function add_shipping_total_to_review_order() {
272 316 ?>
273 317 <tr class="sellkit-shipping-total">
274 - <th><?php echo __( 'Shipping', 'sellkit' ); ?></th>
318 + <th><?php echo esc_html__( 'Shipping', 'sellkit' ); ?></th>
275 319 <td>
276 320 <?php
277 321 $price = WC()->cart->get_shipping_total();
278 322
@@ -279,9 +323,9 @@
279 323 if ( WC()->cart->display_prices_including_tax() ) {
280 324 $price = WC()->cart->get_shipping_total() + WC()->cart->shipping_tax_total;
281 325 }
282 326
283 - echo wc_price( $price );
327 + echo wp_kses_post( wc_price( $price ) );
284 328 ?>
285 329 </td>
286 330 </tr>
287 331 <?php
@@ -806,8 +850,9 @@
806 850 * Modify cart contents using bundled products.
807 851 *
808 852 * @since 1.1.0
809 853 * @return void
854 + * @SuppressWarnings(PHPMD.CyclomaticComplexity)
810 855 */
811 856 public function sellkit_checkout_modify_cart_by_bundle_products() {
812 857 $qty = filter_input( INPUT_POST, 'qty', FILTER_SANITIZE_NUMBER_INT );
813 858 $id = filter_input( INPUT_POST, 'id', FILTER_SANITIZE_NUMBER_INT );
@@ -827,11 +872,31 @@
827 872 wp_send_json_success();
828 873 }
829 874
830 875 if ( 'radio' === $type ) {
831 - $step_data = get_post_meta( $checkout_id, 'step_data', true );
832 - $products = $step_data['data']['products']['list'];
833 - $selected = $products[ $id ];
876 + $step_data = get_post_meta( $checkout_id, 'step_data', true );
877 + $products = $step_data['data']['products']['list'];
878 + $reset_cart = isset( $step_data['data']['products']['reset_cart'] ) ? $step_data['data']['products']['reset_cart'] : 'true';
879 +
880 + if ( 'true' === $reset_cart ) {
881 + foreach ( WC()->cart->get_cart() as $item ) {
882 + if ( empty( $item['product_id'] ) ) {
883 + continue;
884 + }
885 +
886 + if ( array_key_exists( $item['product_id'], $products ) ) {
887 + continue;
888 + }
889 +
890 + $products[ $item['product_id'] ] = [
891 + 'quantity' => $item['quantity'],
892 + 'discount' => '',
893 + 'discountType' => 'fixed',
894 + ];
895 + }
896 + }
897 +
898 + $selected = ! empty( $products[ $id ] ) ? $products[ $id ] : [];
834 899 $real_quantity = ( empty( $selected['quantity'] ) ) ? 1 : $selected['quantity'];
835 900
836 901 if ( (int) $real_quantity !== (int) $qty ) {
837 902 wp_send_json_error( esc_html__( 'Oh do not be tricky.', 'sellkit' ) );
@@ -886,8 +951,9 @@
886 951 * @param int $checkout_id_ajax checkout id.
887 952 * @param string $source source of products, bump or default products to be checked.
888 953 * @param array $upsell_data upsell product data coming from popup.
889 954 * @since 1.2.8
955 + * @SuppressWarnings(PHPMD.CyclomaticComplexity)
890 956 */
891 957 public static function apply_discounted_prices( $cart = [], $checkout_id_ajax = null, $source = 'default', $upsell_data = [] ) {
892 958 $checkout_id = get_queried_object_id();
893 959
@@ -909,9 +975,9 @@
909 975
910 976 if (
911 977 'default' === $source &&
912 978 array_key_exists( 'data', $step_data ) &&
913 - array_key_exists( 'list', $step_data['data']['products'] )
979 + ( ! empty( $step_data['data']['products'] ) && array_key_exists( 'list', $step_data['data']['products'] ) )
914 980 ) {
915 981 $products = $step_data['data']['products']['list'];
916 982 }
917 983
@@ -922,9 +988,14 @@
922 988 if ( ! array_key_exists( 'products', $bump['data'] ) ) {
923 989 continue;
924 990 }
925 991
926 - $key = array_key_first( $bump['data']['products']['list'] );
992 + $key = ! empty( $bump['data']['products']['list'] ) ? array_key_first( $bump['data']['products']['list'] ) : null;
993 +
994 + if ( empty( $key ) ) {
995 + continue;
996 + }
997 +
927 998 $products[ $key ] = $bump['data']['products']['list'][ $key ];
928 999 }
929 1000 }
930 1001
@@ -947,12 +1018,16 @@
947 1018 }
948 1019
949 1020 foreach ( $products as $product_id => $product_details ) {
950 1021 if ( $item_id === $product_id ) {
951 - $discount_type = $product_details['discountType'];
952 - $discount_value = $product_details['discount'];
1022 + $discount_type = isset( $product_details['discountType'] ) ? $product_details['discountType'] : '';
1023 + $discount_value = isset( $product_details['discount'] ) ? $product_details['discount'] : '';
953 1024
954 1025 $price = Helper::calculate_discount( $item_id, $discount_type, $discount_value );
1026 +
1027 + if ( 'upsell' === $source ) {
1028 + self::$sellkit_upsell_products[ $product_id ] = $price;
1029 + }
955 1030 }
956 1031 }
957 1032
958 1033 if ( false !== $price ) {
@@ -958,9 +1033,9 @@
958 1033 if ( false !== $price ) {
959 1034 $details['data']->set_price( $price );
960 1035 }
961 1036
962 - $final_price += $details['data']->get_price( $price ) * $details['quantity'];
1037 + $final_price += $details['data']->get_price() * $details['quantity'];
963 1038 }
964 1039
965 1040 self::modify_products_price_before_woo_apply_discounts( $final_price );
966 1041 }
@@ -1093,8 +1168,9 @@
1093 1168 /**
1094 1169 * Recalculate checkout and cart prices.
1095 1170 *
1096 1171 * @since 1.2.8
1172 + * @SuppressWarnings(PHPMD.CyclomaticComplexity)
1097 1173 */
1098 1174 public function before_cart_calculate() {
1099 1175 // More than twice isn't necessary. this is called multiple times by WooCommerce.
1100 1176 if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 && wp_doing_ajax() ) {
@@ -1116,11 +1192,13 @@
1116 1192 // Catch id after pressing place order button. none of above methods worked.
1117 1193 if ( empty( $checkout_id ) ) {
1118 1194 $data = filter_input( INPUT_POST, 'post_data', FILTER_DEFAULT );
1119 1195
1120 - parse_str( $data, $data );
1196 + if ( ! empty( $data ) ) {
1197 + parse_str( $data, $data );
1198 + }
1121 1199
1122 - if ( array_key_exists( 'sellkit_current_page_id', $data ) ) {
1200 + if ( is_array( $data ) && array_key_exists( 'sellkit_current_page_id', $data ) ) {
1123 1201 $checkout_id = $data['sellkit_current_page_id'];
1124 1202 }
1125 1203 }
1126 1204 }
@@ -1135,8 +1213,43 @@
1135 1213 // Apply funnel prices.
1136 1214 self::apply_discounted_prices( wc()->cart, $checkout_id );
1137 1215 self::apply_discounted_prices( wc()->cart, $checkout_id, 'bumps' );
1138 1216
1217 + // Apply upsell discount.
1218 + $sellkit_upsell_prices = null;
1219 + if ( isset( $_POST['woocommerce-process-checkout-nonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['woocommerce-process-checkout-nonce'] ) ), 'woocommerce-process_checkout' ) ) {
1220 + $sellkit_upsell_prices = isset( $_POST['sellkit_product_prices'] ) ? sanitize_textarea_field( wp_unslash( $_POST['sellkit_product_prices'] ) ) : null;
1221 + }
1222 + $upsell_product_ids;
1223 +
1224 + if ( isset( $sellkit_upsell_prices ) && ! empty( $sellkit_upsell_prices ) ) {
1225 + $sellkit_upsell_prices = json_decode( $sellkit_upsell_prices, true );
1226 + $upsell_product_ids = array_keys( $sellkit_upsell_prices );
1227 + }
1228 +
1229 + if ( isset( $upsell_product_ids ) ) {
1230 + foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
1231 + $product = $cart_item['data'];
1232 + $product_name = $product->get_name();
1233 + $product_id = $product->get_id();
1234 +
1235 + if ( in_array( $product_id, $upsell_product_ids, true ) ) {
1236 + $upsell_price = $sellkit_upsell_prices[ $product_id ];
1237 + $product->set_price( $upsell_price );
1238 + }
1239 +
1240 + $price = $product->get_price();
1241 + }
1242 + }
1243 +
1244 + $auto_apply_coupon_cookie_value = null;
1245 +
1246 + if ( isset( $_COOKIE['sellkit_rejected_coupon'] ) ) {
1247 + // Get the value of the cookie.
1248 + $auto_apply_coupon_cookie_value = sanitize_text_field( wp_unslash( $_COOKIE['sellkit_rejected_coupon'] ) );
1249 + $auto_apply_coupon_cookie_value = explode( ',', $auto_apply_coupon_cookie_value );
1250 + }
1251 +
1139 1252 // We should re apply coupons after each price changes. to make sure everything is correct.
1140 1253 $optimization_data = ! empty( $funnel_data['data']['optimization'] ) ? $funnel_data['data']['optimization'] : '';
1141 1254
1142 1255 if ( Checkout::apply_coupon_validation( $optimization_data ) ) {
@@ -1142,8 +1255,11 @@
1142 1255 if ( Checkout::apply_coupon_validation( $optimization_data ) ) {
1143 1256 WC()->cart->remove_coupons();
1144 1257
1145 1258 foreach ( $optimization_data['auto_apply_coupons'] as $auto_apply_coupon ) {
1259 + if ( ! empty( $auto_apply_coupon_cookie_value ) && in_array( $auto_apply_coupon['label'], $auto_apply_coupon_cookie_value, true ) ) {
1260 + continue;
1261 + }
1146 1262 wc()->cart->add_discount( get_the_title( $auto_apply_coupon['value'] ) );
1147 1263 }
1148 1264
1149 1265 wc_clear_notices();
@@ -1161,16 +1277,24 @@
1161 1277 $funnel = new Sellkit_Funnel( $step );
1162 1278 $next_step = $funnel->next_step_data;
1163 1279 $popups = [ 'upsell', 'downsell' ];
1164 1280
1281 + $funnel->next_step_data['type'] = (array) $funnel->next_step_data['type'];
1282 +
1165 1283 if ( 'decision' === $funnel->next_step_data['type']['key'] ) {
1166 - $this->take_care_of_decision_step( $funnel->next_step_data['page_id'] );
1284 + $page_id = isset( $funnel->next_step_data['page_id'] ) ? apply_filters( 'wpml_object_id', $funnel->next_step_data['page_id'], 'sellkit_step', true ) : 0; // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- WPML API.
1285 +
1286 + $this->helper_id = $step;
1287 + $this->take_care_of_decision_step( $page_id, $funnel->funnel_id );
1167 1288 return;
1168 1289 }
1169 1290
1170 1291 if ( in_array( $funnel->next_step_data['type']['key'], $popups, true ) ) {
1292 +
1293 + $next_step = $this->is_set_upsell_product( $next_step );
1294 +
1171 1295 wp_send_json_success( [
1172 - 'next_id' => $next_step['page_id'],
1296 + 'next_id' => apply_filters( 'wpml_object_id', $next_step['page_id'], 'sellkit_step', true ), // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- WPML API.
1173 1297 'next_type' => $next_step['type']['key'],
1174 1298 ] );
1175 1299 }
1176 1300 }
@@ -1175,14 +1299,51 @@
1175 1299 }
1176 1300 }
1177 1301
1178 1302 /**
1303 + * Check the upsell or downsell have product or not, ignore upsell/downsell step if product doesn't set.
1304 + *
1305 + * @param array $next_step Next step data.
1306 + * @since 2.6.0
1307 + */
1308 + private function is_set_upsell_product( $next_step ) {
1309 + if ( isset( $next_step['type']['key'] ) && ! in_array( $next_step['type']['key'], [ 'upsell', 'downsell' ], true ) ) {
1310 + return $next_step;
1311 + }
1312 +
1313 + $products = isset( $next_step['data'] ) ? $next_step['data']['products'] : [];
1314 + $list = isset( $products['list'] ) ? $products['list'] : [];
1315 +
1316 + if ( empty( $list ) ) {
1317 + $funnel = isset( $next_step['page_id'] ) ? new Sellkit_Funnel( $next_step['page_id'] ) : null;
1318 + $next_step = ! empty( $funnel ) ? $funnel->next_no_step_data : [];
1319 +
1320 + if ( empty( $next_step ) && ! empty( $funnel ) ) {
1321 + return $funnel->end_node_step_data;
1322 + }
1323 +
1324 + if ( isset( $next_step['type']['key'] ) && in_array( $next_step['type']['key'], [ 'upsell', 'downsell' ], true ) ) {
1325 +
1326 + $next_step = $this->is_set_upsell_product( $next_step );
1327 + }
1328 + }
1329 +
1330 + return $next_step;
1331 + }
1332 +
1333 + /**
1179 1334 * Gets step id before the decision step and return result.
1180 1335 *
1181 1336 * @param int $step_id id of the step before decision step.
1337 + * @param int $funnel_id id of the funnel.
1182 1338 * @since 1.6.2
1183 1339 */
1184 - private function take_care_of_decision_step( $step_id ) {
1340 + private function take_care_of_decision_step( $step_id, $funnel_id = null ) {
1341 + // Failed decision step due to no page id should be checked a little different.
1342 + if ( empty( $step_id ) && ! empty( $funnel_id ) ) {
1343 + $this->check_decision_step_with_no_page_id();
1344 + }
1345 +
1185 1346 $funnel = new Sellkit_Funnel( $step_id );
1186 1347 $conditions = ! empty( $funnel->current_step_data['data']['conditions'] ) ? $funnel->current_step_data['data']['conditions'] : [];
1187 1348 $is_valid = sellkit_conditions_validation( $conditions );
1188 1349 $next_step = $funnel->next_no_step_data;
@@ -1190,21 +1351,51 @@
1190 1351 if ( $is_valid ) {
1191 1352 $next_step = $funnel->next_step_data;
1192 1353 }
1193 1354
1355 + $next_step = $this->is_set_upsell_product( $next_step );
1356 + $next_step['type'] = (array) $next_step['type'];
1357 +
1194 1358 if ( 'decision' === $next_step['type']['key'] ) {
1195 - $this->take_care_of_decision_step( $next_step['page_id'] );
1359 + $this->take_care_of_decision_step( apply_filters( 'wpml_object_id', $next_step['page_id'], 'sellkit_step', true ) ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- WPML API.
1196 1360
1197 1361 return;
1198 1362 }
1199 1363
1200 1364 wp_send_json_success( [
1201 - 'next_id' => $next_step['page_id'],
1365 + 'next_id' => apply_filters( 'wpml_object_id', $next_step['page_id'], 'sellkit_step', true ), // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- WPML API.
1202 1366 'next_type' => $next_step['type']['key'],
1203 1367 ] );
1204 1368 }
1205 1369
1206 1370 /**
1371 + * Decision next step directly using funnel data.
1372 + *
1373 + * @since 1.8.6
1374 + */
1375 + private function check_decision_step_with_no_page_id() {
1376 + $funnel = new Sellkit_Funnel( $this->helper_id );
1377 + $decicion_data = $funnel->next_step_data;
1378 + $conditions = $decicion_data['data']['conditions'];
1379 + $funnel_data = get_post_meta( $funnel->funnel_id, 'nodes', true );
1380 + $next_no = 'none' !== $decicion_data['targets'][1]['nodeId'] ? $funnel_data[ $decicion_data['targets'][1]['nodeId'] ] : $funnel->end_node_step_data;
1381 + $next_yes = 'none' !== $decicion_data['targets'][0]['nodeId'] ? $funnel_data[ $decicion_data['targets'][0]['nodeId'] ] : $funnel->end_node_step_data;
1382 + $is_valid = sellkit_conditions_validation( $conditions );
1383 + $next_step = $next_no;
1384 +
1385 + if ( $is_valid ) {
1386 + $next_step = $next_yes;
1387 + }
1388 +
1389 + $next_step = $this->is_set_upsell_product( $next_step );
1390 +
1391 + wp_send_json_success( [
1392 + 'next_id' => apply_filters( 'wpml_object_id', $next_step['page_id'], 'sellkit_step', true ), // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- WPML API.
1393 + 'next_type' => $next_step['type']['key'],
1394 + ] );
1395 + }
1396 +
1397 + /**
1207 1398 * Perform upsell popup accept button.
1208 1399 *
1209 1400 * @since 1.6.2
1210 1401 */
@@ -1224,29 +1415,62 @@
1224 1415 wp_send_json_error( esc_html__( 'Empty Step Data.', 'sellkit' ) );
1225 1416 }
1226 1417
1227 1418 // Add product to cart.
1228 - $product_id = array_key_first( $upsell_data['data']['products']['list'] );
1229 - $qty = $upsell_data['data']['products']['list'][ $product_id ]['quantity'];
1419 + $product_id = '';
1420 + $qty = '';
1230 1421
1422 + if (
1423 + is_array( $upsell_data['data'] ) &&
1424 + array_key_exists( 'products', $upsell_data['data'] ) &&
1425 + ! empty( $upsell_data['data']['products']['list'] )
1426 + ) {
1427 + $product_id = array_key_first( $upsell_data['data']['products']['list'] );
1428 + $qty = ! empty( $upsell_data['data']['products']['list'][ $product_id ] ) ? $upsell_data['data']['products']['list'][ $product_id ]['quantity'] : 0;
1429 + }
1430 +
1231 1431 if ( empty( $qty ) ) {
1232 1432 $qty = 1;
1233 1433 }
1234 1434
1235 - WC()->cart->add_to_cart( $product_id, $qty );
1236 - // Take care of cart and applied discounts.
1237 - self::apply_discounted_prices( WC()->cart, $checkout_id, 'upsell', $upsell_data );
1238 - self::make_changes_after_cart_item_edit( $checkout_id );
1435 + $added_product_hash = '';
1436 +
1437 + if ( ! in_array( $product_id, array_column( WC()->cart->get_cart(), 'product_id' ), true ) ) {
1438 + $added_product_hash = WC()->cart->add_to_cart( $product_id, $qty );
1439 +
1440 + // Take care of cart and applied discounts.
1441 + self::apply_discounted_prices( WC()->cart, $checkout_id, 'upsell', $upsell_data );
1442 + self::make_changes_after_cart_item_edit( $checkout_id );
1443 + }
1444 +
1239 1445 // Response.
1240 - $funnel = new Sellkit_Funnel( $upsell_id );
1241 - $next_step = $funnel->next_step_data;
1446 + $funnel = new Sellkit_Funnel( $upsell_id );
1447 + $next_step = $funnel->next_step_data;
1448 + $next_step = $this->is_set_upsell_product( $next_step );
1449 + $next_step['type'] = ! empty( $next_step['type'] ) ? (array) $next_step['type'] : null;
1242 1450
1451 + if ( 'upsell' === $funnel->current_step_data['type']['key'] && isset( WC()->cart->cart_contents[ $added_product_hash ] ) ) {
1452 + $analytics_updater = new Data_Updater();
1453 + $total = empty( WC()->cart->cart_contents[ $added_product_hash ]['line_total'] ) ? 0 : WC()->cart->cart_contents[ $added_product_hash ]['line_total'];
1454 +
1455 + $analytics_updater->set_funnel_id( $funnel->funnel_id );
1456 + $analytics_updater->add_new_upsell_revenue_log( $total );
1457 + }
1458 +
1459 + $contact_data = [
1460 + 'key' => $funnel->current_step_data['type']['key'],
1461 + 'page_id' => $funnel->current_step_data['page_id'],
1462 + ];
1463 +
1464 + Base_Contacts::step_is_passed( $contact_data );
1465 +
1243 1466 // Step with empty data, will be redirected to thankyou page.
1244 - if ( empty( $next_step ) ) {
1467 + if ( empty( $next_step ) || empty( $next_step['type'] ) ) {
1245 1468 wp_send_json_success(
1246 1469 [
1247 1470 'next_id' => $funnel->end_node_step_data['page_id'],
1248 1471 'next_type' => $funnel->end_node_step_data['type']['key'],
1472 + 'upsell_prices' => wp_json_encode( self::$sellkit_upsell_products ),
1249 1473 ]
1250 1474 );
1251 1475 }
1252 1476
@@ -1255,10 +1479,11 @@
1255 1479 return;
1256 1480 }
1257 1481
1258 1482 $response = [
1259 - 'next_id' => $next_step['page_id'],
1483 + 'next_id' => apply_filters( 'wpml_object_id', $next_step['page_id'], 'sellkit_step', true ), // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- WPML API.
1260 1484 'next_type' => $next_step['type']['key'],
1485 + 'upsell_prices' => wp_json_encode( self::$sellkit_upsell_products ),
1261 1486 ];
1262 1487
1263 1488 wp_send_json_success( $response );
1264 1489 }
@@ -1276,11 +1501,16 @@
1276 1501 }
1277 1502
1278 1503 $funnel = new Sellkit_Funnel( $upsell_id );
1279 1504 $next_step = $funnel->next_no_step_data;
1505 + $next_step = $this->is_set_upsell_product( $next_step );
1280 1506
1507 + if ( $next_step ) {
1508 + $next_step['type'] = (array) $next_step['type'];
1509 + }
1510 +
1281 1511 // Step with empty data, will be redirected to thankyou page.
1282 - if ( empty( $next_step ) ) {
1512 + if ( empty( $next_step ) || empty( $next_step['type'] ) ) {
1283 1513 wp_send_json_success(
1284 1514 [
1285 1515 'next_id' => $funnel->end_node_step_data['page_id'],
1286 1516 'next_type' => $funnel->end_node_step_data['type']['key'],
@@ -1293,11 +1523,60 @@
1293 1523 return;
1294 1524 }
1295 1525
1296 1526 $response = [
1297 - 'next_id' => $next_step['page_id'],
1527 + 'next_id' => apply_filters( 'wpml_object_id', $next_step['page_id'], 'sellkit_step', true ), // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- WPML API.
1298 1528 'next_type' => $next_step['type']['key'],
1299 1529 ];
1300 1530
1301 1531 wp_send_json_success( $response );
1532 + }
1533 +
1534 + /**
1535 + * Add new item to the WooCommerce order details on the edit page.
1536 + *
1537 + * @param object $order woocommerce order object.
1538 + * @since 1.8.9
1539 + */
1540 + public function add_item_to_order_details( $order ) {
1541 + $order_id = $order->get_id();
1542 + $custom_fields = get_post_meta( $order_id, 'sellkit_checkout_widget_custom_field_of_order', true );
1543 + $current_action = current_action();
1544 +
1545 + if ( empty( $custom_fields ) || ! is_array( $custom_fields ) ) {
1546 + return;
1547 + }
1548 +
1549 + foreach ( $custom_fields as $field ) {
1550 + $key_name = $field['key_name'];
1551 + $label = $field['label'];
1552 +
1553 + // For old users data.
1554 + if ( empty( $label ) ) {
1555 + $label = $key_name;
1556 + $label = str_replace( '_', ' ', $label );
1557 + $label = str_replace( '-', ' ', $label );
1558 + $label = ucwords( $label );
1559 + }
1560 +
1561 + if (
1562 + 'woocommerce_admin_order_data_after_shipping_address' === $current_action &&
1563 + 'shipping' === substr( $key_name, 0, 8 )
1564 + ) {
1565 + ?>
1566 + <h3><?php echo esc_html( $label ); ?></h3>
1567 + <div><?php echo esc_html( get_post_meta( $order_id, $key_name, true ) ); ?></div>
1568 + <?php
1569 + }
1570 +
1571 + if (
1572 + 'woocommerce_admin_order_data_after_billing_address' === $current_action &&
1573 + 'billing' === substr( $key_name, 0, 7 )
1574 + ) {
1575 + ?>
1576 + <h3><?php echo esc_html( $label ); ?></h3>
1577 + <div><?php echo esc_html( get_post_meta( $order_id, $key_name, true ) ); ?></div>
1578 + <?php
1579 + }
1580 + }
1302 1581 }
1303 1582 }