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 / 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 2.8.16, at includes/core/data-store/class-wpfnl-store-funnel-data.php

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