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

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

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