PluginProbe
WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell / 3.12.11
WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell v3.12.11
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 / admin / modules / template-library / sources / remote.php

remote.php in WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell 3.12.11, at admin/modules/template-library/sources/remote.php

573 lines 20.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Remote class
4 *
5 * @package
6 */
7 namespace WPFunnels\TemplateLibrary;
8
9 use WPFunnels\API;
10 use WPFunnels\Rest\Controllers\GutenbergCSSController;
11 use WPFunnels\Rest\Controllers\TemplateLibraryController;
12 use WPFunnels\Wpfnl;
13 use WPFunnels\Wpfnl_functions;
14 use function cli\err;
15 use WPFunnelsPro\AbTesting\Wpfnl_Ab_Testing;
16 class Wpfnl_Source_Remote extends Wpfnl_Source_Base
17 {
18
19 /**
20 * Get souce
21 *
22 * @return String
23 */
24 public function get_source()
25 {
26 return 'remote';
27 }
28
29 /**
30 * Get funnels
31 *
32 * @return Obj
33 */
34 public function get_funnels($arg = [])
35 {
36 return API::get_funnels_data($arg);
37 }
38
39
40 /**
41 * Get funnel
42 */
43 public function get_funnel($template_id)
44 {
45 }
46
47 /**
48 * Get data
49 *
50 * @param Array $args
51 *
52 * @return String
53 */
54 public function get_data(array $args)
55 {
56 }
57
58
59 /**
60 * Import funnel
61 *
62 * @param array $args
63 *
64 * @return array
65 */
66 public function import_funnel($args = [])
67 {
68 $is_pro = apply_filters( 'wpfunnels/is_pro_license_activated', false );
69 $is_store_checkout = isset( $args['is_store_checkout'] ) && $args['is_store_checkout'] === 'true';
70
71 if ( ! $is_pro ) {
72 if ( $is_store_checkout ) {
73 $sc_count = \WPFunnels\Wpfnl_functions::count_store_checkout_funnels();
74 if ( $sc_count >= 3 ) {
75 return array(
76 'success' => false,
77 'message' => __( 'You have reached the maximum limit of 3 store checkouts on the free plan. Upgrade to Pro for unlimited store checkouts.', 'wpfnl' ),
78 );
79 }
80 } else {
81 $funnel_count = \WPFunnels\Wpfnl_functions::count_non_store_checkout_funnels();
82 if ( $funnel_count >= 3 ) {
83 return array(
84 'success' => false,
85 'message' => __( 'You have reached the maximum limit of 3 funnels on the free plan. Upgrade to Pro for unlimited funnels.', 'wpfnl' ),
86 );
87 }
88 }
89 }
90
91 $funnel = Wpfnl::$instance->funnel_store;
92 $funnel_id = $funnel->create();
93 $funnel->update_meta($funnel_id, '_is_imported', 'yes');
94 $general_settings = get_option( '_wpfunnels_general_settings' );
95 // Mark as Store Checkout funnel if imported from Store Checkout page
96 if ( $is_store_checkout ) {
97 update_post_meta( $funnel_id, '_wpfnl_funnel_type', 'store_checkout' );
98 $funnel->update_meta( $funnel_id, '_is_store_checkout', 'yes' );
99 } else {
100 if( $funnel_id ){
101
102 if( isset( $general_settings['funnel_type'] ) ){
103 if( 'woocommerce' == $general_settings['funnel_type'] ){
104 $general_settings['funnel_type'] = 'sales';
105 update_option( '_wpfunnels_general_settings', $general_settings );
106 }
107 if( 'sales' == $general_settings['funnel_type'] ){
108 // Check if LMS add-on is active AND at least one LMS plugin (LearnDash or CreatorLMS) is active
109 if( Wpfnl_functions::is_lms_addon_active() && Wpfnl_functions::is_any_lms_plugin_active() && isset($args['type']) && 'lms' === $args['type'] ){
110 update_post_meta( $funnel_id, '_wpfnl_funnel_type', 'lms' );
111 } elseif( Wpfnl_functions::is_wc_active() && isset($args['type']) && 'wc' === $args['type'] ){
112 update_post_meta( $funnel_id, '_wpfnl_funnel_type', 'wc' );
113 } elseif( isset($args['type']) && 'lead' === $args['type'] ){
114 update_post_meta( $funnel_id, '_wpfnl_funnel_type', 'lead' );
115 }
116 }else{
117 if( isset($args['type']) && 'lead' === $args['type'] ){
118 update_post_meta( $funnel_id, '_wpfnl_funnel_type', 'lead' );
119 }
120 }
121 }
122 }
123 }
124
125 // Set funnel status to draft if specified
126 if (isset($args['status']) && $args['status'] === 'draft') {
127 wp_update_post([
128 'ID' => $funnel_id,
129 'post_status' => 'draft'
130 ]);
131 }
132
133 $remote_id = isset($args['remoteID']) ? $args['remoteID'] : 0;
134 if ( !$remote_id ) {
135 return array(
136 'success' => false,
137 );
138 }
139 $response = TemplateLibraryController::get_funnel( $remote_id );
140 $funnel_data = isset($response['_funnel_data']) ? $response['_funnel_data'] : $response['funnel_data'];
141
142 // If filtered steps are provided from frontend (e.g. for sales funnels), use those instead
143 if ( isset($args['steps']) && is_array($args['steps']) && !empty($args['steps']) ) {
144 // Replace the steps in funnel_data with filtered steps from frontend
145 if ( is_array($funnel_data) ) {
146 $funnel_data['steps'] = $args['steps'];
147 } elseif ( is_string($funnel_data) ) {
148 // If funnel_data is JSON string, decode, replace, and re-encode
149 $decoded = json_decode($funnel_data, true);
150 if ( is_array($decoded) ) {
151 $decoded['steps'] = $args['steps'];
152 $funnel_data = $decoded;
153 }
154 }
155 }
156
157 update_post_meta( $funnel_id, '_funnel_data', $funnel_data );
158
159 $funnel_title = isset($args['name']) ? $args['name'] : '';
160 $params = array(
161 'ID' => $funnel_id,
162 'post_title' => $funnel_title,
163 'post_name' => sanitize_title($funnel_title),
164 );
165 wp_update_post($params);
166
167 do_action('wpfunnels_after_funnel_imported', $funnel_id, $args['type'], $general_settings['builder']);
168
169 return [
170 'success' => true,
171 'funnelID' => $funnel_id,
172 ];
173 }
174
175
176 /**
177 * Import step
178 *
179 * @param array $args
180 *
181 * @return array
182 */
183 public function import_step( $args = [] )
184 {
185
186 if (empty($args['funnelID'])) {
187 return [
188 'success' => true,
189 'message' => __('No funnel id found', 'wpfnl'),
190 ];
191 }
192 // Check if this is a Store Checkout funnel and skip non-checkout/thankyou steps
193 // Only applies to bulk/funnel-template imports, not single step imports from the canvas
194 $is_single_step = isset($args['isSingleStep']) && 'yes' === $args['isSingleStep'];
195 $funnel_type = get_post_meta($args['funnelID'], '_wpfnl_funnel_type', true);
196 if ( ! $is_single_step && $funnel_type === 'store_checkout') {
197 $step_type = isset($args['step']['step_type']) ? $args['step']['step_type'] : '';
198 // Silently skip non-checkout and non-thankyou steps
199 if (!in_array($step_type, ['checkout', 'thankyou'])) {
200 return [
201 'success' => true,
202 'stepID' => 0,
203 'skipped' => true,
204 'message' => __('Step skipped for Store Checkout', 'wpfnl'),
205 ];
206 }
207 }
208
209 do_action('wpfunnel_step_import_start');
210
211 $response = TemplateLibraryController::get_step($args['step']['ID']);
212 $isSingleStep = isset($args['isSingleStep']) && 'yes' === $args['isSingleStep'] ? true : false;
213 $title = $response['title'];
214 $post_content = $response['content'];
215 $post_metas = $response['post_meta'];
216
217 $builder = Wpfnl_functions::get_builder_type();
218
219 $step = Wpfnl::$instance->step_store;
220 $step_id = $step->create_step($args['funnelID'], $title, $args['step']['step_type'], $post_content);
221 $step->import_metas($step_id, $post_metas, $isSingleStep );
222
223 // re-signing the shortcode signature keys if builder type is oxygen
224 if( 'oxygen' === Wpfnl_functions::get_builder_type() ) {
225 $ct_shortcodes = get_post_meta( $step_id, 'ct_builder_shortcodes', true );
226 $ct_shortcodes = parse_shortcodes($ct_shortcodes, false, false);
227 $shortcodes = parse_components_tree($ct_shortcodes['content']);
228 update_post_meta($step_id, 'ct_builder_shortcodes', $shortcodes);
229 }
230
231 if ( 'divi-builder' === Wpfnl_functions::get_builder_type() ) {
232 if ( isset( $response['data']['divi_content'] ) && ! empty( $response['data']['divi_content'] ) ) {
233 update_post_meta( $step_id, 'divi_content', $response['data']['divi_content'] );
234 wp_update_post(
235 array(
236 'ID' => $step_id,
237 'post_content' => $response['data']['divi_content']
238 )
239 );
240 }
241 }
242
243 if ( 'gutenberg' === Wpfnl_functions::get_builder_type() ) {
244 if ( isset( $response['data']['rawData'] ) && ! empty( $response['data']['rawData'] ) ) {
245 wp_update_post(
246 array(
247 'ID' => $step_id,
248 'post_content' => $response['data']['rawData']
249 )
250 );
251 }
252
253 $this->restore_gutenberg_css( $step_id, $response );
254 }
255
256 $funnel = Wpfnl::$instance->funnel_store;
257 $funnel->set_id($args['funnelID']);
258 $funnel->set_steps_order();
259 $funnel->save_steps_order( $step_id, $args['step']['step_type'], $title );
260
261 if( isset($args['importType']) && $args['importType'] === 'templates' ) {
262 $this->update_step_id_in_funnel_data_and_identifier( $args['step']['ID'], $step_id, $args );
263 }
264 do_action('wpfunnels/update_ab_testing_start_settings', $step_id);
265 do_action('wpfunnels_step_import_complete');
266 do_action('wpfunnels_after_step_import', $step_id, $builder);
267 update_post_meta($step_id, '_wp_page_template', 'wpfunnels_default');
268 $funnel_id = $args['funnelID'];
269 $utm_settings = Wpfnl_functions::get_funnel_utm_settings( $funnel_id );
270 $view_link = get_post_permalink( $step_id );
271
272 if ( $utm_settings[ 'utm_enable' ] == 'on' ) {
273 unset( $utm_settings[ 'utm_enable' ] );
274 $view_link = add_query_arg( $utm_settings, $view_link );
275 $view_link = strtolower( $view_link );
276 }
277
278 $response = [
279 'success' => true,
280 'stepID' => $step_id,
281 'stepEditLink' => get_edit_post_link($step_id, 'raw') ?? admin_url( 'post.php?post=' . $step_id . '&action=edit' ),
282 'stepViewLink' => $view_link,
283 'abTestingSettingsData'=> $this->get_default_start_setting($step_id),
284 ];
285
286 if( isset( $args['lastClickedAddStep'] ) ){
287 $reconfigureSettings = get_post_meta( $funnel->get_id(),'_wpfnl_reconfigurable_condition_data', true);
288 if( is_array($reconfigureSettings) && !empty($reconfigureSettings) ){
289 $key = array_search($args['lastClickedAddStep'], array_column($reconfigureSettings, 'nodeId'));
290 if( false !== $key ){
291 $reconfigureSettings[$key]['step_id'] = $step_id;
292 // update_post_meta( $funnel->get_id(),'_wpfnl_reconfigurable_condition_data', $reconfigureSettings );
293 $response['reconfigureSettings'] = $reconfigureSettings;
294 // update_post_meta( $step_id, '_wpfnl_maybe_enable_condition', $reconfigureSettings[$key]['is_enable'] );
295 }
296 }
297 }
298 update_post_meta($step_id, '_step_type', $args['step']['step_type']);
299 return $response;
300 }
301
302 /**
303 * Import variation step
304 *
305 * @param Array $args
306 *
307 * @return Array
308 */
309 public function import_variation_step( $args = [] )
310 {
311 if (empty($args['funnelID'])) {
312 return [
313 'success' => true,
314 'message' => __('No funnel id found', 'wpfnl'),
315 ];
316 }
317 do_action('wpfunnel_step_import_start');
318 $response = TemplateLibraryController::get_step($args['step']['id']);
319
320 $title = !empty($args['step_name']) ? $args['step_name'] : $response['title'];
321 $post_content = $response['content'];
322 $post_metas = $response['post_meta'];
323
324 $builder = Wpfnl_functions::get_builder_type();
325
326 $step = Wpfnl::$instance->step_store;
327 $step_id = $step->create_step($args['funnelID'], $title, $args['step']['step_type'], $post_content,false);
328 $step->import_metas($step_id, $post_metas);
329
330 if( 'oxygen' === Wpfnl_functions::get_builder_type() ) {
331 $ct_shortcodes = get_post_meta( $step_id, 'ct_builder_shortcodes', true );
332 $ct_shortcodes = parse_shortcodes($ct_shortcodes, false, false);
333 $shortcodes = parse_components_tree($ct_shortcodes['content']);
334 update_post_meta($step_id, 'ct_builder_shortcodes', $shortcodes);
335 }
336
337 if ( 'divi-builder' === Wpfnl_functions::get_builder_type() ) {
338 if ( isset( $response['data']['divi_content'] ) && ! empty( $response['data']['divi_content'] ) ) {
339 update_post_meta( $step_id, 'divi_content', $response['data']['divi_content'] );
340 wp_update_post(
341 array(
342 'ID' => $step_id,
343 'post_content' => $response['data']['divi_content']
344 )
345 );
346 }
347 }
348
349 if ( 'gutenberg' === Wpfnl_functions::get_builder_type() ) {
350 if ( isset( $response['data']['rawData'] ) && ! empty( $response['data']['rawData'] ) ) {
351 wp_update_post(
352 array(
353 'ID' => $step_id,
354 'post_content' => $response['data']['rawData']
355 )
356 );
357 }
358
359 $this->restore_gutenberg_css( $step_id, $response );
360 }
361
362 $funnel = Wpfnl::$instance->funnel_store;
363 $funnel->set_id($args['funnelID']);
364
365 /**
366 * Update ab testig settings
367 *
368 * @param Integer $args['step_id'] - this is parent step id
369 * @param Integer $step_id - this is parent variant id
370 */
371 do_action('wpfunnels/update_ab_testing_settings', $args['step_id'], $step_id );
372 do_action('wpfunnels_step_import_complete');
373 do_action('wpfunnels_after_step_import', $step_id, $builder);
374 update_post_meta($step_id, '_wp_page_template', 'wpfunnels_default');
375
376 $response = [
377 'success' => true,
378 'stepID' => $step_id,
379 'stepEditLink' => get_edit_post_link($step_id, 'raw') ?? admin_url( 'post.php?post=' . $step_id . '&action=edit' ),
380 'stepViewLink' => get_permalink($step_id),
381 ];
382
383 return apply_filters('wpfunnels/modify_import_variant_response', $response, $args['step_id'] );
384
385 }
386
387
388 /**
389 * Get default start settings
390 */
391 public function get_default_start_setting( $step_id ){
392 $step_edit_link = get_edit_post_link($step_id);
393
394 $funnel_id = Wpfnl_functions::get_funnel_id_from_step( $step_id );
395 $utm_settings = Wpfnl_functions::get_funnel_utm_settings( $funnel_id );
396 $view_link = get_post_permalink( $step_id );
397
398 if ( $utm_settings[ 'utm_enable' ] == 'on' ) {
399 unset( $utm_settings[ 'utm_enable' ] );
400 $view_link = add_query_arg( $utm_settings, $view_link );
401 $view_link = strtolower( $view_link );
402 }
403
404 if( 'elementor' == Wpfnl_functions::get_builder_type() ){
405 $step_edit_link = str_replace('/&amp;/g','&',$step_edit_link);
406 $step_edit_link = str_replace('edit','elementor',$step_edit_link);
407 }
408
409 $default_settings = [
410 'is_ab_enabled' => '',
411 'start_settings' => [
412 'auto_winner' => [
413 'is_enabled' => '',
414 'conditions' => [
415 'index' => 'trafiic',
416 'value' => 70
417 ]
418 ],
419 'winner' => '',
420 'is_started' => '',
421 'start_date' => date( 'Y-m-d H:i:s' ),
422 'variations' => [
423 [
424 'id' => $step_id,
425 'traffic' => 100,
426 'step_type'=> get_post_meta($step_id,'_step_type',true),
427 'variation_type' => 'original',
428 'step_edit_link' => $step_edit_link,
429 'step_view_link' => $view_link,
430 'step_title' => get_the_title($step_id),
431 'conversion' => 0,
432 'visit' => 0,
433 'shouldShowAnalytics' => false,
434 ],
435 ],
436 ]
437
438 ];
439
440 return $default_settings;
441 }
442
443
444 /**
445 * Update funnel identifier
446 *
447 * @param $remote_step
448 * @param $new_step
449 * @param $args
450 *
451 * @return void
452 */
453 public function update_step_id_in_funnel_data_and_identifier( $remote_step, $new_step, $args )
454 {
455 $funnel_id = $args['funnelID'];
456 $funnel_identifier = array();
457 $funnel_data = array();
458 $funnel_json = get_post_meta( $funnel_id, '_funnel_data', true ) ? get_post_meta( $funnel_id, '_funnel_data', true ) : get_post_meta( $funnel_id, 'funnel_data', true );
459
460 if ($funnel_json) {
461 if(is_array($funnel_json)) {
462 $funnel_data = $funnel_json;
463 } else {
464 $funnel_data = json_decode($funnel_json,1);
465 }
466 $node_data = $funnel_data['drawflow']['Home']['data'];
467 foreach ($node_data as $node_key => $node_value) {
468 if ( isset($node_value['data']['step_id']) && $node_value['data']['step_id'] == $remote_step ) {
469 $post_edit_link = base64_encode(get_edit_post_link($new_step));
470 $post_view_link = base64_encode(get_post_permalink($new_step));
471 $funnel_data['drawflow']['Home']['data'][$node_key]['data']['step_id'] = $new_step;
472 $funnel_data['drawflow']['Home']['data'][$node_key]['data']['step_edit_link'] = $post_edit_link;
473 $funnel_data['drawflow']['Home']['data'][$node_key]['data']['step_view_link'] = $post_view_link;
474 $funnel_data['drawflow']['Home']['data'][$node_key]['html'] = $node_value['data']['step_type'] . $new_step;
475 $funnel_identifier[$node_value['id']] = $new_step;
476 } else {
477 if ($node_value['data']['step_type'] != 'conditional') {
478 $funnel_identifier[$node_value['id']] = $node_value['data']['step_id'];
479 } else {
480 $funnel_identifier[$node_value['id']] = $node_value['data']['node_identifier'];
481 }
482 }
483 }
484 }
485
486 if ( $funnel_data ) {
487
488 update_post_meta($funnel_id, '_funnel_data', $funnel_data);
489 }
490
491 if ($funnel_identifier) {
492 $funnel_identifier_json = json_encode($funnel_identifier, JSON_UNESCAPED_SLASHES);
493 update_post_meta($funnel_id, 'funnel_identifier', $funnel_identifier_json);
494 }
495 }
496
497
498 /**
499 * Restore generated Gutenberg CSS for imported remote templates.
500 *
501 * Remote step responses may expose the generated block CSS outside post meta,
502 * so rebuild the imported step's CSS meta/file explicitly.
503 *
504 * @param int $step_id
505 * @param array $response
506 *
507 * @return void
508 */
509 private function restore_gutenberg_css( $step_id, $response ) {
510 $css = '';
511
512 if ( isset( $response['data']['_qubely_css'] ) && is_string( $response['data']['_qubely_css'] ) ) {
513 $css = $response['data']['_qubely_css'];
514 }
515
516 if ( ! $css ) {
517 $css = get_post_meta( $step_id, '_wpfunnels_gb_css', true );
518 }
519
520 if ( ! $css ) {
521 return;
522 }
523
524 $css_controller = new GutenbergCSSController();
525 $css = $css_controller->set_import_url_to_top_css( $css );
526
527 update_post_meta( $step_id, '_wpfunnels_gb_css', $css );
528
529 $upload_dir = wp_upload_dir();
530 $dir = trailingslashit( $upload_dir['basedir'] ) . 'wpfunnels/css/';
531 $filename = sprintf( 'wpfnl-css-%d.css', $step_id );
532
533 if ( ! file_exists( $dir ) ) {
534 wp_mkdir_p( $dir );
535 }
536
537 file_put_contents( $dir . $filename, $css );
538 }
539
540
541 /**
542 * Get steps
543 *
544 * @param $funnel_flow_data
545 *
546 * @return array
547 *
548 * @since 2.0.5
549 */
550 private function get_steps( $funnel_flow_data ) {
551 $drawflow = $funnel_flow_data['drawflow'];
552 $steps = array();
553 if( isset( $drawflow['Home']['data'] ) ) {
554 $drawflow_data = $drawflow['Home']['data'];
555 foreach ( $drawflow_data as $key => $data ) {
556 $step_data = $data['data'];
557 $step_type = $step_data['step_type'];
558 if('conditional' !== $step_type) {
559 $step_id = $step_data['step_id'];
560 $step_name = sanitize_text_field(get_the_title($step_data['step_id']));
561 $steps[] = array(
562 'id' => $step_id,
563 'step_type' => $step_type,
564 'name' => $step_name,
565 );
566 }
567
568 }
569 }
570 return $steps;
571 }
572 }
573