PluginProbe
SellKit – Funnel builder and checkout optimizer for WooCommerce to sell more, faster / trunk
SellKit – Funnel builder and checkout optimizer for WooCommerce to sell more, faster vtrunk
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 / global-checkout / class.php

class.php in SellKit – Funnel builder and checkout optimizer for WooCommerce to sell more, faster trunk, at includes/global-checkout/class.php

510 lines 13.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Sellkit\Global_Checkout;
4
5 defined('ABSPATH') || exit;
6
7 use Elementor\Plugin as Elementor;
8 use Sellkit\Funnel\Steps\Checkout as CheckoutStep;
9
10 /**
11 * Checkout.
12 *
13 * @SuppressWarnings(PHPMD.NPathComplexity)
14 * @SuppressWarnings(PHPMD.CyclomaticComplexity)
15 * @SuppressWarnings(PHPMD.UnusedPrivateMethod)
16 * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
17 * @since 1.7.4
18 */
19 class Checkout
20 {
21 const SELLKIT_GLOBAL_CHECKOUT_OPTION = 'sellkit_global_checkout_id';
22 const SELLKIT_GLOBAL_CHECKOUT_HEADER_FOOTER_TEMPLATE = 'sellkit_global_checkout_header_footer_templates';
23
24 /**
25 * Current post ID.
26 *
27 * @since 2.3.0
28 * @var null|integer
29 */
30 public $post_id = null;
31
32 /**
33 * Construct.
34 *
35 * @since 1.7.4
36 */
37 public function __construct()
38 {
39 if (! function_exists('sellkit_pro') || ! sellkit_pro()->is_active_sellkit_pro) {
40 return;
41 }
42
43 add_action('wp', [$this, 'checkout_block_bump_query_var']);
44 add_action('wp', [$this, 'init_sellkit_global_checkout']);
45 add_action('wp_ajax_handle_sellkit_global_checkout_ajax_requests', [$this, 'handle_ajax_requests']);
46 }
47
48 /**
49 * Order bump for sellkit checkout block
50 *
51 * @since 2.3.0
52 */
53 public function checkout_block_bump_query_var()
54 {
55 $global_checkout_id = get_option(self::SELLKIT_GLOBAL_CHECKOUT_OPTION, 0);
56
57 $steps = get_post_meta($global_checkout_id, 'nodes', true);
58 $bump_data = [];
59
60 if (! is_array($steps)) {
61 return;
62 }
63
64 foreach ($steps as $step) {
65 $step['type'] = (array) $step['type'];
66
67 if ('checkout' === $step['type']['key']) {
68 $bump_data = ! empty($step['bump']) ? $step['bump'] : [];
69 }
70 }
71
72 if (! empty($bump_data)) {
73 $bump_data = $this->get_valid_bumps($bump_data);
74
75 set_query_var('bump_data', $bump_data);
76 }
77 }
78
79 /**
80 * Init sellkit global checkout.
81 *
82 * @since 1.7.4
83 */
84 public function init_sellkit_global_checkout()
85 {
86 $global_checkout_id = get_option(self::SELLKIT_GLOBAL_CHECKOUT_OPTION, 0);
87
88 if (
89 0 === $global_checkout_id ||
90 'publish' !== get_post_status((int) $global_checkout_id) ||
91 (function_exists('is_checkout') && ! is_checkout())
92 ) {
93 return;
94 }
95
96 $steps = get_post_meta($global_checkout_id, 'nodes', true);
97 $checkout_id = 0;
98 $bump_data = [];
99 $optimization_data = '';
100 $funnel_id = 0;
101
102 if (! is_array($steps)) {
103 return;
104 }
105
106 foreach ($steps as $step) {
107 $step['type'] = (array) $step['type'];
108
109 if ('checkout' === $step['type']['key']) {
110 $checkout_id = apply_filters('wpml_object_id', $step['page_id'], 'sellkit_step', true); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- WPML API.
111 $bump_data = ! empty($step['bump']) ? $step['bump'] : [];
112 $optimization_data = ! empty($step['data']['optimization']) ? $step['data']['optimization'] : '';
113 $funnel_id = isset($step['funnel_id']) ? $step['funnel_id'] : 0;
114 }
115 }
116
117 $checkout_steps = get_post_meta($checkout_id, 'step_data', true);
118
119 if (empty($funnel_id) && ! empty($checkout_steps)) {
120 $funnel_id = isset($checkout_steps['funnel_id']) ? $checkout_steps['funnel_id'] : 0;
121 }
122
123 if (0 === $checkout_id) {
124 return;
125 }
126
127 // Remove previous content.
128 remove_all_filters('the_content');
129
130 if (defined('ELEMENTOR_VERSION') && 'elementor' === sellkit()->page_builder()) {
131 // Set the page content.
132 add_filter('the_content', function () use ($checkout_id) {
133 ob_Start();
134 $content = Elementor::instance()->frontend->get_builder_content_for_display((int) $checkout_id, true);
135 echo do_shortcode($content);
136 return ob_get_clean();
137 }, 5);
138
139 // Set sellkit canvas templates as the page template.
140 add_action('template_redirect', function () {
141 // Let WooCommerce clear the cart on a successful order-received visit before
142 // our exit prevents its priority-20 hook from ever running.
143 if (function_exists('wc_clear_cart_after_payment')) {
144 wc_clear_cart_after_payment();
145 }
146
147 sellkit()->load_files([
148 'templates/canvas'
149 ]);
150
151 exit;
152 });
153 }
154
155 if ('gutenberg' === sellkit()->page_builder()) {
156 $this->load_checkout_block_frontend();
157
158 $checkout_post = get_post($checkout_id);
159
160 global $post;
161 $post = $checkout_post; // phpcs:ignore:WordPress.WP.GlobalVariablesOverride.OverrideProhibited
162 setup_postdata($post);
163
164 $content = do_blocks($post->post_content);
165
166 $content = apply_filters('the_content', $content); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- WordPress core filter.
167
168 add_filter('the_content', function () use ($content) {
169 ob_Start();
170
171 echo $content; // phpcs:ignore:WordPress.Security.EscapeOutput.OutputNotEscaped
172
173 return ob_get_clean();
174 }, 5);
175
176 // Set sellkit canvas templates as the page template.
177 add_action('template_redirect', function () {
178 // Let WooCommerce clear the cart on a successful order-received visit before
179 // our exit prevents its priority-20 hook from ever running.
180 if (function_exists('wc_clear_cart_after_payment')) {
181 wc_clear_cart_after_payment();
182 }
183
184 sellkit()->load_files([
185 'templates/default-canvas'
186 ]);
187
188 exit;
189 });
190 }
191
192 add_filter('sellkit_global_checkout_activated', function () {
193 return true;
194 });
195
196 add_action('sellkit_checkout_required_hidden_fields', function () use ($checkout_id) {
197 ?>
198 <input type="hidden" name="sellkit_current_page_id" value="<?php echo esc_attr($checkout_id); ?>">
199 <input type="hidden" name="sellkit_global_checkout_id" value="<?php echo esc_attr($checkout_id); ?>">
200 <?php
201 });
202
203 if (! empty($bump_data)) {
204 $bump_data = $this->get_valid_bumps($bump_data);
205
206 set_query_var('bump_data', $bump_data);
207 }
208
209 if (! empty($optimization_data) && CheckoutStep::apply_coupon_validation($optimization_data)) {
210 foreach ($optimization_data['auto_apply_coupons'] as $auto_apply_coupon) {
211 wc()->cart->add_discount(get_the_title($auto_apply_coupon['value']));
212 }
213
214 wc_clear_notices();
215 }
216
217 $header_footer_templates = get_post_meta(intval($funnel_id), self::SELLKIT_GLOBAL_CHECKOUT_HEADER_FOOTER_TEMPLATE, true);
218
219 if (empty($header_footer_templates) || ! is_array($header_footer_templates)) {
220 $header_footer_templates = maybe_unserialize($header_footer_templates);
221 }
222
223 if (empty($header_footer_templates) || ! is_array($header_footer_templates)) {
224 $header_footer_templates = [];
225 }
226
227 add_filter('sellkit_global_checkout_header_applied_id', function ($default) use ($header_footer_templates) {
228 if (
229 array_key_exists('header', $header_footer_templates) &&
230 array_key_exists('value', $header_footer_templates['header'])
231 ) {
232 return $header_footer_templates['header']['value'];
233 }
234
235 return $default;
236 });
237
238 add_filter('sellkit_global_checkout_footer_applied_id', function ($default) use ($header_footer_templates) {
239 if (
240 array_key_exists('footer', $header_footer_templates) &&
241 array_key_exists('value', $header_footer_templates['footer'])
242 ) {
243 return $header_footer_templates['footer']['value'];
244 }
245
246 return $default;
247 });
248 }
249
250 /**
251 * Load checkout block on frontend.
252 *
253 * @since 2.3.0
254 */
255 public function load_checkout_block_frontend()
256 {
257 global $post;
258
259 if (empty($post->post_content)) {
260 return;
261 }
262
263 $this->post_id = $post->ID;
264
265 $block = 'blocks/checkout';
266
267 $block_data = explode('/', $block);
268 $block_name = $block_data[1];
269
270 $class_name = str_replace('-', ' ', $block_name);
271 $class_name = str_replace(' ', '_', ucwords($class_name));
272 $class_name = "Sellkit\blocks\Render\\{$class_name}";
273 $class_path = 'block-editor/' . $block . '/index';
274
275 sellkit()->load_files([
276 $class_path,
277 ]);
278
279 $new_class = new $class_name($this->post_id);
280
281 if (! \WP_Block_Type_Registry::get_instance()->is_registered("sellkit-blocks/{$block_name}")) {
282 $this->register_inner_blocks_by_parent($new_class);
283 $new_class->register_block_meta();
284 }
285 }
286
287 /**
288 * Register inner blocks by parent.
289 *
290 * @param Object $parent_class Parent class name.
291 * @since 2.3.0
292 * @return void
293 */
294 private function register_inner_blocks_by_parent($parent_class)
295 {
296 if (! method_exists($parent_class, 'has_inner_blocks')) {
297 return;
298 }
299
300 $inner_blocks = $parent_class->get_inner_block();
301
302 sellkit()->load_files($inner_blocks);
303
304 foreach ($inner_blocks as $key => $value) {
305 if (isset($this->inner_blocks["blocks/{$key}"])) {
306 continue;
307 }
308
309 $inner_block_class = 'Sellkit\Blocks\Inner_Block\\' . str_replace('-', '_', ucwords($key));
310
311 if (! class_exists($inner_block_class)) {
312 continue;
313 }
314
315 $inner_block_instance = new $inner_block_class($this->post_id);
316 if (! \WP_Block_Type_Registry::get_instance()->is_registered("sellkit-inner-blocks/{$key}")) {
317 $inner_block_instance->register_block_meta();
318 }
319 }
320 }
321
322 /**
323 * Handle ajax requests.
324 *
325 * @since 1.8.9
326 */
327 public function handle_ajax_requests()
328 {
329 check_ajax_referer('sellkit', 'nonce');
330
331 if (! current_user_can('manage_options')) {
332 wp_send_json_error('You do not have access to this section.', 'sellkit');
333 }
334
335 $action = filter_var($_REQUEST['sub_action'], FILTER_SANITIZE_FULL_SPECIAL_CHARS); // phpcs:ignore
336
337 call_user_func([$this, $action]);
338 }
339
340 /**
341 * Get header & footer design templates for Global checkout.
342 *
343 * @since 1.8.9
344 */
345 private function get_design_templates()
346 {
347 $type = filter_input(INPUT_GET, 'template_type', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
348 $search = filter_input(INPUT_GET, 'input_value', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
349
350 $args = [
351 'post_type' => 'elementor_library',
352 'post_status' => ['private', 'publish'],
353 's' => $search,
354 'posts_per_page' => -1,
355 'meta_query' => [ //phpcs:ignore
356 [
357 'key' => '_elementor_template_type',
358 'value' => $type,
359 ],
360 ],
361 ];
362
363 $posts = new \WP_Query($args);
364
365 $values = [
366 [
367 'label' => esc_html__('Default', 'sellkit'),
368 'value' => 'default',
369 ]
370 ];
371
372 if ($posts->post_count > 0) {
373 foreach ($posts->posts as $post) {
374 $values[] = [
375 'label' => $post->post_title,
376 'value' => $post->ID,
377 ];
378 }
379
380 wp_send_json_success($values);
381 }
382
383 wp_send_json_success($values);
384 }
385
386 /**
387 * Save selected header/footer template id ofr the global checkout.
388 *
389 * @since 1.8.9
390 */
391 private function save_selected_template_id()
392 {
393 $funnel_id = filter_input(INPUT_POST, 'funnel', FILTER_SANITIZE_NUMBER_INT);
394 $template_id = filter_input(INPUT_POST, 'template_id', FILTER_DEFAULT, FILTER_FORCE_ARRAY);
395 $template_type = filter_input(INPUT_POST, 'template', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
396 $data = get_post_meta($funnel_id, self::SELLKIT_GLOBAL_CHECKOUT_HEADER_FOOTER_TEMPLATE, true);
397
398 if (empty($data) || ! is_array($data)) {
399 $data = [];
400 }
401
402 if (isset($data[$template_type])) {
403 unset($data[$template_type]);
404 }
405
406 $data[$template_type] = [
407 'label' => (empty($template_id['label'])) ? esc_html__('Search...', 'sellkit') : $template_id['label'],
408 'value' => (empty($template_id['value'])) ? 0 : $template_id['value'],
409 ];
410
411 update_post_meta($funnel_id, self::SELLKIT_GLOBAL_CHECKOUT_HEADER_FOOTER_TEMPLATE, $data);
412
413 wp_send_json_success($data);
414 }
415
416 /**
417 * Get selected header/footer id.
418 *
419 * @since 1.8.9
420 */
421 private function get_selected_template_id()
422 {
423 $funnel_id = filter_input(INPUT_POST, 'funnel', FILTER_SANITIZE_NUMBER_INT);
424 $data = get_post_meta($funnel_id, self::SELLKIT_GLOBAL_CHECKOUT_HEADER_FOOTER_TEMPLATE, true);
425 $template = filter_input(INPUT_POST, 'template', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
426
427 if (empty($data)) {
428 $data = [
429 'header' => [
430 'label' => esc_html__('Search...', 'sellkit'),
431 'value' => 0,
432 ],
433 'footer' => [
434 'label' => esc_html__('Search...', 'sellkit'),
435 'value' => 0,
436 ],
437 ];
438 }
439
440 if (! is_array($data)) {
441 $data = maybe_unserialize($data);
442 }
443
444 wp_send_json_success($data);
445 }
446
447 /**
448 * Create new Elementor template.
449 *
450 * @since 1.8.9
451 */
452 private function create_new_template()
453 {
454 $template = filter_input(INPUT_POST, 'template', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
455 $post_title = filter_input(INPUT_POST, 'post_title', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
456
457 $args = [
458 'post_type' => 'elementor_library',
459 'post_title' => $post_title,
460 'post_status' => 'publish',
461 'meta_input' => [
462 '_elementor_template_type' => $template,
463 '_elementor_edit_mode' => 'builder',
464 'jx-layout-type' => $template,
465 '_wp_page_template' => 'full-width.php',
466 ],
467 ];
468
469 $id = wp_insert_post($args);
470
471 if (intval($id) > 0) {
472 $editor_url = Elementor::$instance->documents->get($id)->get_edit_url();
473
474 wp_send_json_success([
475 'label' => $post_title,
476 'value' => $id,
477 'url' => $editor_url,
478 ]);
479 }
480
481 wp_send_json_error();
482 }
483
484 /**
485 * Checks all bumps and return data.
486 *
487 * @since 1.8.1
488 * @param array $bump_data Bump data.
489 * @return array
490 */
491 public function get_valid_bumps($bump_data)
492 {
493 $valid_bumps = [];
494
495 foreach ($bump_data as $bump) {
496 $conditions = ! empty($bump['data']['conditions']) ? $bump['data']['conditions'] : '';
497
498 if (! empty($conditions) && empty(sellkit_conditions_validation($conditions))) {
499 continue;
500 }
501
502 $valid_bumps[] = $bump;
503 }
504
505 return $valid_bumps;
506 }
507 }
508
509 new Checkout();
510