PluginProbe
SellKit – Funnel builder and checkout optimizer for WooCommerce to sell more, faster / 1.5.4
SellKit – Funnel builder and checkout optimizer for WooCommerce to sell more, faster v1.5.4
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 1.8.1 All 42 releases
sellkit / includes / funnel / steps / checkout.php

checkout.php in SellKit – Funnel builder and checkout optimizer for WooCommerce to sell more, faster 1.5.4, at includes/funnel/steps/checkout.php

347 lines 8.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Sellkit\Funnel\Steps;
4
5 use Sellkit\Funnel\Analytics\Data_Updater;
6 use Sellkit\Funnel\Contacts\Base_Contacts;
7 use Sellkit\Database;
8 use Sellkit_Funnel;
9
10 defined( 'ABSPATH' ) || die();
11
12 /**
13 * Class Sellkit_Checkout.
14 *
15 * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
16 * @since 1.1.0
17 */
18 class Checkout {
19
20 /**
21 * Funnel instance.
22 *
23 * @var Sellkit_Funnel Funnel object.
24 * @since 1.1.0
25 */
26 public $funnel;
27
28 /**
29 * Checkout constructor.
30 *
31 * @since 1.1.0
32 */
33 public function __construct() {
34 $this->update_funnel_data();
35
36 if ( empty( $this->funnel->funnel_id ) ) {
37 return;
38 }
39
40 add_action( 'woocommerce_checkout_create_order', [ $this, 'save_order_custom_meta_data' ], 10 );
41 add_action( 'woocommerce_after_order_notes', [ $this, 'custom_checkout_hidden_fields' ], 10 );
42 add_action( 'wc_ajax_update_order_review', [ $this, 'do_actions' ] );
43 }
44
45 /**
46 * Adding items to the checkout page.
47 *
48 * @since 1.1.0
49 * @SuppressWarnings(PHPMD.NPathComplexity)
50 * @SuppressWarnings(PHPMD.CyclomaticComplexity)
51 */
52 public function do_actions() {
53 // These variables should be used in checkout builder widget.
54 $funnel_data = $this->funnel->current_step_data;
55 $optimization_data = ! empty( $funnel_data['data']['optimization'] ) ? $funnel_data['data']['optimization'] : '';
56 $redirect_url = ! empty( $optimization_data['closed_checkout_redirect_url'] ) ? $optimization_data['closed_checkout_redirect_url'] : site_url();
57
58 add_action( 'template_redirect', function () use ( $funnel_data ) {
59 $product_settings = ! empty( $funnel_data['data']['products']['settings'] ) ? $funnel_data['data']['products']['settings'] : '';
60 $bump_data = ! empty( $funnel_data['bump'] ) ? $funnel_data['bump'] : '';
61
62 if ( ! empty( $product_settings ) ) {
63 set_query_var( 'funnel_product_settings', $product_settings );
64 }
65
66 if ( ! empty( $bump_data ) ) {
67 $bump_data = $this->get_valid_bumps( $bump_data );
68
69 set_query_var( 'bump_data', $bump_data );
70 }
71 } );
72
73 if (
74 ! empty( $optimization_data['expiration_date'] ) &&
75 ! empty( $optimization_data['expire_checkout_coupons_switch'] ) &&
76 time() > $optimization_data['expiration_date'] &&
77 'on' === $optimization_data['expire_checkout_coupons_switch']
78 ) {
79 wp_redirect( $this->add_http_to_url( $redirect_url ) ); // phpcs:ignore
80 exit;
81 }
82
83 if ( empty( $funnel_data ) ) {
84 return;
85 }
86
87 if (
88 empty( $funnel_data['data']['products']['list'] ) ||
89 ! is_array( $funnel_data['data']['products']['list'] )
90 ) {
91 return;
92 }
93
94 $funnel_products = $funnel_data['data']['products']['list'];
95
96 if ( ! sellkit()->has_valid_dependencies() ) {
97 return;
98 }
99
100 $action = sellkit_htmlspecialchars( INPUT_GET, 'wc-ajax' );
101
102 if ( 'update_order_review' !== $action && 'checkout' !== $action ) {
103 wc()->cart->empty_cart();
104
105 foreach ( $funnel_products as $product_id => $product ) {
106 $quantity = ! empty( $product['quantity'] ) ? $product['quantity'] : 1;
107
108 wc()->cart->add_to_cart( $product_id, $quantity );
109 }
110 }
111
112 if ( empty( $optimization_data ) ) {
113 return;
114 }
115
116 if ( self::apply_coupon_validation( $optimization_data ) ) {
117 foreach ( $optimization_data['auto_apply_coupons'] as $auto_apply_coupon ) {
118 wc()->cart->add_discount( get_the_title( $auto_apply_coupon['value'] ) );
119 }
120
121 wc_clear_notices();
122 }
123 }
124
125 /**
126 * Adds http if it is needed.
127 *
128 * @since 1.5.0
129 * @param string $url Entered url.
130 * @return string|boolean
131 */
132 private function add_http_to_url( $url ) {
133 if ( ! preg_match( '~^(?:f|ht)tps?://~i', $url ) ) {
134 return 'http://' . $url;
135 }
136
137 return $url;
138 }
139
140 /**
141 * Saving the funnel data to the order.
142 *
143 * @since 1.1.0
144 * @param object $order Order object.
145 */
146 public function save_order_custom_meta_data( $order ) {
147 if ( empty( $this->funnel->next_step_data ) ) {
148 return;
149 }
150
151 Base_Contacts::step_is_passed();
152 $this->check_bump_acceptance( $order );
153
154 $analytics_updater = new Data_Updater();
155
156 $analytics_updater->set_funnel_id( $this->funnel->funnel_id );
157 $analytics_updater->add_new_order_log( $order );
158
159 $order->update_meta_data( 'sellkit_funnel_next_step_data', $this->funnel->next_step_data );
160 $order->update_meta_data( 'sellkit_funnel_id', $this->funnel->funnel_id );
161 }
162
163 /**
164 * Adding page id field to the inputs.
165 *
166 * @since 1.1.0
167 */
168 public function custom_checkout_hidden_fields() {
169 woocommerce_form_field( 'sellkit_current_page_id', [
170 'type' => 'hidden',
171 'class' => [ 'hidden form-row-wide' ],
172 ], get_the_ID() );
173 }
174
175 /**
176 * Check If a coupon should be applied.
177 *
178 * @since 1.1.0
179 * @param array $optimization_data Optimization data.
180 */
181 public static function apply_coupon_validation( $optimization_data ) {
182 if (
183 empty( $optimization_data['auto_apply_coupons_switch'] ) ||
184 'on' !== $optimization_data['auto_apply_coupons_switch']
185 ) {
186 return false;
187 }
188
189 if (
190 empty( $optimization_data['auto_apply_coupons'] ) ||
191 ! is_array( $optimization_data['auto_apply_coupons'] )
192 ) {
193 return false;
194 }
195
196 return true;
197 }
198
199 /**
200 * Calculate total discount.
201 *
202 * @since 1.1.0
203 * @param string $total Total.
204 * @param string $value Value.
205 * @param string $type Type.
206 * @return false|float|int|mixed
207 */
208 public function calculate_discount( $total, $value, $type ) {
209 if ( empty( $value ) || 1 > $value ) {
210 return 0;
211 }
212
213 if ( strpos( $type, 'fixed' ) !== false ) {
214 return $value;
215 }
216
217 if ( strpos( $type, 'percentage' ) !== false ) {
218 return ( floatval( $total ) * floatval( $value ) ) / 100;
219 }
220
221 return 0;
222 }
223
224 /**
225 * Gets extracted post data.
226 *
227 * @since 1.1.0
228 * @param string $post_data Post data.
229 */
230 private function get_current_page_id_by_post_data( $post_data ) {
231 $vars = explode( '&', $post_data );
232 $extracted_data = [];
233
234 foreach ( $vars as $value ) {
235 $result = explode( '=', urldecode( $value ) );
236 $extracted_data[ $result[0] ] = $result[1];
237 }
238
239 if ( empty( $extracted_data['sellkit_current_page_id'] ) ) {
240 return null;
241 }
242
243 return $extracted_data['sellkit_current_page_id'];
244 }
245
246 /**
247 * Checks all bumps and return data.
248 *
249 * @since 1.1.0
250 * @param array $bump_data Bump data.
251 */
252 public function get_valid_bumps( $bump_data ) {
253 $valid_bumps = [];
254
255 foreach ( $bump_data as $bump ) {
256 $conditions = ! empty( $bump['data']['conditions'] ) ? $bump['data']['conditions'] : '';
257
258 if ( ! empty( $conditions ) && empty( sellkit_conditions_validation( $conditions ) ) ) {
259 continue;
260 }
261
262 $valid_bumps[] = $bump;
263 }
264
265 return $valid_bumps;
266 }
267
268 /**
269 * Checks if bump is accepted during checkout or not and updates table accordingly.
270 *
271 * @param object $order WooCommerce order object.
272 * @return void
273 *
274 * @since 1.5.0
275 * @access private
276 */
277 private function check_bump_acceptance( $order ) {
278 if (
279 empty( $this->funnel->funnel_id ) ||
280 empty( $this->funnel->current_step_data['bump'] )
281 ) {
282 return;
283 }
284
285 $bump_product_ids = [];
286 foreach ( $this->funnel->current_step_data['bump'] as $bump ) {
287 if ( empty( $bump['data']['products'] ) ) {
288 continue;
289 }
290
291 $bump_product_ids = array_merge( $bump_product_ids, array_keys( $bump['data']['products']['list'] ) );
292 }
293
294 $bump_exists_in_order = false;
295
296 foreach ( $order->get_items() as $item ) {
297 $product_id = $item->get_changes()['product_id'];
298
299 if ( in_array( $product_id, $bump_product_ids, true ) ) {
300 $bump_exists_in_order = true;
301 break;
302 }
303 }
304
305 if ( ! $bump_exists_in_order ) {
306 return;
307 }
308
309 $database = new Database();
310 $old_values = [];
311
312 // Getting old data.
313 $result = $database->get( 'funnel_contact', [ 'id' => $_SESSION['entered_funnel_id'] ] );
314
315 if ( ! empty( $result[0]['order_bump'] ) ) {
316 $old_values = unserialize( $result[0]['order_bump'] ); // phpcs:ignore
317 }
318
319 $new_values = array_merge( $old_values, [ $this->funnel->current_step_data['page_id'] ] );
320
321 $database->update(
322 'funnel_contact',
323 [ 'order_bump' => $new_values ],
324 [ 'id' => $_SESSION['entered_funnel_id'] ]
325 );
326 }
327
328 /**
329 * Updates funnel data.
330 *
331 * @since 1.1.0
332 */
333 public function update_funnel_data() {
334 $action = sellkit_htmlspecialchars( INPUT_GET, 'wc-ajax' );
335
336 if ( 'update_order_review' === $action ) {
337 $post_data = sellkit_htmlspecialchars( INPUT_POST, 'post_data' );
338
339 $this->funnel = new Sellkit_Funnel( $this->get_current_page_id_by_post_data( $post_data ) );
340
341 return;
342 }
343
344 $this->funnel = Sellkit_Funnel::get_instance();
345 }
346 }
347