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 +331 -26 1.6.82.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,15 +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 +
1358 + if ( 'decision' === $next_step['type']['key'] ) {
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.
1360 +
1361 + return;
1362 + }
1363 +
1194 1364 wp_send_json_success( [
1195 - '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.
1196 1366 'next_type' => $next_step['type']['key'],
1197 1367 ] );
1198 1368 }
1199 1369
1200 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 + /**
1201 1398 * Perform upsell popup accept button.
1202 1399 *
1203 1400 * @since 1.6.2
1204 1401 */
@@ -1218,23 +1415,66 @@
1218 1415 wp_send_json_error( esc_html__( 'Empty Step Data.', 'sellkit' ) );
1219 1416 }
1220 1417
1221 1418 // Add product to cart.
1222 - $product_id = array_key_first( $upsell_data['data']['products']['list'] );
1223 - $qty = $upsell_data['data']['products']['list'][ $product_id ]['quantity'];
1419 + $product_id = '';
1420 + $qty = '';
1224 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 +
1225 1431 if ( empty( $qty ) ) {
1226 1432 $qty = 1;
1227 1433 }
1228 1434
1229 - WC()->cart->add_to_cart( $product_id, $qty );
1230 - // Take care of cart and applied discounts.
1231 - self::apply_discounted_prices( WC()->cart, $checkout_id, 'upsell', $upsell_data );
1232 - 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 +
1233 1445 // Response.
1234 - $funnel = new Sellkit_Funnel( $upsell_id );
1235 - $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;
1236 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 +
1466 + // Step with empty data, will be redirected to thankyou page.
1467 + if ( empty( $next_step ) || empty( $next_step['type'] ) ) {
1468 + wp_send_json_success(
1469 + [
1470 + 'next_id' => $funnel->end_node_step_data['page_id'],
1471 + 'next_type' => $funnel->end_node_step_data['type']['key'],
1472 + 'upsell_prices' => wp_json_encode( self::$sellkit_upsell_products ),
1473 + ]
1474 + );
1475 + }
1476 +
1237 1477 if ( 'decision' === $next_step['type']['key'] ) {
1238 1478 $this->take_care_of_decision_step( $next_step['page_id'] );
1239 1479 return;
1240 1480 }
@@ -1239,10 +1479,11 @@
1239 1479 return;
1240 1480 }
1241 1481
1242 1482 $response = [
1243 - '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.
1244 1484 'next_type' => $next_step['type']['key'],
1485 + 'upsell_prices' => wp_json_encode( self::$sellkit_upsell_products ),
1245 1486 ];
1246 1487
1247 1488 wp_send_json_success( $response );
1248 1489 }
@@ -1260,9 +1501,24 @@
1260 1501 }
1261 1502
1262 1503 $funnel = new Sellkit_Funnel( $upsell_id );
1263 1504 $next_step = $funnel->next_no_step_data;
1505 + $next_step = $this->is_set_upsell_product( $next_step );
1264 1506
1507 + if ( $next_step ) {
1508 + $next_step['type'] = (array) $next_step['type'];
1509 + }
1510 +
1511 + // Step with empty data, will be redirected to thankyou page.
1512 + if ( empty( $next_step ) || empty( $next_step['type'] ) ) {
1513 + wp_send_json_success(
1514 + [
1515 + 'next_id' => $funnel->end_node_step_data['page_id'],
1516 + 'next_type' => $funnel->end_node_step_data['type']['key'],
1517 + ]
1518 + );
1519 + }
1520 +
1265 1521 if ( 'decision' === $next_step['type']['key'] ) {
1266 1522 $this->take_care_of_decision_step( $next_step['page_id'] );
1267 1523 return;
1268 1524 }
@@ -1267,11 +1523,60 @@
1267 1523 return;
1268 1524 }
1269 1525
1270 1526 $response = [
1271 - '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.
1272 1528 'next_type' => $next_step['type']['key'],
1273 1529 ];
1274 1530
1275 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 + }
1276 1581 }
1277 1582 }