PluginProbe
WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell / 3.13.3
WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell v3.13.3
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 / data-store / class-wpfnl-store-funnel-data.php

class-wpfnl-store-funnel-data.php in WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell 3.13.3, at includes/core/data-store/class-wpfnl-store-funnel-data.php

704 lines 19.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Store funnel data
4 *
5 * @package
6 */
7 namespace WPFunnels\Data_Store;
8
9 use Elementor\Plugin;
10 use WP_Error;
11 use WPFunnels\Wpfnl_functions;
12
13 class Wpfnl_Funnel_Store_Data extends Wpfnl_Abstract_Store_data implements Wpfnl_Data_Store
14 {
15 protected $id = 0;
16
17 protected $funnel_name;
18
19 protected $published_date;
20
21 protected $data;
22
23 protected $steps_order = [];
24
25 protected $nr_steps = 0;
26
27 protected $status;
28
29 protected $step_ids = [];
30
31 protected $first_step_id = 0;
32
33 protected $first_step_type;
34
35 protected $current_step_id;
36
37 /**
38 * Create funnel. This will create funnel without steps
39 *
40 * @param string $funnel_name
41 *
42 * @return int|\WP_Error
43 *
44 * @since 1.0.0
45 */
46 public function create( $funnel_name = '' )
47 {
48 $funnel_id = wp_insert_post(
49 apply_filters(
50 'wpfunnels/wpfunnels_new_funnel_params',
51 [
52 'post_type' => WPFNL_FUNNELS_POST_TYPE,
53 'post_status' => 'publish',
54 'post_title' => $funnel_name ? wp_strip_all_tags( $funnel_name ) : 'New Funnel',
55 ]
56 ),
57 true
58 );
59 if ($funnel_id && ! is_wp_error($funnel_id)) {
60
61 // Provisional type only — callers that know the funnel's real type
62 // (create_funnel, the template importer) overwrite this straight after.
63 if( Wpfnl_functions::is_wc_active() ){
64 update_post_meta( $funnel_id, '_wpfnl_funnel_type', 'wc' );
65 }else{
66 update_post_meta( $funnel_id, '_wpfnl_funnel_type', 'lms' );
67 }
68 $this->set_id($funnel_id);
69 }
70
71 do_action( 'wpfunnels_after_funnel_creation', $funnel_id );
72 return $funnel_id;
73 }
74
75
76 /**
77 * Clone funnel with all the
78 * steps and meta data
79 * derived from https://rudrastyh.com/wordpress/duplicate-post.html
80 *
81 * @since 1.0.0
82 */
83 public function clone_funnel()
84 {
85 global $wpdb;
86 $funnel_id = wp_insert_post(
87 apply_filters(
88 'wpfunnels/wpfunnels_new_funnel_params',
89 [
90 'post_title' => wp_strip_all_tags($this->get_funnel_name()).' - Copy',
91 'post_type' => WPFNL_FUNNELS_POST_TYPE,
92 'post_status' => 'publish',
93 ]
94 ),
95 true
96 );
97 $parent_id = $this->get_id();
98 $funnel_data = $this->get_meta($this->get_id(), '_funnel_data');
99 $funnel_identifier = $this->get_meta($this->get_id(), 'funnel_identifier');
100 $funnel_identifier_to_string = preg_replace('/\: *([0-9]+\.?[0-9e+\-]*)/', ':"\\1"', $funnel_identifier);
101 $funnel_identifier_json_to_data = json_decode($funnel_identifier_to_string, true);
102 $exclude_meta = array( '_is_imported', '_steps_order', '_steps', '_funnel_data', 'wpfnls_is_newui_migrated','wpfnl_mint_automation_id' );
103 $compoare_step_ids = array();
104
105 foreach ($funnel_identifier_json_to_data as $funnel_identifier_key => $funnel_identifier_value) {
106 $identifier_data = get_post_meta( $parent_id, $funnel_identifier_value, true );
107 if ($identifier_data) {
108 $exclude_meta[] = $funnel_identifier_value;
109 $this->update_meta($funnel_id, $funnel_identifier_value, $identifier_data);
110 }
111 }
112
113 $this->duplicate_all_meta( $this->get_id(), $funnel_id, $exclude_meta, true );
114 $this->update_meta($funnel_id, '_funnel_data', $funnel_data);
115 $this->update_meta($funnel_id, 'funnel_data', $funnel_data);
116 $this->update_meta($funnel_id, 'funnel_identifier', $funnel_identifier);
117
118
119 if ($funnel_id && ! is_wp_error($funnel_id)) {
120 $step_order = $this->get_order();
121 $this->set_step_ids();
122 $_new_step_ids = [];
123 foreach ($step_order as $order) {
124 if (Wpfnl_functions::check_if_module_exists($order['id'])) {
125 if ($this->check_if_step_in_funnel($order['id'])) {
126 $sql_query_sel = [];
127 $_step_id = $order['id'];
128 $title = get_the_title($_step_id);
129 $page_template = get_post_meta($_step_id, '_wp_page_template', true);
130 $post_content = get_post_field('post_content', $_step_id);
131
132 $step = new Wpfnl_Steps_Store_Data();
133 $step_id = $step->create_step($funnel_id, $title, $order['step_type'], $post_content, true);
134
135 $compoare_step_ids[$_step_id] = $step_id;
136 $builder = Wpfnl_functions::get_builder_type();
137
138 $_new_step_ids[] = [
139 'id' => $step_id,
140 'step_type' => $order['step_type'],
141 'name' => $order['name'],
142 ];
143 $step->update_meta($step_id, '_funnel_id', $funnel_id);
144 $this->duplicate_all_meta( $_step_id, $step_id, array('_funnel_id','_is_duplicate','wpfnl_mint_automation_id') );
145
146 /**
147 * Save the new step information on funnel data and funnel identifier.
148 * This is required to show steps in funnel canvas
149 */
150
151 $this->update_step_id_in_funnel_data_and_identifier($_step_id, $step_id, $funnel_id);
152
153 delete_post_meta($step_id, '_wp_page_template');
154 $step->update_meta($step_id, '_wp_page_template', $page_template);
155 $step->update_meta($step_id, '_is_duplicate', 'yes');
156
157 $step_edit_link = get_edit_post_link($step_id);
158 if( 'elementor' === Wpfnl_functions::get_builder_type() ){
159 $step_edit_link = str_replace(['&amp;', 'edit'], ['&', 'elementor'], $step_edit_link);
160 if ( is_plugin_active( 'elementor/elementor.php' ) && class_exists( '\Elementor\Plugin' ) ) {
161 Plugin::$instance->files_manager->clear_cache(); // Clearing cache of Elementor CSS.
162 }
163 }
164
165 /**
166 * Fires after duplicating an A/B testing step in WP Funnels.
167 *
168 * @param int $step_id The ID of the duplicated step.
169 * @param string $builder The name of the builder used for the duplication.
170 */
171 do_action('wpfunnels_after_ab_testing_duplicate', $step_id, $builder);
172
173
174 /**
175 * Fires after a step is duplicated in a funnel.
176 *
177 * @param int $funnel_id The ID of the funnel.
178 * @param int $step_id The ID of the duplicated step.
179 *
180 * @since 3.1.0
181 */
182 do_action('wpfunnels/after_step_duplicate', $funnel_id, $step_id );
183
184 }
185 }
186 }
187 $_new_step_ids = array_values(array_filter($_new_step_ids));
188 $this->update_meta( $funnel_id, '_steps', $_new_step_ids );
189 $this->update_meta( $funnel_id, '_steps_order', $_new_step_ids );
190
191 }
192 //duplicate funnel automation event settings
193 $this->duplicate_automation_event_settings( $parent_id , $funnel_id , $compoare_step_ids );
194 do_action( 'wpfunnels/after_save_funnel_data', $funnel_id );
195 Wpfnl_functions::generate_first_step( $funnel_id, [] );
196 return $funnel_id;
197 }
198
199
200 /**
201 * Duplicate all meta key and values
202 *
203 * @param $parent_id
204 * @param $post_id
205 * @param array $exclude_meta
206 * @param bool $raw
207 */
208 public function duplicate_all_meta( $parent_id, $post_id, $exclude_meta = array(), $raw = false ) {
209 global $wpdb;
210 $exclude_sql = '';
211 if( !empty($exclude_meta) ) {
212 $metas = implode("', '",$exclude_meta );
213 $exclude_sql = "AND meta_key NOT IN ('".$metas."')";
214 }
215 $post_meta_infos = $wpdb->get_results("SELECT meta_key, meta_value FROM $wpdb->postmeta WHERE (post_id=$parent_id {$exclude_sql})");
216 if (count($post_meta_infos)!=0) {
217 $insert_sql_query = "INSERT INTO $wpdb->postmeta (post_id, meta_key, meta_value) VALUES";
218 $sql_query_arr = [];
219 foreach ($post_meta_infos as $meta_info) {
220 $meta_key = $meta_info->meta_key;
221
222 if( '_wp_old_slug' === $meta_key) continue;
223 if( 'funnel_automation_data' === $meta_key ) continue;
224
225 if ( '_wpfnl_ab_testing_start_settings' === $meta_key ){
226 $meta_value = get_post_meta( $parent_id, $meta_key,true );
227
228 $variations = isset( $meta_value['variations'] ) ? $meta_value['variations'] : array();
229
230 $step = new Wpfnl_Steps_Store_Data();
231 for ($i = 0; $i < count($variations); $i++){
232
233 $id = isset( $variations[$i]['stepId'] ) ? $variations[$i]['stepId'] : 0;
234 $title = isset( $variations[$i]['stepName'] ) ? $variations[$i]['stepName'] : '' ;
235 $step_type = isset( $variations[$i]['stepType'] ) ? $variations[$i]['stepType'] : '' ;
236 $post_content = get_post_field('post_content', $id);
237
238 if (isset($variations[$i]['variationType']) && 'original' === $variations[$i]['variationType']){
239 $step_id = $post_id;
240 }else {
241
242 $step_id = $step->create_step($post_id, $title, $step_type, $post_content, true);
243 // If step can't be created, continue to try creating next variation
244 if ( !$step_id || $step_id instanceof WP_Error ){
245 continue;
246 }
247
248 $this->duplicate_elementor_step_meta( $id, $step_id);
249 $this->duplicate_product_data_for_each_step($step_type, $id, $step_id);
250 $this->duplicate_all_meta( $id, $step_id, array('_wpfnl_ab_testing_start_settings') );
251 update_post_meta($step_id, '_parent_step_id', $post_id);
252
253 // Get the funnel id from variation parent step id
254 $funnel_id = Wpfnl_functions::get_funnel_id_from_step( $post_id );
255 update_post_meta($step_id, '_funnel_id', $funnel_id);
256 }
257 $this->update_step_id_in_funnel_data_and_identifier($id, $step_id, $post_id);
258
259 $meta_value['variations'][$i]['stepId'] = $step_id;
260 $meta_value['variations'][$i]['stepEditLink'] = get_edit_post_link($step_id);
261 $meta_value['variations'][$i]['stepViewLink'] = get_post_permalink($step_id);
262
263 }
264
265 update_post_meta($post_id, $meta_key, $meta_value);
266
267 continue;
268 }
269
270 if ( $raw ) {
271 $meta_value = get_post_meta( $parent_id, $meta_key,true );
272
273 update_post_meta($post_id, $meta_key, $meta_value);
274 }
275
276 $sql_query_arr[] = $wpdb->prepare( '( %d, %s, %s )', $post_id, $meta_key, $meta_info->meta_value );
277
278 }
279
280 if (!$raw) {
281 $insert_sql_query .= implode( ',', $sql_query_arr );
282 $wpdb->query( $insert_sql_query );
283 }
284 }
285 }
286
287
288
289 /**
290 * Duplicate automation event settings
291 *
292 * @param String $parent_id
293 * @param String $post_id
294 * @param Array $compoare_step_ids
295 */
296 private function duplicate_automation_event_settings( $parent_id , $post_id, $compoare_step_ids ){
297
298 $prev_settings = get_post_meta( $parent_id , 'funnel_automation_data', true );
299
300 if( $prev_settings ){
301 foreach( $prev_settings as $key => $settings ){
302 foreach( $settings['triggers'] as $index => $trigger ){
303 if( $prev_settings[$key]['triggers'][$index][0]['type'] == 'offer' ){
304
305 $prev_settings[$key]['triggers'][$index][0]['event'] = str_replace($prev_settings[$key]['triggers'][$index][0]['stepID'],$compoare_step_ids[$prev_settings[$key]['triggers'][$index][0]['stepID']],$prev_settings[$key]['triggers'][$index][0]['event']);
306 $prev_settings[$key]['triggers'][$index][0]['stepID'] = $compoare_step_ids[$prev_settings[$key]['triggers'][$index][0]['stepID']];
307 }
308 }
309 }
310 update_post_meta( $post_id, 'funnel_automation_data', $prev_settings );
311 }
312 }
313
314 /**
315 * Duplicate Meta of Each Step related to Elementor style
316 *
317 * @param int $id parent id
318 * @param int $new_id duplicated id
319 *
320 * @since 2.7.7
321 */
322 public function duplicate_elementor_step_meta($id, $new_id){
323 $meta_keys = array(
324 '_elementor_edit_mode',
325 '_elementor_template_type',
326 '_elementor_version',
327 '_elementor_data',
328 '_elementor_page_assets',
329 '_elementor_css'
330 );
331
332 foreach ($meta_keys as $meta_key) {
333 $meta_value = get_post_meta($id, $meta_key, true);
334 update_post_meta($new_id, $meta_key, $meta_value);
335 }
336 }
337
338 /**
339 * Duplicate Meta of Each Step related to Woo-products
340 *
341 * @param string $type step type
342 * @param int $id parent id
343 * @param int $new_id duplicated id
344 *
345 * @since 2.7.7
346 */
347 public function duplicate_product_data_for_each_step($type, $id, $new_id){
348 $meta_fields = [
349 'checkout' => [
350 '_wpfnl_checkout_products',
351 '_wpfnl_checkout_discount_main_product',
352 'order-bump-settings',
353 '_wpfnl_checkout_coupon',
354 '_wpfnl_checkout_collapsible_coupon',
355 '_wpfnl_multiple_product',
356 '_wpfnl_quantity_support',
357 'wpfnl_checkout_billing_fields',
358 'wpfnl_checkout_shipping_fields',
359 'wpfnl_checkout_additional_fields',
360 '_wpfunnels_edit_field_additional_settings',
361 ],
362 'upsell' => [
363 '_wpfnl_upsell_products',
364 '_wpfnl_upsell_discount',
365 '_wpfnl_upsell_replacement_settings',
366 '_wpfnl_upsell_replacement',
367 ],
368 'downsell' => [
369 '_wpfnl_downsell_products',
370 '_wpfnl_downsell_discount',
371 '_wpfnl_downsell_replacement_settings',
372 '_wpfnl_downsell_replacement',
373 ],
374 'thankyou' => [
375 '_wpfnl_thankyou_order_overview',
376 '_wpfnl_thankyou_order_details',
377 '_wpfnl_thankyou_billing_details',
378 '_wpfnl_thankyou_shipping_details',
379 '_wpfnl_thankyou_is_custom_redirect',
380 '_wpfnl_thankyou_is_direct_redirect',
381 '_wpfnl_thankyou_set_time',
382 '_wpfnl_thankyou_custom_redirect_url'
383 ]
384 ];
385
386 if ( isset($meta_fields[$type] )) {
387 foreach ( $meta_fields[$type] as $meta_key ) {
388 $meta_value = get_post_meta($id, $meta_key, true);
389 update_post_meta($new_id, $meta_key, $meta_value);
390 }
391 }
392 }
393
394
395 /**
396 * Update funnel data and funnel
397 * window for canvas
398 *
399 * @param $prev_step_id
400 * @param $new_step
401 * @param $funnel_id
402 *
403 * @since 2.0.0
404 */
405 public function update_step_id_in_funnel_data_and_identifier($prev_step_id, $new_step, $funnel_id)
406 {
407 $funnel_identifier = array();
408 $funnel_json = get_post_meta($funnel_id, '_funnel_data', true);
409 $funnel_data = array();
410 if ($funnel_json) {
411 $funnel_data = $funnel_json;
412 $node_data = $funnel_data['drawflow']['Home']['data'];
413 foreach ($node_data as $node_key => $node_value) {
414 if(isset($node_value['data']['step_id'])) {
415 if ($node_value['data']['step_id'] == $prev_step_id) {
416 $post_edit_link = base64_encode(get_edit_post_link($new_step));
417 $post_view_link = base64_encode(get_post_permalink($new_step));
418 $funnel_data['drawflow']['Home']['data'][$node_key]['data']['step_id'] = $new_step;
419 $funnel_data['drawflow']['Home']['data'][$node_key]['data']['step_edit_link'] = $post_edit_link;
420 $funnel_data['drawflow']['Home']['data'][$node_key]['data']['step_view_link'] = $post_view_link;
421 $funnel_data['drawflow']['Home']['data'][$node_key]['html'] = $node_value['data']['step_type'] . $new_step;
422 $funnel_identifier[$node_value['id']] = $new_step;
423 } else {
424 if ($node_value['data']['step_type'] != 'conditional') {
425 $funnel_identifier[$node_value['id']] = $node_value['data']['step_id'];
426 }
427 }
428 }
429 if( $node_value['data']['step_type'] == 'conditional' ) {
430 $funnel_identifier[$node_value['id']] = $node_value['data']['node_identifier'];
431 }
432 }
433 }
434 update_post_meta($funnel_id, '_funnel_data', $funnel_data);
435
436 if ($funnel_identifier) {
437 $funnel_identifier_json = json_encode($funnel_identifier, JSON_UNESCAPED_SLASHES);
438 update_post_meta($funnel_id, 'funnel_identifier', $funnel_identifier_json);
439 }
440 }
441
442
443 /**
444 * Delete funnel with all its
445 * data
446 *
447 * @param $id
448 *
449 * @return bool|void
450 */
451 public function delete($id)
452 {
453 wp_delete_post($id);
454 $this->set_step_ids();
455 foreach ($this->step_ids as $step_id) {
456 wp_delete_post($step_id);
457 }
458 return true;
459 }
460
461
462 public function read($id)
463 {
464 $funnel = get_post($id);
465 if ($funnel) {
466 $this->set_data($funnel);
467 } else {
468 $this->error('funnel_not_found', __('Invalid Funnel', 'wpfnl'));
469 }
470 }
471
472
473 /**
474 * Init all required data for a complete
475 * funnel object
476 *
477 * @param \WP_Post $funnel
478 *
479 * @since 1.0.0
480 */
481 public function set_data(\WP_Post $funnel)
482 {
483 $step_id = filter_input(INPUT_GET, 'step_id', FILTER_SANITIZE_SPECIAL_CHARS);
484 $this->current_step_id = $step_id;
485 $this->set_id($funnel->ID);
486 $this->funnel_name = $funnel->post_title ? $funnel->post_title : 'No title';
487 $this->status = Wpfnl_functions::get_formatted_status($funnel->post_status);
488 if (Wpfnl_functions::validate_date( $funnel->post_date )) {
489 $this->published_date = Wpfnl_functions::get_formatted_date($funnel->post_date);
490 }
491 $this->set_step_ids();
492 $this->set_steps_order();
493 $this->set_fisrt_step_info();
494 }
495
496
497 /**
498 * All the steps ids within
499 * the funnel
500 *
501 * @since 1.0.0
502 */
503 public function set_step_ids()
504 {
505
506 $this->step_ids = get_posts(
507 [
508 'numberposts' => -1,
509 'post_type' => WPFNL_STEPS_POST_TYPE,
510 'post_status' => array('publish', 'draft','trash'),
511 'fields' => 'ids',
512 'meta_query' => [
513 [
514 'key' => '_funnel_id',
515 'value' => $this->id,
516 ]
517 ]
518 ]
519 );
520 }
521
522
523
524 /**
525 * Set step order for funnel
526 *
527 * @since 1.0.0
528 */
529 public function set_steps_order()
530 {
531 $steps_order = get_post_meta($this->id, '_steps_order', true);
532 $_steps_order = Wpfnl_functions::unserialize_array_data($steps_order);
533 // check if step exits and status is published
534 if( is_array($_steps_order) ){
535 $this->steps_order = array_filter($_steps_order, function ($item) {
536 if (isset($item['id']) && Wpfnl_functions::check_if_module_exists($item['id'])) {
537 return true;
538 }
539 return false;
540 });
541 }
542
543 if ($steps_order) {
544 $this->nr_steps = count($this->steps_order);
545 } else {
546 $this->steps_order = [];
547 }
548 }
549
550
551 public function get_steps_order() {
552 return $this->steps_order;
553 }
554
555 /**
556 * Reinit the step order of the funnel
557 * if any step is deleted
558 *
559 * @since 1.0.0
560 */
561 public function reinitialize_steps_order()
562 {
563 if (count($this->get_order())) {
564 $_steps_order = Wpfnl_functions::unserialize_array_data($this->get_order());
565 $steps_order = array();
566 // check if step exits and status is published
567 if($_steps_order) {
568 foreach ($_steps_order as $key => $step) {
569 if (Wpfnl_functions::check_if_module_exists($step['id'])) {
570 $steps_order[$key] = $step;
571 }
572 }
573 }
574
575 $this->steps_order = $steps_order;
576 $this->update_meta($this->get_id(), '_steps_order', $steps_order);
577 }
578 }
579
580
581 /**
582 * Save store order of the funnel
583 *
584 * @param $step_id
585 * @param $step_type
586 * @param string $title
587 *
588 * @since 1.0.0
589 */
590 public function save_steps_order($step_id, $step_type, $title='')
591 {
592 $this->steps_order[] = [
593 'id' => $step_id,
594 'step_type' => $step_type,
595 'name' => get_the_title($step_id),
596 ];
597 $this->update_meta($this->get_id(), '_steps_order', $this->steps_order);
598 }
599
600
601 /**
602 * Set the first step of the
603 * funnel if any exists
604 *
605 * @since 1.0.0
606 */
607 public function set_fisrt_step_info()
608 {
609 if (count($this->steps_order)) {
610 $first_step = reset($this->steps_order);
611 $this->first_step_type = $first_step['step_type'];
612 $this->first_step_id = $first_step['id'];
613 }
614 }
615
616
617 public function get_first_step_type()
618 {
619 return $this->first_step_type;
620 }
621
622
623 public function get_first_step_id()
624 {
625 return $this->first_step_id;
626 }
627
628
629 /**
630 * Update funnel name
631 *
632 * @param $name
633 *
634 * @since 1.0.0
635 */
636 public function update_funnel_name($name)
637 {
638 $funnel = [
639 'ID' => $this->id,
640 'post_title' => $name,
641 ];
642 wp_update_post($funnel);
643 }
644
645
646
647 public function get_id()
648 {
649 return $this->id;
650 }
651
652
653 public function get_funnel_name()
654 {
655 return $this->funnel_name;
656 }
657
658
659 public function get_published_date()
660 {
661 return $this->published_date;
662 }
663
664
665 public function get_data()
666 {
667 return $this->data;
668 }
669
670
671 public function get_order()
672 {
673 return $this->steps_order;
674 }
675
676
677 public function get_total_steps()
678 {
679 return $this->nr_steps;
680 }
681
682
683 public function get_status()
684 {
685 return $this->status;
686 }
687
688 public function get_step_ids()
689 {
690 return $this->step_ids;
691 }
692
693 public function get_current_step_id()
694 {
695 return $this->current_step_id;
696 }
697
698
699 public function check_if_step_in_funnel($step_id)
700 {
701 return in_array($step_id, $this->step_ids);
702 }
703 }
704