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.4 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 All 262 releases
← All changes | admin/modules/template-library/sources/remote.php +182 -83 2.8.16 → 3.13.3 View file →
@@ -1,13 +1,14 @@
1 1 <?php
2 2 /**
3 3 * Remote class
4 - *
4 + *
5 5 * @package
6 6 */
7 7 namespace WPFunnels\TemplateLibrary;
8 8
9 9 use WPFunnels\API;
10 +use WPFunnels\Rest\Controllers\GutenbergCSSController;
10 11 use WPFunnels\Rest\Controllers\TemplateLibraryController;
11 12 use WPFunnels\Wpfnl;
12 13 use WPFunnels\Wpfnl_functions;
13 14 use function cli\err;
@@ -16,9 +17,9 @@
16 17 {
17 18
18 19 /**
19 20 * Get souce
20 - *
21 + *
21 22 * @return String
22 23 */
23 24 public function get_source()
24 25 {
@@ -26,9 +27,9 @@
26 27 }
27 28
28 29 /**
29 30 * Get funnels
30 - *
31 + *
31 32 * @return Obj
32 33 */
33 34 public function get_funnels($arg = [])
34 35 {
@@ -44,11 +45,11 @@
44 45 }
45 46
46 47 /**
47 48 * Get data
48 - *
49 + *
49 50 * @param Array $args
50 - *
51 + *
51 52 * @return String
52 53 */
53 54 public function get_data(array $args)
54 55 {
@@ -58,41 +59,65 @@
58 59 /**
59 60 * Import funnel
60 61 *
61 62 * @param array $args
62 - *
63 + *
63 64 * @return array
64 65 */
65 66 public function import_funnel($args = [])
66 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 +
67 91 $funnel = Wpfnl::$instance->funnel_store;
68 92 $funnel_id = $funnel->create();
69 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 + }
70 119
71 - if( $funnel_id ){
72 - $general_settings = get_option( '_wpfunnels_general_settings' );
73 - if( isset( $general_settings['funnel_type'] ) ){
74 - if( 'woocommerce' == $general_settings['funnel_type'] ){
75 - $general_settings['funnel_type'] = 'sales';
76 - update_option( '_wpfunnels_general_settings', $general_settings );
77 - }
78 - if( 'sales' == $general_settings['funnel_type'] ){
79 - if( Wpfnl_functions::is_lms_addon_active() && isset($args['type']) && 'lms' === $args['type'] ){
80 - update_post_meta( $funnel_id, '_wpfnl_funnel_type', 'lms' );
81 - } elseif( Wpfnl_functions::is_wc_active() && isset($args['type']) && 'wc' === $args['type'] ){
82 - update_post_meta( $funnel_id, '_wpfnl_funnel_type', 'wc' );
83 - } elseif( isset($args['type']) && 'lead' === $args['type'] ){
84 - update_post_meta( $funnel_id, '_wpfnl_funnel_type', 'lead' );
85 - }
86 - }else{
87 - if( isset($args['type']) && 'lead' === $args['type'] ){
88 - update_post_meta( $funnel_id, '_wpfnl_funnel_type', 'lead' );
89 - }
90 - }
91 - }
92 - }
93 -
94 -
95 120 $remote_id = isset($args['remoteID']) ? $args['remoteID'] : 0;
96 121 if ( !$remote_id ) {
97 122 return array(
98 123 'success' => false,
@@ -98,10 +123,26 @@
98 123 'success' => false,
99 124 );
100 125 }
101 126 $response = TemplateLibraryController::get_funnel( $remote_id );
102 - $funnel_data = $response['funnel_data'];
103 - update_post_meta( $funnel_id, 'funnel_data', $funnel_data );
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 );
104 145
105 146 $funnel_title = isset($args['name']) ? $args['name'] : '';
106 147 $params = array(
107 148 'ID' => $funnel_id,
@@ -108,8 +149,11 @@
108 149 'post_title' => $funnel_title,
109 150 'post_name' => sanitize_title($funnel_title),
110 151 );
111 152 wp_update_post($params);
153 +
154 + do_action('wpfunnels_after_funnel_imported', $funnel_id, $args['type'], $general_settings['builder']);
155 +
112 156 return [
113 157 'success' => true,
114 158 'funnelID' => $funnel_id,
115 159 ];
@@ -119,13 +163,14 @@
119 163 /**
120 164 * Import step
121 165 *
122 166 * @param array $args
123 - *
167 + *
124 168 * @return array
125 169 */
126 170 public function import_step( $args = [] )
127 171 {
172 +
128 173 if (empty($args['funnelID'])) {
129 174 return [
130 175 'success' => true,
131 176 'message' => __('No funnel id found', 'wpfnl'),
@@ -130,21 +175,39 @@
130 175 'success' => true,
131 176 'message' => __('No funnel id found', 'wpfnl'),
132 177 ];
133 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 +
134 196 do_action('wpfunnel_step_import_start');
197 +
135 198 $response = TemplateLibraryController::get_step($args['step']['ID']);
136 -
199 + $isSingleStep = isset($args['isSingleStep']) && 'yes' === $args['isSingleStep'] ? true : false;
137 200 $title = $response['title'];
138 201 $post_content = $response['content'];
139 202 $post_metas = $response['post_meta'];
203 +
140 204 $builder = Wpfnl_functions::get_builder_type();
141 205
142 206 $step = Wpfnl::$instance->step_store;
143 207 $step_id = $step->create_step($args['funnelID'], $title, $args['step']['step_type'], $post_content);
144 - $step->import_metas($step_id, $post_metas);
208 + $step->import_metas($step_id, $post_metas, $isSingleStep );
145 209
146 -
147 210 // re-signing the shortcode signature keys if builder type is oxygen
148 211 if( 'oxygen' === Wpfnl_functions::get_builder_type() ) {
149 212 $ct_shortcodes = get_post_meta( $step_id, 'ct_builder_shortcodes', true );
150 213 $ct_shortcodes = parse_shortcodes($ct_shortcodes, false, false);
@@ -172,8 +235,10 @@
172 235 'post_content' => $response['data']['rawData']
173 236 )
174 237 );
175 238 }
239 +
240 + $this->restore_gutenberg_css( $step_id, $response );
176 241 }
177 242
178 243 $funnel = Wpfnl::$instance->funnel_store;
179 244 $funnel->set_id($args['funnelID']);
@@ -186,11 +251,10 @@
186 251 do_action('wpfunnels/update_ab_testing_start_settings', $step_id);
187 252 do_action('wpfunnels_step_import_complete');
188 253 do_action('wpfunnels_after_step_import', $step_id, $builder);
189 254 update_post_meta($step_id, '_wp_page_template', 'wpfunnels_default');
190 -
191 - $funnel_id = Wpfnl_functions::get_funnel_id_from_step( $step_id );
192 - $utm_settings = Wpfnl_functions::get_funnel_utm_settings( $funnel_id );
255 + $funnel_id = $args['funnelID'];
256 + $utm_settings = Wpfnl_functions::get_funnel_utm_settings( $funnel_id );
193 257 $view_link = get_post_permalink( $step_id );
194 258
195 259 if ( $utm_settings[ 'utm_enable' ] == 'on' ) {
196 260 unset( $utm_settings[ 'utm_enable' ] );
@@ -197,24 +261,37 @@
197 261 $view_link = add_query_arg( $utm_settings, $view_link );
198 262 $view_link = strtolower( $view_link );
199 263 }
200 264
201 - return [
202 - 'success' => true,
203 - 'stepID' => $step_id,
204 - 'stepEditLink' => get_edit_post_link( $step_id ),
205 - 'stepViewLink' => $view_link,
206 - 'abTestingSettingsData' => $this->get_default_start_setting( $step_id ),
207 - ];
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 + ];
208 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 + }
209 288
210 - }
211 -
212 289 /**
213 290 * Import variation step
214 - *
291 + *
215 292 * @param Array $args
216 - *
293 + *
217 294 * @return Array
218 295 */
219 296 public function import_variation_step( $args = [] )
220 297 {
@@ -226,9 +303,9 @@
226 303 }
227 304 do_action('wpfunnel_step_import_start');
228 305 $response = TemplateLibraryController::get_step($args['step']['id']);
229 306
230 - $title = isset($args['step_name']) ? $args['step_name'] : $response['title'];
307 + $title = !empty($args['step_name']) ? $args['step_name'] : $response['title'];
231 308 $post_content = $response['content'];
232 309 $post_metas = $response['post_meta'];
233 310
234 311 $builder = Wpfnl_functions::get_builder_type();
@@ -264,31 +341,15 @@
264 341 'post_content' => $response['data']['rawData']
265 342 )
266 343 );
267 344 }
345 +
346 + $this->restore_gutenberg_css( $step_id, $response );
268 347 }
269 348
270 349 $funnel = Wpfnl::$instance->funnel_store;
271 350 $funnel->set_id($args['funnelID']);
272 - $funnel->set_steps_order();
273 - $funnel->save_steps_order( $step_id, $args['step']['step_type'], $title );
274 351
275 -
276 - if( isset($args['importType']) && $args['importType'] === 'templates' ) {
277 - $this->update_step_id_in_funnel_data_and_identifier( $args['step']['id'], $step_id, $args );
278 - }
279 -
280 - $funnel_data = get_post_meta( $args['funnelID'], 'funnel_data', true );
281 - $steps = $funnel_data['drawflow']['Home']['data'];
282 - foreach ( $steps as $key => $step_data ) {
283 - $node_data = $step_data['data'];
284 - if ( 'conditional' != $node_data['step_type'] && $step_id == $node_data['step_id'] ) {
285 - $step_data['class'] = $step_data['class'].'-'.'has-ab-variation';
286 - $funnel_data['drawflow']['Home']['data'][$key] = $step_data;
287 - }
288 - }
289 - update_post_meta($args['funnelID'], 'funnel_data', $funnel_data);
290 -
291 352 /**
292 353 * Update ab testig settings
293 354 *
294 355 * @param Integer $args['step_id'] - this is parent step id
@@ -297,13 +358,13 @@
297 358 do_action('wpfunnels/update_ab_testing_settings', $args['step_id'], $step_id );
298 359 do_action('wpfunnels_step_import_complete');
299 360 do_action('wpfunnels_after_step_import', $step_id, $builder);
300 361 update_post_meta($step_id, '_wp_page_template', 'wpfunnels_default');
301 -
362 +
302 363 $response = [
303 364 'success' => true,
304 365 'stepID' => $step_id,
305 - 'stepEditLink' => get_edit_post_link($step_id),
366 + 'stepEditLink' => get_edit_post_link($step_id, 'raw') ?? admin_url( 'post.php?post=' . $step_id . '&action=edit' ),
306 367 'stepViewLink' => get_permalink($step_id),
307 368 ];
308 369
309 370 return apply_filters('wpfunnels/modify_import_variant_response', $response, $args['step_id'] );
@@ -313,9 +374,9 @@
313 374
314 375 /**
315 376 * Get default start settings
316 377 */
317 - private function get_default_start_setting( $step_id ){
378 + public function get_default_start_setting( $step_id ){
318 379 $step_edit_link = get_edit_post_link($step_id);
319 380
320 381 $funnel_id = Wpfnl_functions::get_funnel_id_from_step( $step_id );
321 382 $utm_settings = Wpfnl_functions::get_funnel_utm_settings( $funnel_id );
@@ -368,13 +429,13 @@
368 429
369 430
370 431 /**
371 432 * Update funnel identifier
372 - *
433 + *
373 434 * @param $remote_step
374 435 * @param $new_step
375 436 * @param $args
376 - *
437 + *
377 438 * @return void
378 439 */
379 440 public function update_step_id_in_funnel_data_and_identifier( $remote_step, $new_step, $args )
380 441 {
@@ -380,9 +441,10 @@
380 441 {
381 442 $funnel_id = $args['funnelID'];
382 443 $funnel_identifier = array();
383 444 $funnel_data = array();
384 - $funnel_json = get_post_meta( $funnel_id, 'funnel_data', true );
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 +
385 447 if ($funnel_json) {
386 448 if(is_array($funnel_json)) {
387 449 $funnel_data = $funnel_json;
388 450 } else {
@@ -408,16 +470,10 @@
408 470 }
409 471 }
410 472
411 473 if ( $funnel_data ) {
412 - update_post_meta($funnel_id, 'funnel_data', $funnel_data);
413 474
414 - /**
415 - * Save steps data
416 - */
417 - $steps = $this->get_steps( $funnel_data );
418 - update_post_meta( $funnel_id, '_steps', $steps );
419 - Wpfnl_functions::generate_first_step( $funnel_id, $steps );
475 + update_post_meta($funnel_id, '_funnel_data', $funnel_data);
420 476 }
421 477
422 478 if ($funnel_identifier) {
423 479 $funnel_identifier_json = json_encode($funnel_identifier, JSON_UNESCAPED_SLASHES);
@@ -425,13 +481,56 @@
425 481 }
426 482 }
427 483
428 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 +
429 528 /**
430 529 * Get steps
431 530 *
432 531 * @param $funnel_flow_data
433 - *
532 + *
434 533 * @return array
435 534 *
436 535 * @since 2.0.5
437 536 */