PluginProbe
WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell / 3.13.1
WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell v3.13.1
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 2.8.17 2.8.18 All 259 releases
wpfunnels / includes / core / rest-api / Controllers / class-step-controller.php

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

1,100 lines 39.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Step controller
4 *
5 * @package WPFunnels\Rest\Controllers
6 */
7
8 namespace WPFunnels\Rest\Controllers;
9
10 use WP_Error;
11 use WP_REST_Request;
12 use WP_REST_Response;
13 use WPFunnels\Metas\Wpfnl_Step_Meta_keys;
14 use WPFunnels\Wpfnl;
15 use WPFunnels\Wpfnl_functions;
16 use WPFunnels\TemplateLibrary\Manager;
17 use Elementor\Plugin;
18 class StepController 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 = 'steps';
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, '/' . 'funnels/(?P<funnel_id>[\d\.]+)/' . $this->rest_base . '/(?P<step_id>[\d\.]+)/metadata', array(
76 array(
77 'methods' => \WP_REST_Server::EDITABLE,
78 'args' => array(
79 'funnel_id' => array(
80 'validate_callback' => function($param, $request, $key) {
81 return is_numeric( $param );
82 }
83 ),
84 'step_id' => array(
85 'validate_callback' => function($param, $request, $key) {
86 return is_numeric( $param );
87 }
88 )
89 ),
90 'callback' => [
91 $this,
92 'save_step_metadata'
93 ],
94 'permission_callback' => [
95 $this,
96 'update_items_permissions_check'
97 ],
98 )
99 ));
100
101 register_rest_route(
102 $this->namespace,
103 '/' . $this->rest_base . '/(?P<step_id>[\d\.]+)/delete-step',
104 array(
105 'methods' => \WP_REST_Server::DELETABLE,
106 'callback' => array(
107 $this,
108 'delete_step',
109 ),
110 'permission_callback' => array(
111 $this,
112 'update_items_permissions_check',
113 ),
114 ),
115 );
116
117 register_rest_route(
118 $this->namespace,
119 '/' . $this->rest_base . '/create-step',
120 array(
121 array(
122 'methods' => \WP_REST_Server::EDITABLE,
123 'callback' => array(
124 $this,
125 'create_step',
126 ),
127 'permission_callback' => array(
128 $this,
129 'update_items_permissions_check',
130 ),
131 ),
132 )
133 );
134
135 register_rest_route(
136 $this->namespace,
137 '/' . $this->rest_base . '/wpfunnel-import-step',
138 array(
139 array(
140 'methods' => \WP_REST_Server::EDITABLE,
141 'callback' => array(
142 $this,
143 'import_step',
144 ),
145 'permission_callback' => array(
146 $this,
147 'update_items_permissions_check',
148 ),
149 ),
150 )
151 );
152
153 register_rest_route(
154 $this->namespace, '/' . $this->rest_base . '/update-conditional-status',
155 array(
156 array(
157 'methods' => \WP_REST_Server::EDITABLE,
158 'callback' => array(
159 $this,
160 'update_conditional_status',
161 ),
162 'permission_callback' => array(
163 $this,
164 'update_items_permissions_check',
165 ),
166 'args' => array(
167 'stepId' => array(
168 'description' => __('Funnel step ID.', 'wpfnl'),
169 'type' => 'integer',
170 'required' => true
171 ),
172 'status' => array(
173 'description' => __('Condition status.', 'wpfnl'),
174 'type' => 'string',
175 'required' => true
176 ),
177 ),
178 ),
179 )
180 );
181
182 register_rest_route(
183 $this->namespace, '/' . $this->rest_base . '/get-conditions',
184 array(
185 array(
186 'methods' => \WP_REST_Server::READABLE,
187 'callback' => array(
188 $this,
189 'get_conditions',
190 ),
191 'permission_callback' => array(
192 $this,
193 'update_items_permissions_check',
194 ),
195 'args' => array(
196 'stepId' => array(
197 'description' => __('Funnel step ID.', 'wpfnl'),
198 'type' => 'integer',
199 'required' => true
200 )
201 ),
202 ),
203 )
204 );
205
206 register_rest_route(
207 $this->namespace, '/' . $this->rest_base . '/save-condition',
208 array(
209 array(
210 'methods' => \WP_REST_Server::EDITABLE,
211 'callback' => array(
212 $this,
213 'save_condition',
214 ),
215 'permission_callback' => array(
216 $this,
217 'update_items_permissions_check',
218 ),
219 'args' => array(
220 'stepId' => array(
221 'description' => __('Funnel step ID.', 'wpfnl'),
222 'type' => 'integer',
223 'required' => true
224 ),
225 'conditions' => array(
226 'description' => __('Funnel step ID.', 'wpfnl'),
227 'type' => 'array',
228 'required' => true
229 ),
230 ),
231 ),
232 )
233 );
234
235 register_rest_route(
236 $this->namespace, '/' . $this->rest_base . '/paste-step',
237 array(
238 array(
239 'methods' => \WP_REST_Server::EDITABLE,
240 'callback' => array(
241 $this,
242 'paste_step',
243 ),
244 'permission_callback' => array(
245 $this,
246 'update_items_permissions_check',
247 ),
248 'args' => array(
249 'stepId' => array(
250 'description' => __('Funnel step ID.', 'wpfnl'),
251 'type' => 'integer',
252 'required' => true
253 ),
254 'funnelId' => array(
255 'description' => __('Funnel ID.', 'wpfnl'),
256 'type' => 'integer',
257 'required' => true
258 )
259 ),
260 ),
261 )
262 );
263 }
264
265 /**
266 * Responsible to create a single step of funnels
267 *
268 * @param WP_REST_Request $payload Data from request.
269 *
270 * @return array
271 * @since 1.0.0
272 */
273 public function create_step($payload)
274 {
275 if (!isset($payload['funnel_id'], $payload['step_type'])) {
276 return $this->prepare_wp_error_response(
277 'rest_invalid_request',
278 __('Invalid rest request.', 'wpfnl'),
279 array('status' => 400)
280 );
281 }
282
283 $funnel_id = $payload['funnel_id'];
284 $step_type = $payload['step_type'];
285 $step_name = isset($payload['step_name']) ? $payload['step_name'] : $step_type;
286 $funnel = Wpfnl::get_instance()->funnel_store;
287 $step = Wpfnl::get_instance()->step_store;
288 $step_id = $step->create_step($funnel_id, $step_name, $step_type);
289
290 $step->set_id($step_id);
291
292 if (!$step_id || is_wp_error($step_id)) {
293 return $this->prepare_wp_error_response(
294 'rest_step_create_failed',
295 __('Failed to create a step', 'wpfnl'),
296 array('status' => 400)
297 );
298 }
299
300 $funnel->set_id($funnel_id);
301 $step_edit_link = get_edit_post_link($step_id);
302 $step_view_link = get_post_permalink($step_id);
303 $response = array(
304 'success' => true,
305 'step_id' => $step_id,
306 'step_edit_link' => $step_edit_link,
307 'step_view_link' => rtrim($step_view_link, '/'),
308 'step_title' => $step->get_title(),
309 'conversion' => 0,
310 'visit' => 0,
311 'shouldShowAnalytics' => false,
312 'abTestingSettingsData' => [],
313 );
314
315 if (isset($payload['lastClickedAddStep'])) {
316 $reconfigureSettings = get_post_meta($funnel->get_id(), '_wpfnl_reconfigurable_condition_data', true);
317 if (is_array($reconfigureSettings) && !empty($reconfigureSettings)) {
318 $key = array_search($payload['lastClickedAddStep'], array_column($reconfigureSettings, 'nodeId'));
319 if (false !== $key) {
320 $reconfigureSettings[$key]['step_id'] = $step_id;
321 update_post_meta($funnel->get_id(), '_wpfnl_reconfigurable_condition_data', $reconfigureSettings);
322 $response['reconfigureSettings'] = $reconfigureSettings;
323 update_post_meta($step_id, '_wpfnl_maybe_enable_condition', $reconfigureSettings[$key]['is_enable']);
324 }
325 }
326 }
327
328 return rest_ensure_response($response);
329 }
330
331
332 /**
333 * Update step meta fields
334 *
335 * @param WP_REST_Request $request
336 * @return WP_Error|\WP_HTTP_Response|WP_REST_Response
337 * @since 3.0.14
338 */
339 public function save_step_metadata(\WP_REST_Request $request)
340 {
341 $params = $request->get_params();
342 $funnel_id = isset($params['funnel_id']) ? intval($params['funnel_id']) : 0;
343 $step_id = isset($params['step_id']) ? intval($params['step_id']) : 0;
344
345 if (!$funnel_id) {
346 wp_send_json_error(array(
347 'success' => false,
348 'message' => __('Invalid funnel id is provided.', 'wpfnl')
349 ));
350 }
351
352 if (WPFNL_STEPS_POST_TYPE !== get_post_type( $step_id )) {
353 wp_send_json_error(array(
354 'success' => false,
355 'message' => __('Invalid step id is provided.', 'wpfnl')
356 ));
357 }
358
359 $is_slug_available = Wpfnl_functions::is_slug_available($params['slug'], $step_id, $params['title']);
360
361 if (!$is_slug_available) {
362 wp_send_json_error(array(
363 'success' => false,
364 'message' => __('Slug must be unique', 'wpfnl')
365 ));
366 }
367
368 $result = $this->update_step_name( $funnel_id, $step_id, $params );
369 $step_type = Wpfnl_functions::get_step_type($step_id);
370 $default_meta = Wpfnl_functions::get_step_default_meta($step_type);
371
372 Wpfnl_Step_Meta_keys::save_meta($step_id, $params, $default_meta);
373
374 return rest_ensure_response(array(
375 'success' => true,
376 'post_title' => $result['post_title'],
377 'permalink' => $result['permalink'],
378 'funnel_main_link' => $result['funnel_main_link'],
379 'slug' => $result['slug'],
380 'message' => __('Saved Successfully', 'wpfnl')
381 ));
382 }
383
384
385 /**
386 * Update the step name and step slug. This will also impact the drawflow data to update the step name
387 * and slug which is saved under funnel.
388 *
389 * @param $funnel_id
390 * @param $step_id
391 * @param $metadata
392 * @return array
393 *
394 * @since 3.0.14
395 */
396 public function update_step_name( $funnel_id, $step_id, $metadata ) {
397 $step_title = isset( $metadata['title'] ) ? sanitize_text_field( $metadata['title'] ) : '';
398 $step_slug = isset( $metadata['slug'] ) ? sanitize_title( $metadata['slug'] ) : '';
399 $parent_id = get_post_meta($step_id, '_parent_step_id', true);
400
401 wp_update_post([
402 "ID" => $step_id,
403 "post_title" => $step_title,
404 "post_name" => $step_slug,
405 ]);
406
407 if ( defined('WPFNL_PRO_VERSION') ) {
408 do_action('wpfunnels/before_update_step_meta', $step_id, $funnel_id, $metadata);
409 }
410 else {
411 if (isset($metadata['title'], $metadata['slug'])) {
412 $steps = Wpfnl_functions::get_steps($funnel_id);
413 foreach ($steps as $key => $step) {
414 if ( $step['id'] == $step_id ) {
415 $steps[$key]['name'] = $metadata['title'];
416 }
417 }
418 update_post_meta( $funnel_id, '_steps_order', $steps );
419 }
420 }
421
422 if ($step_id == $parent_id || !$parent_id) {
423 $funnel_data = get_post_meta($funnel_id, '_funnel_data', true);
424 if (isset($funnel_data['drawflow']['Home']['data']) and is_array($funnel_data['drawflow']['Home']['data'])) {
425
426 foreach ($funnel_data['drawflow']['Home']['data'] as $key => $data) {
427 if (isset($data['data']['step_id']) && (int)$step_id === (int)$data['data']['step_id']) {
428 $edit_post_link = base64_encode(get_edit_post_link($step_id));
429 $view_link = base64_encode(get_the_permalink($step_id));
430 $funnel_data['drawflow']['Home']['data'][$key]['data']['step_view_link'] = $view_link;
431 $funnel_data['drawflow']['Home']['data'][$key]['data']['step_edit_link'] = $edit_post_link;
432 }
433 }
434 update_post_meta($funnel_id, '_funnel_data', $funnel_data);
435 }
436
437 $funnel_data = get_post_meta($funnel_id, 'funnel_data', true);
438 if (isset($funnel_data['drawflow']['Home']['data']) and is_array($funnel_data['drawflow']['Home']['data'])) {
439 foreach ($funnel_data['drawflow']['Home']['data'] as $key => $data) {
440 if (isset($data['data']['step_id']) && (int)$step_id === (int)$data['data']['step_id']) {
441 $edit_post_link = base64_encode(get_edit_post_link($step_id));
442 $view_link = base64_encode(get_the_permalink($step_id));
443 $funnel_data['drawflow']['Home']['data'][$key]['data']['step_view_link'] = $view_link;
444 $funnel_data['drawflow']['Home']['data'][$key]['data']['step_edit_link'] = $edit_post_link;
445 }
446 }
447 update_post_meta($funnel_id, 'funnel_data', $funnel_data);
448 }
449 }
450
451 $first_step_id = Wpfnl_functions::get_first_step($funnel_id);
452 $utm_settings = Wpfnl_functions::get_funnel_utm_settings($funnel_id);
453 $view_link = get_post_permalink($first_step_id);
454
455 if (!empty($utm_settings['utm_enable']) && 'on' === $utm_settings['utm_enable']) {
456 unset($utm_settings['utm_enable']);
457 $view_link = add_query_arg($utm_settings, $view_link);
458 $view_link = strtolower($view_link);
459 }
460
461 return array(
462 'post_title' => $step_title,
463 'permalink' => rtrim(get_the_permalink($step_id), '/'),
464 'funnel_main_link' => esc_url($view_link),
465 'slug' => sanitize_title($step_slug),
466 );
467 }
468
469
470
471 /**
472 * Common function to update step meta
473 *
474 * @param WP_REST_Request $request
475 *
476 * @return \WP_REST_Response
477 *
478 * @since 2.7.10
479 */
480 public static function update_step_meta_on_funnel_name_change($funnel_id, $step_id, $settings)
481 {
482 if (is_plugin_active('wpfunnels-pro/wpfnl-pro.php') && Wpfnl_functions::is_pro_license_activated()) {
483 /**
484 * Fires to update step slug on ab testing variation on funnel name change
485 *
486 * @param int $step_id The ID of the step.
487 * @param int $funnel_id The ID of the funnel to which the step belongs.
488 * @param array $settings An array of settings containing the title and slug for the step.
489 * @since 2.7.0
490 *
491 */
492 do_action('wpfunnels/before_update_step_meta_on_funnel_name_change', $step_id, $funnel_id, $settings);
493 } else {
494 if (isset($settings['funnel_id'], $settings['step_id'], $settings['title'], $settings['slug'])) {
495 $steps = Wpfnl_functions::get_steps($settings['funnel_id']);
496 if (!empty($steps)) {
497 foreach ($steps as $key => $step) {
498 if ($step['id'] == $settings['step_id']) {
499 $steps[$key]['name'] = $settings['title'];
500 }
501 }
502 }
503 update_post_meta($settings['funnel_id'], '_steps_order', $steps);
504 wp_update_post([
505 "ID" => $step_id,
506 "post_title" => wp_strip_all_tags($settings['title']),
507 "post_name" => sanitize_title($settings['slug']),
508 ]);
509 }
510 }
511 }
512
513
514 /**
515 * Delete step and all its data
516 *
517 * @param WP_REST_Request $payload Data from request.
518 *
519 * @return array
520 *
521 * @since 2.7.9
522 */
523 public function delete_step($payload)
524 {
525 if (!isset ($payload['step_id'])) {
526 return $this->prepare_wp_error_response(
527 'rest_invalid_stepID',
528 __('Invalid Step ID.', 'wpfnl'),
529 array('status' => 404)
530 );
531 }
532
533
534 $step_id = sanitize_text_field($payload['step_id']);
535 $step_type = get_post_meta($step_id, '_step_type', true);
536
537 $result = [
538 'success' => true,
539 ];
540
541 if (!empty($payload['nodeId'])) {
542 $is_enable = Wpfnl_functions::maybe_enable_condition($step_id);
543 $condiitons = Wpfnl_functions::get_conditions($step_id);
544 $next_step = Wpfnl_functions::get_conditional_next_step($step_id);
545 $funnel_id = Wpfnl_functions::get_funnel_id_from_step($step_id);
546 $data = get_post_meta($funnel_id, '_wpfnl_reconfigurable_condition_data', true);
547
548 if (!is_array($data) || empty($data)) {
549 $data = [];
550 } else {
551 $key = array_search($payload['nodeId'], array_column($data, 'nodeId'));
552 if (false !== $key) {
553 unset($data[$key]);
554 }
555 }
556
557 $is_enable_condition = get_post_meta($step_id, '_wpfnl_maybe_enable_condition', true);
558
559 if (!empty($payload['stepId']) && !empty($payload['nodeType']) && 'addstep' !== $payload['nodeType']) {
560 update_post_meta($payload['stepId'], '_wpfnl_maybe_enable_condition', $is_enable_condition);
561 }
562
563 $updatedData = [
564 'step_id' => !empty($payload['nodeType']) && 'addstep' !== $payload['nodeType'] && !empty($payload['stepId']) ? $payload['stepId'] : '',
565 'nodeId' => $payload['nodeId'],
566 'is_enable' => $is_enable_condition,
567 'conditions' => get_post_meta($step_id, '_wpfnl_step_conditions', true),
568 'next_step' => get_post_meta($step_id, '_wpfnl_next_step_after_condition', true),
569 ];
570
571 array_push($data, $updatedData);
572
573 update_post_meta($funnel_id, '_wpfnl_reconfigurable_condition_data', $data);
574 $result['reconfigurable_condition_data'] = $data;
575 }
576
577
578 /**
579 * Delete the automation data linked with the step
580 *
581 * @param int $step_id Step ID.
582 * @since 2.7.0
583 *
584 */
585 do_action('wpfunnels/before_delete_step', $step_id); //phpcs:ignore
586
587 $response = $this->prepare_wp_error_response(
588 'rest_invalid_stepID',
589 __('Invalid Step ID.', 'wpfnl'),
590 array('status' => 404)
591 );
592
593 if ($step_type) {
594 $response = $this->delete_regular_step($step_id);
595 } else if ($step_id) { // For conditional step.
596 $response = $this->conditional_step_response($step_id);
597 }
598
599 $result['response'] = $response;
600 return $result;
601 }
602
603 /**
604 * Delete a regular step and all its data.
605 *
606 * @param int $step_id The ID of the regular step to be deleted.
607 *
608 * @return array The response containing the success status and message.
609 *
610 * @since 2.7.9
611 */
612 private function delete_regular_step($step_id)
613 {
614 if (!$step_id) {
615 return $this->prepare_wp_error_response(
616 'rest_invalid_stepID',
617 __('Invalid Step ID.', 'wpfnl'),
618 array('status' => 404)
619 );
620 }
621
622 $step = new Wpfnl::$instance->step_store();
623 $step->read($step_id);
624
625 $funnel_id = $step->get_funnel_id();
626 $delete_result = $step->delete($step_id);
627 $funnel = Wpfnl::$instance->funnel_store;
628 $funnel->read($funnel_id);
629
630 if ($delete_result) {
631 return $this->prepare_wp_success_response('Step deleted successfully', 200);
632 }
633
634 $response = $this->prepare_wp_error_response(
635 'rest_delete_failure',
636 __('Failed to delete step.', 'wpfnl'),
637 array('status' => 500)
638 );
639
640 return $response;
641 }
642
643 /**
644 * Response for deleting a conditional step.
645 *
646 * @param int $step_id The ID of the conditional step to be deleted.
647 *
648 * @return array The response indicating the success of the deletion.
649 *
650 * @since 2.7.9
651 */
652 private function conditional_step_response($step_id)
653 {
654 if (!$step_id) {
655 return $this->prepare_wp_error_response(
656 'rest_invalid_stepID',
657 __('Invalid Step ID.', 'wpfnl'),
658 array('status' => 404)
659 );
660 }
661
662 return $this->prepare_wp_success_response('Conditional step deleted successfully', 200);
663 }
664
665
666 /**
667 * Prepare a single setting object for response.
668 *
669 * @param object $item Setting object.
670 * @param WP_REST_Request $request Request object.
671 *
672 * @return \WP_REST_Response $response Response data.
673 * @since 1.0.0
674 */
675 public function prepare_item_for_response($item, $request)
676 {
677 $data = $this->add_additional_fields_to_object($item, $request);
678 return rest_ensure_response($data);
679 }
680
681 /**
682 * Import wp funnel steps from remote servers.
683 *
684 * @param array $payload
685 *
686 * @return array
687 * @since 1.0.0
688 */
689 public function import_step($payload)
690 {
691 $manager_class = new Manager();
692 $source = $manager_class->get_source(!empty($payload['source']) ? $payload['source'] : 'remote');
693 return $source->import_step($payload);
694 }
695
696
697 /**
698 * Update conditional status for a step.
699 *
700 * This function updates the conditional status for a specific step based on the provided
701 * step ID and status in the request. It checks for required parameters, sanitizes input,
702 * and updates the corresponding post meta with the new status.
703 *
704 * @param WP_REST_Request $request The REST request object containing parameters.
705 *
706 * @return \WP_REST_Response The REST response indicating the success of the operation.
707 * @since 2.9.0
708 *
709 */
710 public function update_conditional_status($request)
711 {
712 $required_params = array('stepId', 'status');
713
714 // Check if all required parameters are present in the request.
715 foreach ($required_params as $param) {
716 if (!$request->has_param($param)) {
717 return rest_ensure_response($this->prepare_wp_error_response(
718 __("Required parameter '$param' is missing.", 'wpfnl'), 400
719 ));
720 }
721 }
722
723 // Get the step ID and status from the request.
724 $step_id = sanitize_text_field($request['stepId']);
725 $status = sanitize_text_field($request['status']);
726
727 if (!$step_id) {
728 return rest_ensure_response($this->prepare_wp_error_response(
729 __("Required parameter step id is empty.", 'wpfnl'), 400
730 ));
731 }
732
733 // Update the conditional status post meta.
734 update_post_meta($step_id, '_wpfnl_maybe_enable_condition', $status);
735
736 $funnel_id = get_post_meta($step_id, '_funnel_id', true);
737 $reconfigureSettings = get_post_meta($funnel_id, '_wpfnl_reconfigurable_condition_data', true);
738 if (is_array($reconfigureSettings) && !empty($reconfigureSettings)) {
739 $key = array_search($step_id, array_column($reconfigureSettings, 'step_id'));
740 if (false !== $key) {
741 unset($reconfigureSettings[$key]);
742 update_post_meta($funnel_id, '_wpfnl_reconfigurable_condition_data', $reconfigureSettings);
743 }
744 }
745
746 // Return a REST response indicating success.
747 return rest_ensure_response(['success' => true]);
748 }
749
750
751 /**
752 * Get conditional status and conditions for a step.
753 *
754 * This function retrieves the conditional status and associated conditions for a specific step
755 * based on the provided step ID in the request. It checks for required parameters, sanitizes input,
756 * and returns the conditional status, along with the array of conditions.
757 *
758 * @param WP_REST_Request $request The REST request object containing parameters.
759 *
760 * @return \WP_REST_Response The REST response containing the conditional status and conditions.
761 * @since 2.9.0
762 *
763 */
764 public function get_conditions($request)
765 {
766 $required_params = array('stepId');
767
768 // Check if all required parameters are present in the request.
769 foreach ($required_params as $param) {
770 if (!isset($request[$param])) {
771 return rest_ensure_response($this->prepare_wp_error_response(
772 __("Required parameter '$param' is missing.", 'wpfnl'), 400
773 ));
774 }
775 }
776
777 // Get the step ID from the request.
778 $step_id = sanitize_text_field($request['stepId']);
779
780 if (!$step_id) {
781 return rest_ensure_response($this->prepare_wp_error_response(
782 __("Required parameter step id is empty.", 'wpfnl'), 400
783 ));
784 }
785
786 // Retrieve the conditional status from the post meta.
787 $status = get_post_meta($step_id, '_wpfnl_maybe_enable_condition', true);
788
789 // Prepare the response array.
790 $response = [
791 'success' => true,
792 ];
793
794 // Set default status if not available.
795 if (!$status) {
796 $status = 'no';
797 }
798 $response['status'] = $status;
799
800 // Retrieve step conditions from post meta.
801 $conditions = get_post_meta($step_id, '_wpfnl_step_conditions', true);
802
803 // Ensure conditions are available as an array.
804 if (!is_array($conditions) || !$conditions) {
805 $conditions = [];
806 }
807 $response['conditions'] = $conditions;
808
809
810 $afterCondition = get_post_meta($step_id, '_wpfnl_next_step_after_condition', true);
811 if (!is_array($afterCondition) || !$afterCondition) {
812 $afterCondition = [];
813 }
814
815 $response['afterCondition'] = $afterCondition;
816
817 // Return a REST response with the status and conditions.
818 return rest_ensure_response($response);
819 }
820
821
822 /**
823 * Save conditional status and conditions for a step.
824 *
825 * This function handles the saving of conditional status and associated conditions for a specific step
826 * based on the provided step ID in the request. It checks for required parameters, sanitizes input,
827 * and updates the post meta with the conditions and after-condition values.
828 *
829 * @param WP_REST_Request $request The REST request object containing parameters.
830 *
831 * @return \WP_REST_Response The REST response indicating the success of the operation.
832 * @since 2.9.0
833 *
834 */
835 public function save_condition($request)
836 {
837 $required_params = array('stepId', 'conditions');
838
839 // Check if all required parameters are present in the request.
840 foreach ($required_params as $param) {
841 if (!isset($request[$param])) {
842 return rest_ensure_response($this->prepare_wp_error_response(
843 __("Required parameter '$param' is missing.", 'wpfnl'), 400
844 ));
845 }
846 }
847
848 $step_id = sanitize_text_field($request['stepId']);
849 $conditions = filter_var_array($request['conditions']);
850
851 $afterCondition = filter_var_array(isset($request['afterCondition']) ? $request['afterCondition'] : []);
852
853 if (!$step_id) {
854 return rest_ensure_response($this->prepare_wp_error_response(
855 __("Required parameter step id is empty.", 'wpfnl'), 400
856 ));
857 }
858
859 // Update post meta with the conditions and after-condition values.
860 update_post_meta($step_id, '_wpfnl_step_conditions', $conditions);
861 update_post_meta($step_id, '_wpfnl_next_step_after_condition', $afterCondition);
862
863 // Prepare the response array.
864 $response = [
865 'success' => true,
866 ];
867
868 $funnel_id = get_post_meta($step_id, '_funnel_id', true);
869 $reconfigureSettings = get_post_meta($funnel_id, '_wpfnl_reconfigurable_condition_data', true);
870 if (is_array($reconfigureSettings) && !empty($reconfigureSettings)) {
871 $key = array_search($step_id, array_column($reconfigureSettings, 'step_id'));
872 if (false !== $key) {
873 unset($reconfigureSettings[$key]);
874 update_post_meta($funnel_id, '_wpfnl_reconfigurable_condition_data', $reconfigureSettings);
875 }
876 }
877
878 // Return a REST response indicating the success of the operation.
879 return rest_ensure_response($response);
880 }
881
882
883 /**
884 * Paste a step and all its data to create a new step.
885 * This function creates a new step by duplicating an existing step and updating the post meta with the new step information.
886 *
887 * @param WP_REST_Request $request The REST request object containing parameters.
888 *
889 * @return \WP_REST_Response The REST response indicating the success of the operation.
890 *
891 * @since 3.4.16
892 */
893 public function paste_step($request){
894 $required_params = array('stepId','funnelId');
895
896 // Check if all required parameters are present in the request.
897 foreach ($required_params as $param) {
898 if (!isset($request[$param])) {
899 return rest_ensure_response(
900 $this->prepare_wp_error_response( 400,
901 sprintf(__("Required parameter '%s' is missing.", 'wpfnl'), $param), ''
902 )
903 );
904 }
905 }
906 $parent_step_id = sanitize_text_field($request['stepId']);
907 $funnel_id = sanitize_text_field($request['funnelId']);
908 // Clone the parent step to create a new step.
909 $response = $this->clone_parent_step( $parent_step_id, $funnel_id );
910 if( !$response ){
911 return rest_ensure_response($this->prepare_wp_error_response( 400,
912 __("Failed to duplicate a step", 'wpfnl'), ''
913 ));
914 }
915 $step_id = isset($response['step_id']) ? $response['step_id'] : '';
916 $step = isset($response['step']) ? $response['step'] : '';
917 // Duplicate step metadata for this step.
918 $this->duplicate_all_meta( $step, $parent_step_id, $step_id, $funnel_id );
919
920 $builder = Wpfnl_functions::get_builder_type();
921 // Clear elementor cache
922 $this->clear_elementor_cache( $step_id, $builder );
923 // Get the step view link with UTM
924 $view_link = $this->get_step_view_link_with_utm( $step_id, $funnel_id );
925 /**
926 * Fires after duplicating an A/B testing step in WP Funnels.
927 *
928 * @param int $step_id The ID of the duplicated step.
929 * @param string $builder The name of the builder used for the duplication.
930 */
931 do_action('wpfunnels_after_ab_testing_duplicate', $step_id, $builder);
932 /**
933 * Fires after a step is duplicated in a funnel.
934 *
935 * @param int $funnel_id The ID of the funnel.
936 * @param int $step_id The ID of the duplicated step.
937 */
938 do_action('wpfunnels/after_step_duplicate', $funnel_id, $step_id );
939 $response = $this->prepare_response_for_paste_step( $step_id, $response, $view_link );
940 if( !$response ){
941 return rest_ensure_response($this->prepare_wp_error_response( 400,
942 __("Failed to duplicate a step", 'wpfnl'), ''
943 ));
944 }
945 return $response;
946 }
947
948 /**
949 * Prepare API response for paste step.
950 *
951 * @param int $step_id The ID of the step.
952 * @param array $response The response data.
953 * @param string $view_link The view link of the step.
954 *
955 * @return array The response data.
956 *
957 * @throws \WPFunnels\TemplateLibrary\Wpfnl_Source_Remote
958 *
959 * @since 3.4.16
960 */
961 public function prepare_response_for_paste_step( $step_id, $response, $view_link ){
962
963 if( !$step_id ){
964 return false;
965 }
966
967 // Create an instance of remote class.
968 $remote = new \WPFunnels\TemplateLibrary\Wpfnl_Source_Remote();
969
970 return [
971 'success' => true,
972 'stepID' => $step_id,
973 'step_name' => isset($response['title']) ? $response['title'] : '',
974 'step_type' => isset($response['step_type']) ? $response['step_type'] : '',
975 'stepEditLink' => get_edit_post_link($step_id),
976 'stepViewLink' => $view_link,
977 'abTestingSettingsData'=> $remote->get_default_start_setting($step_id),
978 ];
979 }
980
981 /**
982 * Create a new step by duplicating an existing step.
983 *
984 * @param int $parent_step_id The ID of the parent step.
985 * @param int $funnel_id The ID of the funnel.
986 *
987 * @return array The response data.
988 *
989 * @since 3.4.16
990 */
991 public function clone_parent_step( $parent_step_id, $funnel_id ) {
992 if( !$parent_step_id || !$funnel_id ) {
993 return false;
994 }
995
996 $title = get_the_title($parent_step_id);
997 $page_template = get_post_meta($parent_step_id, '_wp_page_template', true);
998 $step_type = get_post_meta($parent_step_id, '_step_type', true);
999 $post_content = get_post_field('post_content', $parent_step_id);
1000
1001 // Create an instance of the step store.
1002 $step = new \WPFunnels\Data_Store\Wpfnl_Steps_Store_Data();
1003
1004 $step_id = $step->create_step($funnel_id, $title, $step_type, $post_content, true);
1005
1006 if( !$step_id ){
1007 return false;
1008 }
1009 // Update the step meta data.
1010 $step->update_meta($step_id, '_funnel_id', $funnel_id);
1011
1012 return [
1013 'step' => $step,
1014 'step_id' => $step_id,
1015 'title' => $title,
1016 'step_type' => $step_type,
1017 'page_template' => $page_template,
1018 ];
1019 }
1020
1021
1022 /**
1023 * Duplicate all the meta data for a step.
1024 *
1025 * @param object $step The step object.
1026 * @param int $parent_step_id The ID of the parent step.
1027 * @param int $step_id The ID of the step.
1028 * @param int $funnel_id The ID of the funnel.
1029 *
1030 * @since 3.4.16
1031 */
1032 public function duplicate_all_meta( $step, $parent_step_id, $step_id, $funnel_id ) {
1033 if( !$parent_step_id || !$step_id || !$funnel_id ) {
1034 return;
1035 }
1036
1037 // Create an instance of the funnel store.
1038 $funnel = new \WPFunnels\Data_Store\Wpfnl_Funnel_Store_Data();
1039 $funnel->duplicate_all_meta( $parent_step_id, $step_id, array('_funnel_id','_is_duplicate','wpfnl_mint_automation_id') );
1040
1041 /**
1042 * Save the new step information on funnel data and funnel identifier.
1043 * This is required to show steps in funnel canvas
1044 */
1045
1046 $funnel->update_step_id_in_funnel_data_and_identifier($parent_step_id, $step_id, $funnel_id);
1047 $step->update_meta($step_id, '_is_duplicate', 'yes');
1048 }
1049
1050 /**
1051 * Clear elememtor cache and remove the cache for the step.
1052 * This is required to clear the cache for the step when it is duplicated.
1053 *
1054 * @param int $step_id The ID of the step.
1055 * @param string $builder The name of the builder.
1056 *
1057 * @since 3.4.16
1058 */
1059 public function clear_elementor_cache( $step_id, $builder ) {
1060 if( !$step_id || 'elementor' === $builder) {
1061 return;
1062 }
1063
1064 $step_edit_link = get_edit_post_link($step_id);
1065
1066 $step_edit_link = str_replace(['&amp;', 'edit'], ['&', 'elementor'], $step_edit_link);
1067 if ( is_plugin_active( 'elementor/elementor.php' ) && class_exists( '\Elementor\Plugin' ) ) {
1068 Plugin::$instance->files_manager->clear_cache(); // Clearing cache of Elementor CSS.
1069 }
1070
1071 }
1072
1073 /**
1074 * Get step view link with UTM.
1075 *
1076 * @param int $step_id The ID of the step.
1077 * @param int $funnel_id The ID of the funnel.
1078 *
1079 * @return string The view link of the step.
1080 *
1081 * @since 3.4.16
1082 */
1083 public function get_step_view_link_with_utm( $step_id, $funnel_id ) {
1084 if( !$step_id ||!$funnel_id ) {
1085 return '';
1086 }
1087
1088 $view_link = get_post_permalink( $step_id );
1089 $utm_settings = Wpfnl_functions::get_funnel_utm_settings($funnel_id);
1090
1091 if ( is_array($utm_settings) && isset($utm_settings[ 'utm_enable' ]) && 'on' === $utm_settings[ 'utm_enable' ] ) {
1092 unset( $utm_settings[ 'utm_enable' ] );
1093 $view_link = add_query_arg( $utm_settings, $view_link );
1094 $view_link = strtolower( $view_link );
1095 }
1096
1097 return $view_link;
1098 }
1099 }
1100