PluginProbe
WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell / 3.10.6
WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell v3.10.6
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.10.6, at includes/core/data-store/class-wpfnl-store-funnel-data.php

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