PluginProbe
WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell / 2.8.16
WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell v2.8.16
3.13.3 3.13.2 3.13.1 3.13.0 3.12.13 3.12.12 3.12.11 3.12.10 3.12.9 3.12.8 3.12.7 3.12.6 3.12.5 3.12.4 3.12.3 3.12.1 3.12.2 3.12.0 3.11.1 3.11.0 3.10.9 3.10.8 3.10.7 3.10.6 2.8.16 All 261 releases
wpfunnels / includes / core / rest-api / Controllers / class-funnel-controller.php

class-funnel-controller.php in WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell 2.8.16, at includes/core/rest-api/Controllers/class-funnel-controller.php

1,283 lines 42.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Funnel controller
4 *
5 * @package WPFunnels\Rest\Controllers
6 */
7 namespace WPFunnels\Rest\Controllers;
8
9 use Error;
10 use WP_Error;
11 use WP_REST_Request;
12 use WP_REST_Response;
13 use WPFunnels\Wpfnl_functions;
14 use Wpfnl_Controller_Type_Factory;
15 use WPFunnels\Modules\Admin\Funnel\Module;
16 use WPFunnels\Wpfnl;
17
18 class FunnelController extends Wpfnl_REST_Controller
19 {
20
21 /**
22 * Endpoint namespace.
23 *
24 * @var string
25 */
26 protected $namespace = 'wpfunnels/v1';
27
28 /**
29 * Route base.
30 *
31 * @var string
32 */
33 protected $rest_base = 'funnel-control';
34
35 /**
36 * Check if user has valid permission
37 *
38 * @param $request
39 *
40 * @return bool|WP_Error
41 * @since 1.0.0
42 */
43 public function update_items_permissions_check($request)
44 {
45 if (!Wpfnl_functions::wpfnl_rest_check_manager_permissions( 'steps', 'edit' )) {
46 return new WP_Error('wpfunnels_rest_cannot_edit', __('Sorry, you cannot edit this resource.', 'wpfnl'), ['status' => rest_authorization_required_code()]);
47 }
48 return true;
49 }
50
51 /**
52 * Makes sure the current user has access to READ the settings APIs.
53 *
54 * @param WP_REST_Request $request Full data about the request.
55 *
56 * @return WP_Error|boolean
57 * @since 3.0.0
58 */
59 public function get_items_permissions_check($request)
60 {
61 if (!Wpfnl_functions::wpfnl_rest_check_manager_permissions('settings')) {
62 return new WP_Error('wpfunnels_rest_cannot_view', __('Sorry, you cannot list resources.', 'wpfnl'), ['status' => rest_authorization_required_code()]);
63 }
64 return true;
65 }
66
67
68 /**
69 * Register rest routes
70 *
71 * @since 1.0.0
72 */
73 public function register_routes()
74 {
75 register_rest_route($this->namespace, '/' . $this->rest_base . '/saveFunnel/', [
76 [
77 'methods' => \WP_REST_Server::EDITABLE,
78 'callback' => [
79 $this,
80 'save_funnel_data'
81 ],
82 'permission_callback' => [
83 $this,
84 'update_items_permissions_check'
85 ] ,
86 ],
87 ]);
88
89 register_rest_route($this->namespace, '/' . $this->rest_base . '/getThankyouData/', [
90 [
91 'methods' => \WP_REST_Server::READABLE,
92 'callback' => [
93 $this,
94 'get_thankyou_data'
95 ],
96 'permission_callback' => [
97 $this,
98 'update_items_permissions_check'
99 ] ,
100 ],
101 ]);
102
103 register_rest_route($this->namespace, '/' . $this->rest_base . '/saveConditionalNode/', [
104 [
105 'methods' => \WP_REST_Server::EDITABLE,
106 'callback' => [
107 $this,
108 'save_conditional_node'
109 ],
110 'permission_callback' => [
111 $this,
112 'update_items_permissions_check'
113 ] ,
114 ],
115 ]);
116 register_rest_route($this->namespace, '/' . $this->rest_base . '/getConditionalNode/', [
117 [
118 'methods' => \WP_REST_Server::READABLE,
119 'callback' => [
120 $this,
121 'get_conditional_node'
122 ],
123 'permission_callback' => [
124 $this,
125 'get_items_permissions_check'
126 ] ,
127 ],
128 ]);
129 register_rest_route($this->namespace, '/' . $this->rest_base . '/getFunnel/', [
130 [
131 'methods' => \WP_REST_Server::READABLE,
132 'callback' => [
133 $this,
134 'get_funnel_data'
135 ],
136 'permission_callback' => [
137 $this,
138 'update_items_permissions_check'
139 ],
140 ],
141 ]);
142
143 register_rest_route($this->namespace, '/' . $this->rest_base . '/getStepType/', [
144 [
145 'methods' => \WP_REST_Server::READABLE,
146 'callback' => [
147 $this,
148 'get_step_type'
149 ],
150 'permission_callback' => [
151 $this,
152 'update_items_permissions_check'
153 ] ,
154 ],
155 ]);
156
157 register_rest_route($this->namespace, '/' . $this->rest_base . '/getFunnelInfo/', [
158 [
159 'methods' => \WP_REST_Server::READABLE,
160 'callback' => [
161 $this,
162 'get_funnel_info'
163 ],
164 'permission_callback' => [
165 $this,
166 'update_items_permissions_check'
167 ],
168 ],
169 ]);
170
171
172 register_rest_route($this->namespace, '/' . $this->rest_base . '/exportFunnel/', [
173 [
174 'methods' => \WP_REST_Server::READABLE,
175 'callback' => [
176 $this,
177 'export_funnel'
178 ],
179 'permission_callback' => [
180 $this,
181 'update_items_permissions_check'
182 ] ,
183 ],
184 ]);
185
186 register_rest_route($this->namespace, '/' . $this->rest_base . '/getallfunnels/', array(
187 array(
188 'methods' => \WP_REST_Server::READABLE,
189 'callback' => [
190 $this,
191 'get_all_funnels'
192 ],
193 'permission_callback' => [
194 $this,
195 'update_items_permissions_check'
196 ] ,
197 ),
198 ));
199
200 register_rest_route($this->namespace, '/' . $this->rest_base . '/steps/', array(
201 'args' => array(
202 'funnel_id' => array(
203 'description' => __('Funnel ID.', 'wpfnl'),
204 'type' => 'string',
205 ),
206 'step_id' => array(
207 'description' => __('Step ID.', 'wpfnl'),
208 'type' => 'string',
209 )
210 ),
211 array(
212 'methods' => \WP_REST_Server::EDITABLE,
213 'callback' => [
214 $this,
215 'update_step_meta'
216 ],
217 'permission_callback' => [
218 $this,
219 'update_items_permissions_check'
220 ] ,
221 )
222 ));
223
224
225 register_rest_route($this->namespace, '/' . $this->rest_base . '/get_gbf_data/(?P<funnel_id>\d+)', [
226 [
227 'methods' => \WP_REST_Server::READABLE,
228 'callback' => [
229 $this,
230 'get_GBF_data'
231 ],
232 'permission_callback' => [
233 $this,
234 'update_items_permissions_check'
235 ] ,
236 ],
237 ]);
238
239 register_rest_route($this->namespace, '/' . $this->rest_base . '/get-settings/(?P<step_id>[\d]+)', [
240 [
241 'methods' => \WP_REST_Server::READABLE,
242 'callback' => [
243 $this,
244 'get_ab_settings'
245 ],
246 'permission_callback' => [
247 $this,
248 'update_items_permissions_check'
249 ] ,
250 ],
251 ]);
252
253 register_rest_route(
254 $this->namespace,
255 '/' . $this->rest_base . '/(?P<funnel_id>\d+)/funnel-name-change',
256 array(
257 array(
258 'methods' => \WP_REST_Server::EDITABLE,
259 'callback' => array(
260 $this,
261 'funnel_name_change',
262 ),
263 'permission_callback' => array(
264 $this,
265 'update_items_permissions_check',
266 ),
267 ),
268 )
269 );
270
271 register_rest_route(
272 $this->namespace,
273 '/' . $this->rest_base . '/wpfnl-get-funnel-settings',
274 array(
275 array(
276 'methods' => \WP_REST_Server::EDITABLE,
277 'callback' => array(
278 $this,
279 'wpfnl_get_funnel_settings',
280 ),
281 'args' => array(
282 'funnel_id' => array(
283 'required' => true,
284 'type' => array('integer', 'string'),
285 'sanitize_callback' => 'absint',
286 ),
287 ),
288 'permission_callback' => array(
289 $this,
290 'update_items_permissions_check',
291 )
292 ),
293 )
294 );
295
296 register_rest_route(
297 $this->namespace,
298 '/' . $this->rest_base . '/bulk-delete-funnel',
299 array(
300 array(
301 'methods' => \WP_REST_Server::EDITABLE,
302 'callback' => array(
303 $this,
304 'delete_marked_funnels',
305 ),
306 'permission_callback' => array(
307 $this,
308 'update_items_permissions_check',
309 ),
310 ),
311 )
312 );
313
314 }
315
316 /**
317 * Check if funnel data exists or not
318 **/
319 public function get_all_funnels()
320 {
321 $args = array(
322 'post_type' => 'wpfunnel_steps',
323 'numberposts' => -1
324 );
325 $funnels = get_posts($args);
326
327 if ($funnels) {
328 if (count($funnels) > 0) {
329 return false;
330 }
331 }
332
333 return true;
334 }
335
336
337 /**
338 * Save thankyou data
339 */
340 public function get_thankyou_data($request)
341 {
342 $step_id = $request['step_id'];
343 $data = array();
344 $data['_wpfnl_thankyou_order_overview'] = get_post_meta( $step_id, '_wpfnl_thankyou_order_overview', true ) ? get_post_meta( $step_id, '_wpfnl_thankyou_order_overview', true ) : 'on';
345 $data['_wpfnl_thankyou_order_details'] = get_post_meta( $step_id, '_wpfnl_thankyou_order_details', true ) ? get_post_meta( $step_id, '_wpfnl_thankyou_order_details', true ) : 'on';
346 $data['_wpfnl_thankyou_billing_details'] = get_post_meta( $step_id, '_wpfnl_thankyou_billing_details', true ) ? get_post_meta( $step_id, '_wpfnl_thankyou_billing_details', true ): 'on';
347 $data['_wpfnl_thankyou_shipping_details'] = get_post_meta( $step_id, '_wpfnl_thankyou_shipping_details', true ) ? get_post_meta( $step_id, '_wpfnl_thankyou_shipping_details', true ) : 'on';
348 $data['_wpfnl_thankyou_is_custom_redirect'] = get_post_meta( $step_id, '_wpfnl_thankyou_is_custom_redirect', true ) ? get_post_meta( $step_id, '_wpfnl_thankyou_is_custom_redirect', true ) : 'off';
349 $data['_wpfnl_thankyou_is_direct_redirect'] = get_post_meta( $step_id, '_wpfnl_thankyou_is_direct_redirect', true ) ? get_post_meta( $step_id, '_wpfnl_thankyou_is_direct_redirect', true ) : 'off';
350 $data['_wpfnl_thankyou_set_time'] = get_post_meta( $step_id, '_wpfnl_thankyou_set_time', true ) ? get_post_meta( $step_id, '_wpfnl_thankyou_set_time', true ) : '';
351 $data['_wpfnl_thankyou_custom_redirect_url']= get_post_meta( $step_id, '_wpfnl_thankyou_custom_redirect_url', true ) ? get_post_meta( $step_id, '_wpfnl_thankyou_custom_redirect_url', true ) : '';
352 return $data;
353 }
354
355 /**
356 * Get conditional node
357 *
358 * @param WP_REST_Request $request request.
359 *
360 * @return array|WP_Error
361 */
362 public function get_conditional_node($request)
363 {
364 $funnel_id = $request['funnel_id'];
365 $node_identifier = $request['node_identifier'];
366
367 $data = get_post_meta($funnel_id, $node_identifier, true);
368 $steps = Wpfnl_functions::get_steps( $funnel_id );
369 $optin_step = [];
370 if( is_array($steps) ){
371 foreach( $steps as $step ){
372 if( 'landing' === $step['step_type'] || 'custom' === $step['step_type'] ){
373 $optin_step[] = [
374 'name' => __('Optin form (', 'wpfnl').$step['name'].')',
375 'value' => __('optin_', 'wpfnl').$step['id'],
376 ];
377 }
378 }
379 }
380
381 if ($data) {
382 $response = array(
383 'status' => 'success',
384 'data' => $data,
385 'optinStep' => []
386 );
387
388 } else {
389 $response = array(
390 'status' => 'error',
391 'data' => '',
392 'optinStep' => []
393 );
394 }
395
396 if( !empty($optin_step) ){
397 $response['status'] = 'success';
398 $response['optinStep'] = $optin_step;
399 }
400
401 return $this->prepare_item_for_response($response, $request);
402 }
403
404 /**
405 * Save conditional node
406 *
407 * @param string $request request.
408 *
409 * @return array|WP_Error
410 */
411 public function save_conditional_node($request)
412 {
413 $funnel_id = $request['funnel_id'];
414 $condition_data = $request['condition_data'];
415 $node_identifier = $request['node_identifier'];
416 update_post_meta($funnel_id, $node_identifier, $condition_data);
417 $response = array(
418 'status' => true,
419 );
420 return $this->prepare_item_for_response( $response, $request );
421 }
422
423 /**
424 * Get step_type.
425 *
426 * @param string $request request.
427 *
428 * @return array|WP_Error
429 */
430 public function get_step_type($request)
431 {
432 $step_type = '';
433 $step_id = $request['step_id'];
434 $step_type = get_post_meta($step_id, '_step_type', true);
435 return $step_type;
436 }
437
438 /**
439 * Get the funnel title and link
440 *
441 * @param $request
442 *
443 * @return \WP_REST_Response
444 */
445 public function get_funnel_info( $request )
446 {
447 $funnel_id = $request['funnel_id'];
448 $title = html_entity_decode(get_the_title($funnel_id));
449 $steps = get_post_meta( $funnel_id, '_steps_order', true );
450 $response['success'] = false;
451 if ($steps) {
452 if ( isset($steps[0]) && $steps[0]['id'] ) {
453 $response['link'] = get_post_permalink($steps[0]['id']);
454 $response['title']= $title;
455 $utm_params = $this->get_utm_params( $funnel_id );
456 if($utm_params != '') {
457 $response['link'] = $response['link'].$utm_params;
458 $response['title']= $title;
459 }
460 $response['success'] = true;
461 }
462 }
463 return $this->prepare_item_for_response($response, $request);
464 }
465
466 /**
467 * Retrieves the funnel data based on the provided request.
468 *
469 * @param mixed $request The request data.
470 * @return WP_Rest_Response The prepared funnel data response.
471 *
472 * @since 2.7.17
473 */
474 public function get_funnel_data( $request ) {
475 $funnel_id = isset( $request['funnel_id'] ) ? $request['funnel_id'] : null;
476 $response = [
477 'status' => 'error',
478 'success' => false
479 ];
480 if (!$funnel_id) {
481 return $this->prepare_item_for_response( $response, $request );
482 }
483
484 $response = $this->prepare_funnel_data_response( $funnel_id );
485
486 return $this->prepare_item_for_response( $response, $request );
487 }
488
489 /**
490 * Prepares the response data for the funnel data based on the provided parameters.
491 *
492 * @param int $funnel_id The ID of the funnel.
493 * @param mixed $request The request data.
494 * @return array The prepared response data.
495 *
496 * @since 2.7.17
497 */
498 private function prepare_funnel_data_response( $funnel_id ) {
499 $response = [
500 'status' => 'error',
501 'success' => false
502 ];
503
504 $funnel_data = get_post_meta($funnel_id, 'funnel_data', true);
505 $funnel_identifier = get_post_meta($funnel_id, 'funnel_identifier', true);
506 $_steps_order = get_post_meta( $funnel_id, '_steps', true );
507 $_steps_order = is_array( $_steps_order ) ? $_steps_order : [] ;
508 $status = get_post_status($funnel_id);
509 $title = html_entity_decode(get_the_title($funnel_id));
510 $first_step_id = Wpfnl_functions::get_first_step($funnel_id);
511
512 /**
513 * Fires to modify funnel view link for A/B testing
514 *
515 * @param string $link
516 * @param int $step_id
517 * @param int $funnel_id
518 *
519 * @return string $link
520 * @since 1.7.8
521 */
522 $link = apply_filters('wpfunnels/modify_funnel_view_link', get_post_permalink($first_step_id), $first_step_id, $funnel_id);
523 $response['title'] = $title;
524
525 $utm_settings = Wpfnl_functions::get_funnel_utm_settings( $funnel_id );
526 $view_link = !empty( $response[ 'link' ] ) ? $response[ 'link' ] : $link;
527
528 if ( $utm_settings[ 'utm_enable' ] == 'on' ) {
529 unset( $utm_settings[ 'utm_enable' ] );
530 $view_link = add_query_arg( $utm_settings, $view_link );
531 $view_link = strtolower( $view_link );
532 $utm_settings[ 'utm_enable' ] = 'on';
533 }
534
535 $response['success'] = true;
536 $step_order_data = self::get_steps_order_data($_steps_order);
537 $response['steps_order'] = $step_order_data['steps_order'];
538 $response['is_ob'] = $step_order_data['is_ob'];
539
540 if ( $funnel_data ) {
541 $response = [
542 'status' => 'success',
543 'funnel_data' => $funnel_data,
544 'funnel_identifier' => $funnel_identifier,
545 'steps_order' => isset ( $response['steps_order'] ) ? $response['steps_order'] : [],
546 'funnel_status' => $status,
547 'title' => $title,
548 'link' => $view_link,
549 'is_ob' => isset ( $response['is_ob'] ) ? $response['is_ob'] : false
550 ];
551
552 /**
553 * Fires to update funnel data response in case of A/B Testing
554 *
555 * @param array $response
556 *
557 * @since 1.7.8
558 * @return array $response
559 **/
560 $response = apply_filters('wpfunnels/update_funnel_data_response', $response);
561
562 if ( !empty( $response[ 'ab_data' ] ) ) {
563 $response[ 'ab_data' ] = $this->update_step_view_link_with_utm_params( $response[ 'ab_data' ], $utm_settings );
564 }
565 } elseif ($title && $status) {
566 $response = [
567 'status' => 'scratch-funnel',
568 'title' => $title,
569 'funnel_status' => $status,
570 ];
571 }
572
573 return $response;
574 }
575
576 /**
577 * Updates A/B test variations' step view links with UTM parameters.
578 *
579 * This method takes A/B test data, specifically variations, and appends UTM parameters
580 * to the step view links of each variation. It does so based on the provided UTM settings
581 * if UTM tracking is enabled.
582 *
583 * @param array $ab_data An array containing A/B test data with variations.
584 * @param array $utm_settings An array of UTM parameters and their values.
585 *
586 * @return array The modified A/B test data with UTM parameters appended to step view links.
587 * @since 2.8.14
588 */
589 private function update_step_view_link_with_utm_params( $ab_data, $utm_settings ) {
590 if ( !empty( $ab_data ) && !empty( $utm_settings[ 'utm_enable' ] ) && 'on' === $utm_settings[ 'utm_enable' ] ) {
591 unset( $utm_settings[ 'utm_enable' ] );
592 foreach( $ab_data as $ab_key => $data ) {
593 $variations = $data[ 'data' ][ 'start_settings' ][ 'variations' ] ?? [];
594 if ( !empty( $variations ) ) {
595 foreach( $variations as $var_key => $variation ) {
596 if ( !empty( $variation[ 'step_view_link' ] ) ) {
597 $ab_data[ $ab_key ][ 'data' ][ 'start_settings' ][ 'variations' ][ $var_key ][ 'step_view_link' ] = add_query_arg( $utm_settings, $variation[ 'step_view_link' ] );
598 }
599 }
600 }
601 }
602 }
603 return $ab_data;
604 }
605
606 /**
607 * Get formatted steps order data.
608 *
609 * Formats the steps order data by populating additional fields and determining if any step is an order bump.
610 *
611 * @param array $steps_order The array of funnel steps order.
612 * @return array Formatted steps order data with additional fields and order bump flag.
613 *
614 * @since 2.7.17
615 */
616 private static function get_steps_order_data( $steps_order ) {
617 $is_order_bump = false;
618 $formatted_steps_order = [];
619 foreach ($steps_order as $step) {
620 $step_id = isset( $step['id'] ) ? $step['id'] : null;
621 $_temp_step = $step;
622 $_temp_step['visit'] = 0;
623 $_temp_step['conversion'] = 0;
624 $_temp_step['name'] = get_the_title( $step_id );
625 $_step_type = get_post_meta( $step_id, '_step_type', true );
626 $should_assign_product = in_array($_step_type, ['checkout', 'upsell', 'downsell']) && !get_post_meta( $step_id, '_wpfnl_checkout_products', true);
627
628 if ( 'checkout' === $_step_type ) {
629 $is_order_bump = self::is_order_bump( $step_id );
630 }
631
632 $_temp_step['should_assign_product'] = $should_assign_product;
633 /**
634 * Fires to add Mail Mint automation data
635 *
636 * @param array $step
637 * @param int $step_id
638 * @since 2.7.0
639 */
640 $formatted_steps_order[] = apply_filters('wpfunnels/step_data', $_temp_step, $step_id);
641 }
642
643 return [
644 'steps_order' => $formatted_steps_order,
645 'is_ob' => $is_order_bump
646 ];
647 }
648
649 /**
650 * Checks if a step in the funnel is an order bump.
651 * Retrieves the order bump settings for the specified step and determines if it is an order bump.
652 * @param array $steps_order The array of funnel steps.
653 * @param int $step_id The ID of the step to check.
654 *
655 *
656 * @return bool True if the step is an order bump, false otherwise.
657 * @since 2.7.17
658 *
659 */
660 public static function is_order_bump( $step_id) {
661 $all_settings = get_post_meta($step_id, 'order-bump-settings', true) ?: [];
662 $is_multiple = Wpfnl_functions::check_array_is_multidimentional($all_settings);
663
664 if (!$is_multiple && $all_settings) {
665 $all_settings['name'] = 'Order bump';
666 $all_settings = Wpfnl_functions::migrate_order_bump($all_settings, $step_id);
667 }
668
669 if (is_array($all_settings) && count($all_settings) > 0) {
670 $funnel_id = get_post_meta($step_id, '_funnel_id', true);
671 $type = get_post_meta($funnel_id, '_wpfnl_funnel_type', true) ?: 'wc';
672 $class_object = Wpfnl_Controller_Type_Factory::build($type);
673 if ($class_object) {
674 $all_settings = $class_object->get_ob_settings($all_settings);
675 }
676 }
677
678
679 if (count($all_settings)) {
680 return true;
681 }
682 return false;
683 }
684
685 /**
686 * Get formatted funnel data
687 *
688 * @param $drawflow
689 *
690 * @return mixed
691 *
692 * @since 2.0.5
693 */
694 private function get_formatted_funnel_data( $drawflow ) {
695 if( isset( $drawflow['drawflow']['Home']['data'] ) ) {
696 $drawflow_data = $drawflow['drawflow']['Home']['data'];
697 foreach ( $drawflow_data as $key => $data ) {
698 $step_data = $data['data'];
699 $step_type = $step_data['step_type'];
700 if('conditional' !== $step_type) {
701 $step_id = $step_data['step_id'];
702 $funnel_id = Wpfnl_functions::get_funnel_id_from_step($step_id);
703 if( 'conditional' !== $step_type ) {
704 $edit_post_link = get_edit_post_link( $step_id );
705 $view_link = get_the_permalink( $step_id );
706 $utm_params = $this->get_utm_params( $funnel_id );
707 if($utm_params != '') {
708 $view_link = $view_link.$utm_params;
709 }
710 $title = get_the_title( $step_id );
711 $drawflow['drawflow']['Home']['data'][$key]['data'] = array(
712 'step_edit_link' => base64_encode( $edit_post_link ),
713 'step_id' => $step_id,
714 'step_type' => $step_data['step_type'],
715 'step_view_link' => base64_encode( rtrim( $view_link, '/' ) ),
716 'step_name' => $title,
717 );
718 }
719 }
720 }
721 }
722 return $drawflow;
723 }
724
725 /**
726 * Save funnel data.
727 *
728 * @param string $request request.
729 *
730 * @return array|WP_Error
731 */
732 public function save_funnel_data($request)
733 {
734 $funnel_id = $request[ 'funnel_id' ] ?? null;
735 $funnel_json = $request[ 'funnel_data' ] ?? [];
736 $funnel_identifier = $request[ 'funnel_identifier' ] ?? [];
737 $should_update_steps_order = $request[ 'should_update_steps_order' ] ?? false;
738 $should_update_steps = $request[ 'should_update_steps' ] ?? false;
739 $funnel_data = [];
740 $_steps = [];
741 $response = [ 'success' => true, 'link' => home_url() ];
742
743 if ($funnel_json) {
744 $funnel_data = $funnel_json;
745 $steps = $funnel_data['drawflow']['Home']['data'];
746 foreach ($steps as $key => $step) {
747 if ($step) {
748 $node_data = $step['data'];
749 if (isset($node_data["step_name"])) unset($node_data["step_name"]);
750 $step['data'] = $node_data;
751 $_steps[$key] = $step;
752 }
753 }
754 }
755 $funnel_data['drawflow']['Home']['data'] = apply_filters('wpfunnels/modify_funnel_data', $_steps);
756 update_post_meta($funnel_id, 'funnel_data', $funnel_data);
757 update_post_meta($funnel_id, 'funnel_identifier', $funnel_identifier);
758
759 if( $should_update_steps ) {
760 $steps = $this->get_steps( $funnel_data );
761 update_post_meta( $funnel_id, '_steps', $steps );
762 Wpfnl_functions::generate_first_step( $funnel_id, $steps );
763 }
764
765 $_steps_order = $this->get_steps_order( $funnel_data );
766 $key = array_search('checkout', array_column($_steps_order, 'step_type'));
767 if( false !== $key ){
768 $funnel_type = get_post_meta( $funnel_id, '_wpfnl_funnel_type', true );
769 if( 'lead' === $funnel_type ){
770 if( Wpfnl_functions::is_wc_active() ){
771 update_post_meta( $funnel_id, '_wpfnl_funnel_type', 'wc' );
772 }else{
773 if( Wpfnl_functions::is_lms_addon_active() ){
774 update_post_meta( $funnel_id, '_wpfnl_funnel_type', 'lms' );
775 }
776 }
777 }
778 }
779 if( $should_update_steps_order ) {
780 $steps_order = array();
781 foreach ($_steps_order as $_step){
782 if(count($_step)) {
783 $steps_order[] = $_step;
784 }
785 }
786
787 if(count($steps_order)) {
788 update_post_meta( $funnel_id, '_steps_order', $steps_order );
789
790 } else {
791 delete_post_meta( $funnel_id, '_steps_order' );
792 }
793 }
794
795 $response['step_id'] = Wpfnl_functions::get_first_step( $funnel_id );
796
797 // Fallback for existing users' existing funnel
798 // For new funnel, this condition should not trigger
799 if( !$response['step_id'] ) {
800 Wpfnl_functions::generate_first_step( $funnel_id );
801 $response['step_id'] = Wpfnl_functions::get_first_step( $funnel_id );
802 }
803 $utm_settings = Wpfnl_functions::get_funnel_utm_settings( $funnel_id );
804 $view_link = get_post_permalink( $response['step_id'] );
805
806 if( !empty( $utm_settings['utm_enable'] ) && 'on' === $utm_settings['utm_enable'] ) {
807 unset($utm_settings['utm_enable']);
808 $view_link = add_query_arg($utm_settings,$view_link);
809 $view_link = strtolower($view_link);
810 }
811
812 $response['link'] = esc_url( $view_link );
813
814 $response['funnel_id'] = $funnel_id;
815 $response['success'] = true;
816 $response['funnel_type'] = get_post_meta( $funnel_id, '_wpfnl_funnel_type', true );
817 $response = apply_filters( 'wpfunnels/update_funnel_link', $response );
818 do_action( 'wpfunnels/after_save_funnel_data', $funnel_id );
819 if( isset($request['mintSteps']) ){
820 do_action( 'wpfunnels/save_mint_automation', $funnel_id, $request['mintSteps']);
821 }
822
823 return rest_ensure_response($response);
824 }
825
826
827 /**
828 * Get steps
829 *
830 * @param $funnel_flow_data
831 *
832 * @return array
833 *
834 * @since 2.0.5
835 */
836 private function get_steps( $funnel_flow_data ) {
837 $drawflow = $funnel_flow_data['drawflow'];
838 $steps = array();
839 if( isset( $drawflow['Home']['data'] ) ) {
840 $drawflow_data = $drawflow['Home']['data'];
841 foreach ( $drawflow_data as $key => $data ) {
842 $step_data = $data['data'];
843 if( 'conditional' !== $step_data['step_type'] ) {
844 $step_id = $step_data['step_id'];
845 $step_type = $step_data['step_type'];
846 $step_name = sanitize_text_field(get_the_title($step_data['step_id']));
847 $steps[] = array(
848 'id' => $step_id,
849 'step_type' => $step_type,
850 'name' => $step_name,
851 );
852 }
853 }
854 }
855 return $steps;
856 }
857
858
859 /**
860 * Get steps order
861 *
862 * @param $funnel_flow_data
863 *
864 * @return array
865 *
866 * @since 2.0.5
867 */
868 private function get_steps_order( $funnel_flow_data ) {
869 $drawflow = $funnel_flow_data['drawflow'];
870 $nodes = array();
871 $step_order = array();
872 $first_node_id = '';
873 $start_node = array();
874
875
876 if( isset( $drawflow['Home']['data'] ) ) {
877 $drawflow_data = $drawflow['Home']['data'];
878
879 /**
880 * If has only one step, that only step will be the first step, no conditions should be checked.
881 * just return the step order
882 */
883 if( 1 === count( $drawflow_data ) ) {
884 $node_id = array_keys($drawflow_data)[0];
885 $data = $drawflow_data[$node_id];
886 $step_data = isset( $data['data'] ) ? $data['data'] : array();
887 $step_type = isset( $step_data['step_type'] ) ? $step_data['step_type'] : '';
888 $step_id = isset( $step_data['step_id'] ) ? $step_data['step_id'] : 0;
889 $step_order[] = array(
890 'id' => $step_id,
891 'step_type' => $step_type,
892 'name' => sanitize_text_field( get_the_title( $step_id ) ),
893 );
894 return $step_order;
895
896 }
897
898 /**
899 * First we will find the first node (the node which has only output connection but no input connection will be considered as first node) and the list of nodes array which has the
900 * step information includes output connection and input connection and it will be stored on $nodes
901 */
902 foreach ( $drawflow_data as $key => $data ) {
903 $step_data = $data['data'];
904 $step_type = $step_data['step_type'];
905 $step_id = $step_type !== 'conditional' ? $step_data['step_id'] : 0;
906 if(
907 (isset( $data['outputs']['output_1']['connections'] ) && count( $data['outputs']['output_1']['connections'] ) ) ||
908 (isset( $data['inputs']['input_1']['connections'] ) && count($data['inputs']['input_1']['connections']) )
909 ) {
910
911 if('conditional' === $step_type) {
912 continue;
913 }
914
915 /**
916 * A starting node is a node which has only output connection but not any input connection.
917 * if the step is landing, then there should not be any input connection for this step. so we will only consider the output connection for landing only.
918 * for other step types (checkout, offer, thankyou), we will check if the step has any output connection and no input connection.
919 */
920 if( 'landing' === $step_type ) {
921 if (
922 isset($data['outputs']['output_1']['connections']) && count($data['outputs']['output_1']['connections']) &&
923 (isset( $data['inputs'] ) && count($data['inputs']) == 0 )
924 ) {
925 $start_node = array(
926 'id' => $step_id,
927 'step_type' => $step_type,
928 'name' => sanitize_text_field(get_the_title($step_id)),
929 );
930 }
931 } else {
932 if (
933 isset($data['outputs']['output_1']['connections']) && count($data['outputs']['output_1']['connections']) &&
934 (isset($data['inputs']['input_1']['connections']) && count($data['inputs']['input_1']['connections']) === 0)
935 ) {
936 $start_node = array(
937 'id' => $step_id,
938 'step_type' => $step_type,
939 'name' => sanitize_text_field(get_the_title($step_id)),
940 );
941 } else {
942 $step_order[] = array(
943 'id' => $step_id,
944 'step_type' => $step_type,
945 'name' => sanitize_text_field(get_the_title($step_id)),
946 );
947 }
948 }
949 }
950 }
951 $step_order = $this->array_insert($step_order, $start_node, 0);
952 }
953
954 return $step_order;
955 }
956
957
958 /**
959 * Array insert element on position
960 *
961 * @param $original
962 * @param $inserted
963 * @param int $position
964 *
965 * @return mixed
966 */
967 private function array_insert(&$original, $inserted, $position) {
968 array_splice($original, $position, 0, array($inserted));
969 return $original;
970 }
971
972
973 /**
974 * Export funnel data
975 *
976 * @param $request
977 *
978 * @return false|string
979 *
980 * @since 1.0.0
981 */
982 public function export_funnel($request)
983 {
984 $funnel_id = $request['funnel_id'];
985
986 //===main array of data which will be downloaded as json file===//
987 $data = array();
988
989 $funnel_title = get_the_title($funnel_id);
990 $funnel_meta = get_post_meta($funnel_id);
991
992 //=== Added title and meta of current funnel post===//
993 $data['title'] = $funnel_title;
994 $data['meta'] = $funnel_meta;
995
996 //=== Find list of steps and ther data===//
997 //== Getting steps from identifier meta==//
998 if (isset($data['meta']['funnel_identifier'])) {
999 $identifier_meta = $data['meta']['funnel_identifier'];
1000 $all_steps_array = array();
1001 foreach ($identifier_meta as $identifier_meta_key => $identifier_meta_value) {
1002 $node_step_pair = json_decode($identifier_meta_value, true);
1003 foreach ($node_step_pair as $node_step_pair_key => $node_step_pair_value) {
1004 $current_steps_array = array();
1005 $step_id = $node_step_pair_value;
1006 $step_title = get_the_title($step_id);
1007 $step_meta = get_post_meta($step_id);
1008 $content_post = get_post($step_id);
1009 $content = json_encode($content_post->post_content);
1010 $current_steps_array['step_id'] = $step_id;
1011 $current_steps_array['title'] = $step_title;
1012 $current_steps_array['meta'] = $step_meta;
1013 $current_steps_array['content'] = $content;
1014 $all_steps_array[] = $current_steps_array;
1015 }
1016 }
1017 $data['steps'] = $all_steps_array;
1018 }
1019
1020 return json_encode($data);
1021 }
1022 /**
1023 * Get UTM Params URL
1024 */
1025
1026 public function get_utm_params( $funnel_id ) {
1027 $utm_params = '';
1028 $utm_settings = $this->get_utm_settings( $funnel_id );
1029 $utm_params = '?utm_source='.'fgddffd'.'&utm_medium='.'ghfds'.'&utm_campaign='.'dsaghfds';
1030 return $utm_params;
1031 if($utm_settings['utm_enable'] == 'on') {
1032 $utm_params = '?utm_source='.$utm_settings['utm_source'].'&utm_medium='.$utm_settings['utm_medium'].'&utm_campaign='.$utm_settings['utm_campaign'];
1033 $utm_params .= ((!empty($utm_settings['utm_content'])) ? '&utm_content='.$utm_settings['utm_content'] : '');
1034 $utm_params = strtolower($utm_params);
1035 }
1036 return $utm_params;
1037 }
1038
1039 /**
1040 * Get GTM Settings
1041 *
1042 * @return array
1043 */
1044 public function get_utm_settings( $funnel_id ) {
1045 $default_settings = array(
1046 'utm_enable' => 'off',
1047 'utm_source' => '',
1048 'utm_medium' => '',
1049 'utm_campaign' => '',
1050 'utm_content' => '',
1051 );
1052 $utm_settings = get_post_meta( $funnel_id, '_wpfunnels_utm_params', true );
1053 return wp_parse_args($utm_settings, $default_settings);
1054 }
1055
1056
1057 /**
1058 * Prepare a single setting object for response.
1059 *
1060 * @param object|array $item Setting object.
1061 * @param WP_REST_Request $request Request object.
1062 *
1063 * @return \WP_REST_Response $response Response data.
1064 * @since 1.0.0
1065 */
1066 public function prepare_item_for_response($item, $request)
1067 {
1068 $data = $this->add_additional_fields_to_object($item, $request);
1069 return rest_ensure_response($data);
1070 }
1071
1072
1073 /**
1074 * Get GBF data
1075 *
1076 * @param $request
1077 *
1078 * @return WP_Error|\WP_REST_Response
1079 */
1080 public function get_GBF_data( $request ){
1081
1082 $funnel_id = $request['funnel_id'];
1083 $steps = Wpfnl_functions::get_steps( $funnel_id );
1084
1085 if( !is_plugin_active( 'wpfunnels-pro-gbf/wpfnl-pro-gb.php' ) ){
1086 $response = array(
1087 'success' => false,
1088 'data' => 'Global Funnel is not activated'
1089 );
1090 return rest_ensure_response($response);
1091 }
1092
1093 $is_gbf = get_post_meta( $funnel_id, 'is_global_funnel', true );
1094 if( 'yes' === $is_gbf ){
1095 $start_condition = get_post_meta( $funnel_id, 'global_funnel_start_condition', true );
1096 $step_ids = array();
1097 foreach( $steps as $step ){
1098 if( $step['step_type'] == 'checkout' ){
1099 if( !empty( $start_condition ) ){
1100 array_push($step_ids,$step['id']);
1101 }
1102 }elseif( $step['step_type'] == 'upsell' ){
1103 $upsell_rules = get_post_meta( $step['id'], 'global_funnel_upsell_rules', true );
1104 if( !empty( $upsell_rules ) ){
1105 array_push($step_ids,$step['id']);
1106 }
1107 }elseif( $step['step_type'] == 'downsell' ){
1108 $downsell_rules = get_post_meta( $step['id'], 'global_funnel_downsell_rules', true );
1109 if( !empty( $downsell_rules ) ){
1110 array_push($step_ids,$step['id']);
1111 }
1112 }
1113 }
1114 }
1115 $response = array(
1116 'success' => false,
1117 'data' => []
1118 );
1119 return rest_ensure_response($response);
1120 }
1121
1122
1123 /**
1124 * Get ab testing default setttings
1125 *
1126 * @param WP_REST_Request $request
1127 *
1128 * @return Array
1129 *
1130 * @since 1.6.21
1131 */
1132 public function get_ab_settings( WP_REST_Request $request ){
1133
1134 $response = [];
1135 if( isset( $request['step_id'] ) ){
1136 $step_id = $request['step_id'];
1137 $default_settings = $this->get_default_start_setting( $step_id );
1138 $response['data'] = $default_settings;
1139 $response['success'] = true;
1140 }else{
1141 $response['data'] = '';
1142 $response['success'] = false;
1143 }
1144
1145 return rest_ensure_response( $response );
1146 }
1147
1148 /**
1149 * Change funnel name
1150 *
1151 * @param WP_REST_Request $payload Funnel name payload.
1152 *
1153 * @return array
1154 * @since 2.7.5
1155 */
1156 public function funnel_name_change( $payload ) {
1157 if ( !isset( $payload['funnel_id'], $payload['funnel_name'] ) ) {
1158 return new WP_Error(
1159 'rest_invalid_request_params',
1160 __( 'Invalid request params.' ),
1161 array( 'status' => 404 )
1162 );
1163 }
1164
1165 $funnel_id = sanitize_text_field( $payload['funnel_id'] );
1166 $updated_name = sanitize_text_field( $payload['funnel_name'] );
1167 Wpfnl::$instance->funnel_store->set_id($funnel_id);
1168 Wpfnl::$instance->funnel_store->update_funnel_name($updated_name);
1169 self::update_steps_url_on_funnel_name_update( $funnel_id );
1170 flush_rewrite_rules();
1171
1172 $response = array(
1173 'success' => true,
1174 'message' => 'Funnel name changed successfully',
1175 'funnelID' => $funnel_id,
1176 'name' => $updated_name
1177 );
1178
1179 return rest_ensure_response( $response );
1180 }
1181
1182 /**
1183 * Update the URL and funnel name for each step in a funnel.
1184 *
1185 * This function retrieves the step IDs associated with a specific funnel,
1186 * and updates the URL and funnel name for each step based on the step ID.
1187 *
1188 * @param int $funnel_id The ID of the funnel.
1189 * @return void
1190 * @since 2.7.10
1191 */
1192 public function update_steps_url_on_funnel_name_update( $funnel_id ){
1193 $step_controller = new StepController();
1194 $step_ids = Wpfnl_functions::get_step_ids( $funnel_id );
1195 foreach ( $step_ids as $step_id ) {
1196 $step_title = get_post_meta( $step_id, '_wpf_step_title', true );
1197 $step_slug = get_post_meta( $step_id, '_wpf_step_slug', true );
1198 $settings = array(
1199 'funnel_id' => $funnel_id,
1200 'step_id' => $step_id,
1201 'title' => !empty($step_title) ? $step_title : get_the_title( $step_id ),
1202 'slug' => !empty($step_slug) ? $step_slug : get_post_field('post_name', $step_id)
1203 );
1204 $step_controller->update_step_meta_on_funnel_name_change( $funnel_id, $step_id, $settings );
1205 }
1206 }
1207
1208 /**
1209 * Get funnel settings by funnel id
1210 *
1211 * @param array $payload Funnel Settings payload data.
1212 * @return WP_Rest_Response
1213 *
1214 * @since 1.0.0
1215 */
1216 public function wpfnl_get_funnel_settings( $payload ) {
1217 // Early return in case of missing funnel id.
1218 if ( !isset( $payload['funnel_id'] )){
1219 return $this->prepare_wp_error_response(
1220 'rest_missing_funnelID',
1221 __('Funnel id is missing', 'wpfnl'),
1222 array(
1223 'status' => 400
1224 )
1225 );
1226 }
1227
1228 // To get global settings.
1229 $global_gtm = Wpfnl_functions::get_gtm_settings();
1230 $global_pixel = Wpfnl_functions::get_facebook_pixel_settings();
1231 $settings = Wpfnl_functions::get_funnel_settings( $payload['funnel_id'] );
1232
1233 // Set default skip offer settings.
1234 $skip_settings = array(
1235 'skip_offer' => 'no',
1236 'skip_if_quantity' => 'no',
1237 );
1238
1239 if ( get_post_meta( $payload['funnel_id'], '_wpfunnels_skip_offer', true ) ) {
1240 $skip_settings = get_post_meta( $payload['funnel_id'], '_wpfunnels_skip_offer', true );
1241 }
1242
1243 // Preparing rest response.
1244 $response = array(
1245 'success' => true,
1246 'data' => $settings,
1247 'globalGtm' => isset ( $global_gtm['gtm_enable'] ) ? $global_gtm['gtm_enable'] : 'no',
1248 'globalPixel' => isset ( $global_pixel['enable_fb_pixel'] ) ? $global_pixel['enable_fb_pixel'] : 'no',
1249 'skipSettings' => $skip_settings,
1250 'skipRecurringOffer' => get_post_meta( $payload['funnel_id'], '_wpfunnels_skip_recurring_offer', true ),
1251 'skipRecurringOfferWithinDays' => get_post_meta( $payload['funnel_id'], '_wpfunnels_skip_recurring_offer_within_days', true ),
1252 );
1253
1254 /**
1255 * Fires to get an individual funnel settings.
1256 *
1257 * @since 1.0.0
1258 *
1259 * @param string $response The settings data.
1260 * @param string $payload['funnel_id'] The individual funnel id.
1261 */
1262 $response = apply_filters( 'wpfunnels/funnel_individual_settings', $response, $payload['funnel_id'] );
1263 $response = rest_ensure_response( $response );
1264
1265 return $response;//phpcs:ignore
1266 }
1267
1268 /**
1269 * Delete marked funnel
1270 *
1271 * @param $payload
1272 *
1273 * @return array|bool
1274 * @since 1.0.0
1275 */
1276 public function delete_marked_funnels( $payload ) {
1277 $funnel_controller = Module::instance();
1278
1279 return $funnel_controller->delete_marked_funnels ( $payload );
1280 }
1281
1282 }
1283