PluginProbe
WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell / 3.12.8
WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell v3.12.8
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 / settings / class-wpfnl-settings.php

class-wpfnl-settings.php in WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell 3.12.8, at admin/modules/settings/class-wpfnl-settings.php

1,150 lines 43.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Settings module
4 *
5 * @package
6 */
7
8 namespace WPFunnels\Modules\Admin\Settings;
9
10 use WPFunnels\Admin\Module\Wpfnl_Admin_Module;
11 use WPFunnels\Rollback;
12 use WPFunnels\Traits\SingletonTrait;
13 use WPFunnels\Wpfnl;
14 use WPFunnels\Wpfnl_functions;
15
16 class Module extends Wpfnl_Admin_Module
17 {
18 use SingletonTrait;
19
20 protected $validations;
21
22 protected $prefix = '_wpfunnels_';
23
24 protected $general_settings;
25
26 protected $permalink_settings;
27
28 protected $optin_settings;
29
30 protected $offer_settings;
31
32 protected $user_roles;
33
34 protected $gtm_events;
35
36 protected $gtm_settings;
37
38 protected $facebook_pixel_events;
39
40 protected $facebook_pixel_settings;
41
42 protected $recaptcha_settings;
43
44 protected $utm_params;
45
46 protected $utm_settings;
47
48 protected $is_allow_sales;
49
50 /**
51 * User Roles Settings.
52 *
53 * @var array $user_roles_settings An associative array containing user roles settings.
54 */
55 protected $user_roles_settings;
56
57 /**
58 * Notification Settings.
59 *
60 * @var array $notification_settings An associative array containing notification settings.
61 */
62 protected $notification_settings;
63
64
65 /**
66 * Google Maps API Key.
67 *
68 * This property stores the API key used for accessing Google Maps services.
69 *
70 * @var string $google_map_api_key The Google Maps API key.
71 */
72 protected $google_map_api_key;
73
74 /**
75 * Page hooks
76 *
77 * @var array
78 */
79 private $page_hooks = [
80 'toplevel_page_wp_funnels',
81 'wp-funnels_page_wp_funnel_settings',
82 'wpfunnels_page_wpfnl_settings',
83 'wp-funnels_page_edit_funnel',
84 'wp-funnels_page_create_funnel',
85 'wp-funnels_page_wpfnl_settings',
86 'wp-funnels_page_wpf-license',
87 'wpfunnels_page_email-builder',
88 ];
89
90 protected $settings_meta_keys = [
91 '_wpfunnels_funnel_type' => 'sales',
92 '_wpfunnels_builder' => 'elementor',
93 '_wpfunnels_paypal_reference' => '',
94 '_wpfunnels_order_bump' => '',
95 '_wpfunnels_ab_testing' => '',
96 '_wpfunnels_allow_funnels' => [
97 'administrator' => true,
98 ],
99 '_wpfunnels_permalink_settings' => '',
100 '_wpfunnels_optin_settings' => '',
101 '_wpfunnels_permalink_step_base' => 'wpfunnels',
102 '_wpfunnels_permalink_flow_base' => 'step',
103 '_wpfunnels_set_permalink' => 'step',
104 ];
105
106 public function __construct()
107 {
108 add_action('admin_enqueue_scripts', [$this, 'enqueue_scripts']);
109 add_action('admin_init', [$this, 'after_permalink_settings_saved']);
110 add_action( 'admin_post_wpfunnels_rollback', [ $this, 'post_wpfunnels_rollback' ] );
111 add_action( 'wpfunnels_send_revenue_report_email', [ $this, 'send_revenue_report_email' ] );
112 $this->init_ajax();
113 }
114
115 public function is_wc_installed()
116 {
117 $path = 'woocommerce/woocommerce.php';
118 $plugins = get_plugins();
119
120 return isset($plugins[ $path ]);
121 }
122
123 public function is_ff_installed()
124 {
125 $path = 'fluentform/fluentform.php';
126 $plugins = get_plugins();
127
128 return isset($plugins[ $path ]);
129 }
130
131 public function is_elementor_installed()
132 {
133 $path = 'elementor/elementor.php';
134 $plugins = get_plugins();
135
136 return isset($plugins[ $path ]);
137 }
138
139
140 public function enqueue_scripts( $hook )
141 {
142 if ( ! in_array( $hook, $this->page_hooks, true ) ) {
143 return;
144 }
145 wp_enqueue_script('settings', plugin_dir_url(__FILE__) . 'js/settings.js', ['jquery'], WPFNL_VERSION, true);
146 }
147
148
149 public function get_view()
150 {
151 $this->init_settings();
152 $is_pro_activated = Wpfnl_functions::is_wpfnl_pro_activated();
153 $global_funnel_type = Wpfnl_functions::get_global_funnel_type();
154 require_once WPFNL_DIR . '/admin/modules/settings/views/view.php';
155 }
156
157 /**
158 * Init ajax hooks for
159 * saving metas
160 *
161 * @since 1.0.0
162 */
163 public function init_ajax()
164 {
165 $this->validations = [
166 'logged_in' => true,
167 'user_can' => 'wpf_manage_funnels',
168 ];
169 wp_ajax_helper()->handle('update-general-settings')
170 ->with_callback([ $this, 'update_general_settings' ])
171 ->with_validation($this->validations);
172
173 wp_ajax_helper()->handle('clear-templates')
174 ->with_callback([ $this, 'clear_templates_data' ])
175 ->with_validation($this->validations);
176
177 wp_ajax_helper()->handle('clear-transient')
178 ->with_callback([ $this, 'clear_transient_cache_data' ])
179 ->with_validation($this->validations);
180
181 wp_ajax_helper()->handle('wpfnl-show-log')
182 ->with_callback([ $this, 'wpfnl_show_log' ])
183 ->with_validation($this->validations);
184
185 wp_ajax_helper()->handle('wpfnl-delete-log')
186 ->with_callback([ $this, 'wpfnl_delete_log' ])
187 ->with_validation($this->validations);
188
189 wp_ajax_helper()->handle('wpfnl-send-test-notification')
190 ->with_callback([ $this, 'send_test_notification' ])
191 ->with_validation($this->validations);
192 }
193
194
195 /**
196 * Update handler for settings
197 * page
198 *
199 * @param $payload
200 *
201 * @return array
202 * @since 1.0.0
203 */
204 public function update_general_settings($payload)
205 {
206 do_action('wpfunnels/before_settings_saved', $payload);
207 $existing_settings = Wpfnl_functions::get_general_settings();
208 $general_settings = [
209 'funnel_type' => sanitize_text_field($payload['funnel_type']),
210 'builder' => sanitize_text_field($payload['builder']),
211 'uninstall_cleanup' => isset($payload['uninstall_cleanup']) ? sanitize_text_field($payload['uninstall_cleanup']) : 'off',
212 'disable_analytics' => isset($payload['analytics_roles']) ? $payload['analytics_roles'] : '',
213 'allow_funnels' => isset($payload['permission_role']) ? $payload['permission_role'] : [],
214 'paypal_reference' => isset($payload['paypal_reference']) ? sanitize_text_field($payload['paypal_reference']) : 'off',
215 'order_bump' => isset($payload['order_bump']) ? sanitize_text_field($payload['order_bump']) : 'off',
216 'ab_testing' => isset($payload['ab_testing']) ? sanitize_text_field($payload['ab_testing']) : 'off',
217 'disable_theme_style' => isset($payload['disable_theme_style']) ? sanitize_text_field($payload['disable_theme_style']) : 'off',
218 'enable_log_status' => isset($payload['enable_log_status']) ? sanitize_text_field($payload['enable_log_status']) : 'off',
219 'enable_skip_cart' => isset($payload['enable_skip_cart']) ? $payload['enable_skip_cart'] : 'no',
220 'skip_cart_for' => isset($payload['skip_cart_for']) ? $payload['skip_cart_for'] : 'whole',
221 'funnel_builder_mode' => isset($payload['funnel_builder_mode']) ? sanitize_text_field($payload['funnel_builder_mode']) : $existing_settings['funnel_builder_mode'],
222 ];
223
224 if ( isset( $payload['funnel_builder_mode'] ) && 'vertical' === $payload['funnel_builder_mode'] ) {
225 do_action( 'wpfunnels_vertical_mode_used' );
226 }
227
228 $permalink_settings = [
229 'structure' => isset($payload['permalink_settings']) ? sanitize_text_field($payload['permalink_settings']) : 'default',
230 'step_base' => isset($payload['permalink_step_base']) ? sanitize_text_field($payload['permalink_step_base']) : WPFNL_STEPS_POST_TYPE,
231 'funnel_base' => isset($payload['permalink_funnel_base']) ? sanitize_text_field($payload['permalink_funnel_base']) : WPFNL_FUNNELS_POST_TYPE,
232 ];
233
234 if( isset($payload['sender_name']) && isset($payload['sender_email']) ){
235 $optin_settings = [
236 'sender_name' => sanitize_text_field($payload['sender_name']),
237 'sender_email' => sanitize_text_field($payload['sender_email']),
238 'email_subject' => isset($payload['email_subject']) ? sanitize_text_field($payload['email_subject']) : '',
239 ];
240 }else{
241 $optin_settings = Wpfnl_functions::get_optin_settings();
242 }
243
244
245 foreach ($payload as $key => $value) {
246 switch ($key) {
247 case 'funnel_type':
248 case 'builder':
249 $cache_key = 'wpfunnels_remote_template_data_' . WPFNL_VERSION;
250 delete_transient($cache_key);
251 delete_option(WPFNL_TEMPLATES_OPTION_KEY);
252 break;
253 case 'permalink_settings':
254 Wpfnl_functions::update_admin_settings($this->prefix.'permalink_saved', true);
255 break;
256 case 'advanced_settings':
257 Wpfnl_functions::update_admin_settings($this->prefix.'advanced_settings', $value);
258 break;
259 default:
260 break;
261 }
262 }
263
264 Wpfnl_functions::update_admin_settings($this->prefix.'general_settings', $general_settings);
265 Wpfnl_functions::update_admin_settings($this->prefix.'permalink_settings', $permalink_settings);
266 Wpfnl_functions::update_admin_settings($this->prefix.'optin_settings', $optin_settings);
267 $this->save_recaptcha_settings($payload);
268 $this->save_user_role_management_data($payload);
269 $this->save_google_map_key($payload);
270 $this->save_lms_settings($payload);
271 $this->save_notification_settings($payload);
272
273 delete_option(WPFNL_TEMPLATES_OPTION_KEY.'_74');
274 delete_option(WPFNL_TEMPLATES_OPTION_KEY.'_73');
275 delete_option(WPFNL_TEMPLATES_OPTION_KEY.'_52');
276 delete_option(WPFNL_TEMPLATES_OPTION_KEY.'_53');
277
278 delete_transient('wpfunnels_remote_template_data_74_' . WPFNL_VERSION);
279 delete_transient('wpfunnels_remote_template_data_73_' . WPFNL_VERSION);
280 delete_transient('wpfunnels_remote_template_data_52_' . WPFNL_VERSION);
281 delete_transient('wpfunnels_remote_template_data_53_' . WPFNL_VERSION);
282
283 do_action('wpfunnels/after_settings_saved', $payload );
284 return [
285 'success' => true
286 ];
287 }
288
289 /**
290 * Save Facebook pixel settings
291 *
292 * @param $settings
293 *
294 * @since 1.0.0
295 */
296 public function save_recaptcha_settings( $settings ) {
297 $enable_recapcha = isset($settings['enable_recaptcha']) ? $settings['enable_recaptcha'] : 'no';
298 $recapcha_site_key = isset($settings['recaptcha_site_key']) ? $settings['recaptcha_site_key'] : '';
299 $recapcha_site_secret = isset($settings['recaptcha_site_secret']) ? $settings['recaptcha_site_secret'] : '';
300 $recaptcha_settings = array(
301 'enable_recaptcha' => $enable_recapcha,
302 'recaptcha_site_key' => $recapcha_site_key,
303 'recaptcha_site_secret' => $recapcha_site_secret
304 );
305 Wpfnl_functions::update_admin_settings('_wpfunnels_recaptcha_setting', $recaptcha_settings );
306 }
307
308
309 /**
310 * Save user role management data
311 *
312 * @param $payload
313 *
314 * @since 3.1.4
315 */
316 public function save_user_role_management_data($payload) {
317 if ( !isset($payload['user_role_management']) ) {
318 return;
319 }
320
321 $roles = wp_unslash( $payload['user_role_management']['roles'] );
322 $sanitized_settings = array();
323 foreach ( $roles as $key => $value ) {
324 $sanitized_settings[ $key ] = ( isset( $roles[ $key ] ) ) ? sanitize_text_field( $value ) : '';
325 }
326 Wpfnl_functions::update_admin_settings('_wpfunnels_user_roles', $sanitized_settings );
327
328 $this->update_user_role_management( $sanitized_settings );
329 }
330
331
332 /**
333 * Update user role management data
334 *
335 * @param $sanitized_settings
336 *
337 * @since 3.1.4
338 */
339 private function update_user_role_management( $sanitized_settings ) {
340
341 foreach ( $sanitized_settings as $user_role => $value ) {
342 $user_role_obj = get_role( $user_role );
343 if ( $user_role_obj ) {
344 if ( 'yes' === $value ) {
345 $user_role_obj->add_cap('wpf_manage_funnels' );
346 } elseif ( 'no' === $value ) {
347 $user_role_obj->remove_cap('wpf_manage_funnels' );
348 }
349 }
350 }
351 }
352
353
354
355 /**
356 * Save google map api key settings key
357 *
358 * @param $payload
359 *
360 * @since 3.1.3
361 */
362 public function save_google_map_key( $payload ) {
363 if ( isset($payload['google_map_api_key']) ) {
364 Wpfnl_functions::update_admin_settings('_wpfunnels_google_map_api_key', $payload['google_map_api_key'] );
365 }
366 }
367
368
369 /**
370 * Save LMS provider settings
371 *
372 * @param $payload
373 *
374 * @since 2.0.0
375 */
376 public function save_lms_settings( $payload ) {
377 if ( isset($payload['lms_provider']) ) {
378 $lms_settings = array(
379 'lms_provider' => sanitize_text_field( $payload['lms_provider'] )
380 );
381 update_option( '_wpfunnels_lms_settings', $lms_settings );
382 }
383 }
384
385 /**
386 * Save notification settings
387 *
388 * @param $payload
389 *
390 * @since 3.2.0
391 */
392 public function save_notification_settings( $payload ) {
393 $old_settings = Wpfnl_functions::get_notification_settings();
394 $old_enabled = isset($old_settings['enable_revenue_report']) ? $old_settings['enable_revenue_report'] : 'no';
395
396 $notification_settings = array(
397 'enable_revenue_report' => isset($payload['enable_revenue_report']) ? sanitize_text_field($payload['enable_revenue_report']) : 'no',
398 'revenue_report_frequency' => isset($payload['revenue_report_frequency']) ? sanitize_text_field($payload['revenue_report_frequency']) : 'weekly',
399 'revenue_report_recipient' => isset($payload['revenue_report_recipient']) ? sanitize_text_field($payload['revenue_report_recipient']) : get_option('admin_email'),
400 'revenue_report_subject' => isset($payload['revenue_report_subject']) ? sanitize_text_field($payload['revenue_report_subject']) : 'Store Revenue Report - {period}',
401 'send_time' => isset($payload['send_time']) ? sanitize_text_field($payload['send_time']) : '10:00',
402 );
403
404 Wpfnl_functions::update_admin_settings('_wpfunnels_notification_settings', $notification_settings );
405
406 $new_enabled = $notification_settings['enable_revenue_report'];
407
408 // Handle action scheduler based on enable/disable
409 if ( $new_enabled === 'yes' && $old_enabled !== 'yes' ) {
410 // Enabled: Schedule the action
411 $this->schedule_revenue_report_email( $notification_settings );
412 } elseif ( $new_enabled !== 'yes' && $old_enabled === 'yes' ) {
413 // Disabled: Remove the scheduled action
414 $this->unschedule_revenue_report_email();
415 } elseif ( $new_enabled === 'yes' ) {
416 // Already enabled but settings changed: Reschedule
417 $this->unschedule_revenue_report_email();
418 $this->schedule_revenue_report_email( $notification_settings );
419 }
420 }
421
422
423 /**
424 * Schedule revenue report email using Action Scheduler
425 *
426 * @param array $settings
427 *
428 * @since 3.2.0
429 */
430 private function schedule_revenue_report_email( $settings ) {
431 if ( ! function_exists( 'as_schedule_recurring_action' ) ) {
432 return;
433 }
434
435 // Calculate next run time based on send_time
436 $send_time = isset( $settings['send_time'] ) ? $settings['send_time'] : '10:00';
437 $frequency = isset( $settings['revenue_report_frequency'] ) ? $settings['revenue_report_frequency'] : 'weekly';
438
439 // Parse time (format: HH:MM)
440 list( $hour, $minute ) = explode( ':', $send_time );
441
442 // Get current time
443 $now = current_time( 'timestamp' );
444 $today = strtotime( date( 'Y-m-d', $now ) );
445
446 // Calculate first run time (today at specified time)
447 $first_run = $today + ( $hour * HOUR_IN_SECONDS ) + ( $minute * MINUTE_IN_SECONDS );
448
449 // If the time has already passed today, schedule for tomorrow
450 if ( $first_run <= $now ) {
451 $first_run += DAY_IN_SECONDS;
452 }
453
454 // Calculate interval based on frequency
455 $interval = ( $frequency === 'monthly' ) ? MONTH_IN_SECONDS : WEEK_IN_SECONDS;
456
457 // Schedule recurring action
458 as_schedule_recurring_action(
459 $first_run,
460 $interval,
461 'wpfunnels_send_revenue_report_email',
462 array(),
463 'wpfunnels'
464 );
465 }
466
467
468 /**
469 * Unschedule revenue report email
470 *
471 * @since 3.2.0
472 */
473 private function unschedule_revenue_report_email() {
474 if ( ! function_exists( 'as_unschedule_all_actions' ) ) {
475 return;
476 }
477
478 as_unschedule_all_actions( 'wpfunnels_send_revenue_report_email', array(), 'wpfunnels' );
479 }
480
481
482 /**
483 * Initialize all the settings value
484 *
485 * @since 1.0.0
486 */
487 public function init_settings()
488 {
489 $this->general_settings = Wpfnl_functions::get_general_settings();
490 $this->is_allow_sales = Wpfnl_functions::maybe_allow_sales_funnel();
491 $this->permalink_settings = Wpfnl_functions::get_permalink_settings();
492 $this->optin_settings = Wpfnl_functions::get_optin_settings();
493 $this->offer_settings = Wpfnl_functions::get_offer_settings();
494 $this->user_roles = Wpfnl_functions::get_user_roles();
495 $this->gtm_events = Wpfnl_functions::get_gtm_events();
496 $this->gtm_settings = Wpfnl_functions::get_gtm_settings();
497 $this->facebook_pixel_events = Wpfnl_functions::get_facebook_events();
498 $this->facebook_pixel_settings = Wpfnl_functions::get_facebook_pixel_settings();
499 $this->utm_params = Wpfnl_functions::get_utm_params();
500 $this->utm_settings = Wpfnl_functions::get_utm_settings();
501 $this->recaptcha_settings = Wpfnl_functions::get_recaptcha_settings();
502 $this->user_roles_settings = Wpfnl_functions::get_user_role_settings();
503 $this->google_map_api_key = Wpfnl_functions::get_google_map_api_key();
504 $this->notification_settings = Wpfnl_functions::get_notification_settings();
505 }
506
507
508
509
510 /**
511 * Clear saved templates data
512 *
513 * @param $payload
514 *
515 * @return array
516 * @since 1.0.0
517 */
518 public function clear_templates_data($payload) {
519
520 delete_option(WPFNL_TEMPLATES_OPTION_KEY.'_wc');
521 delete_option(WPFNL_TEMPLATES_OPTION_KEY.'_lms');
522
523 $builder = Wpfnl_functions::get_builder_type();
524
525 delete_transient('wpfunnels_remote_template_data_wc_' . WPFNL_VERSION);
526 delete_transient('wpfunnels_remote_template_data_lms_' . WPFNL_VERSION);
527 delete_transient('wpfunnels_remote_template_data_lead_' . WPFNL_VERSION);
528 delete_transient('wpfunnels_remote_template_data_store_checkout_' . WPFNL_VERSION);
529
530 delete_transient('wpfunnels_remote_template_data_wc_'. $builder . '_' . WPFNL_VERSION);
531 delete_transient('wpfunnels_remote_template_data_lms_'. $builder . '_' . WPFNL_VERSION);
532 delete_transient('wpfunnels_remote_template_data_lead_'. $builder . '_' . WPFNL_VERSION);
533 delete_transient('wpfunnels_remote_template_data_store_checkout_'. $builder . '_' . WPFNL_VERSION);
534
535 return [
536 'success' => true
537 ];
538 }
539
540
541 /**
542 * Clear transient
543 *
544 * @param $payload
545 *
546 * @return array
547 */
548 public function clear_transient_cache_data($payload) {
549
550 delete_transient('wpfunnels_remote_template_data_' . WPFNL_VERSION);
551 delete_transient('wpfunnels_remote_template_data_wc_' . WPFNL_VERSION);
552 delete_transient('wpfunnels_remote_template_data_lms_' . WPFNL_VERSION);
553 delete_transient('wpfunnels_remote_template_data_lead_' . WPFNL_VERSION);
554 delete_transient('wpfunnels_remote_template_data_store_checkout_' . WPFNL_VERSION);
555 delete_transient('wpfunnels_rollback_versions_' . WPFNL_VERSION);
556 do_action('wpfunnels/after_clear_transient');
557 return array(
558 'success' => true
559 );
560 }
561
562
563 /**
564 * After settings saved hooks
565 *
566 * @since 1.0.0
567 */
568 public function after_permalink_settings_saved()
569 {
570
571 if( Wpfnl_functions::maybe_funnel_page() ){
572 $is_permalink_saved = get_option('_wpfunnels_permalink_saved');
573 if ($is_permalink_saved) {
574 flush_rewrite_rules();
575 delete_option('_wpfunnels_permalink_saved');
576 }
577 }
578 }
579
580
581 /**
582 * Get settings by meta key
583 *
584 * @param $key
585 *
586 * @return mixed|string
587 * @since 1.0.0
588 */
589 public function get_settings_by_key($key)
590 {
591 return isset($this->settings_meta_keys[$key]) ? $this->settings_meta_keys[$key]: '';
592 }
593
594 public function get_name()
595 {
596 return __('settings','wpfnl');
597 }
598
599
600 /**
601 * Get rollback version of WPF
602 *
603 * @return array|mixed
604 * @since 2.3.0
605 */
606 public function get_roll_back_versions() {
607 $rollback_versions = get_transient( 'wpfunnels_rollback_versions_' . WPFNL_VERSION );
608 if ( false === $rollback_versions ) {
609 $max_versions = 10;
610 require_once ABSPATH . 'wp-admin/includes/plugin-install.php';
611 $plugin_information = plugins_api(
612 'plugin_information', [
613 'slug' => 'wpfunnels',
614 ]
615 );
616 if ( empty( $plugin_information->versions ) || ! is_array( $plugin_information->versions ) ) {
617 return [];
618 }
619
620 natsort( $plugin_information->versions );
621 $plugin_information->versions = array_reverse($plugin_information->versions);
622 $rollback_versions = [];
623
624 $current_index = 0;
625 foreach ( $plugin_information->versions as $version => $download_link ) {
626 if ( $max_versions <= $current_index ) {
627 break;
628 }
629
630 $lowercase_version = strtolower( $version );
631 $is_valid_rollback_version = ! preg_match( '/(trunk|beta|rc|dev)/i', $lowercase_version );
632
633 /**
634 * Is rollback version is valid.
635 *
636 * Filters the check whether the rollback version is valid.
637 *
638 * @param bool $is_valid_rollback_version Whether the rollback version is valid.
639 */
640 $is_valid_rollback_version = apply_filters(
641 'wpfunnels/is_valid_rollback_version',
642 $is_valid_rollback_version,
643 $lowercase_version
644 );
645
646 if ( ! $is_valid_rollback_version ) {
647 continue;
648 }
649
650 if ( version_compare( $version, WPFNL_VERSION, '>=' ) ) {
651 continue;
652 }
653
654 $current_index++;
655 $rollback_versions[] = $version;
656 }
657
658 set_transient( 'wpfunnels_rollback_versions_' . WPFNL_VERSION, $rollback_versions, DAY_IN_SECONDS );
659 }
660
661 return $rollback_versions;
662 }
663
664
665 public function post_wpfunnels_rollback() {
666 check_admin_referer( 'wpfunnels_rollback' );
667
668 $rollback_versions = $this->get_roll_back_versions();
669 if ( empty( $_GET['version'] ) || ! in_array( $_GET['version'], $rollback_versions ) ) {
670 wp_die( esc_html__( 'Error occurred, The version selected is invalid. Try selecting different version.', 'wpfnl' ) );
671 }
672
673 $plugin_slug = basename( 'wpfunnels', '.php' );
674
675 $rollback = new Rollback(
676 [
677 'version' => $_GET['version'],
678 'plugin_name' => WPFNL_BASE,
679 'plugin_slug' => $plugin_slug,
680 'package_url' => sprintf( 'https://downloads.wordpress.org/plugin/%1s.%2s.zip', $plugin_slug, $_GET['version'] ),
681 ]
682 );
683
684 $rollback->run();
685
686 wp_die(
687 '', esc_html__( 'Rollback to Previous Version', 'wpfnl' ), [
688 'response' => 200,
689 ]
690 );
691 }
692
693
694 /**
695 * WPFunnels log
696 *
697 * @param $payload
698 *
699 * @return array
700 */
701 public static function wpfnl_show_log( $payload ) {
702 if( isset($payload['logKey']) ){
703 // Reduce to a bare filename — strips any directory traversal (../),
704 // separators, and stream-wrapper prefixes (phar://, php://, etc.).
705 $key = basename( wp_unslash( $payload['logKey'] ) );
706
707 $upload_dir = wp_upload_dir( null, false );
708 $log_url = trailingslashit( $upload_dir['basedir'] ) . 'wpfunnels/wpfunnels-logs/';
709 $file_url = $log_url . $key;
710
711 // Whitelist: key must be a .log filename that actually resolves inside
712 // the logs directory. realpath() comparison defeats any residual traversal.
713 $real_dir = realpath( $log_url );
714 $real_file = file_exists( $file_url ) ? realpath( $file_url ) : false;
715
716 $is_valid = $key
717 && '.log' === strtolower( substr( $key, -4 ) )
718 && $real_dir
719 && $real_file
720 && 0 === strpos( $real_file, trailingslashit( $real_dir ) );
721
722 if ( $is_valid ) {
723 // Never include/execute the log file — read it as data and escape it.
724 $out = file_get_contents( $file_url );
725 $out = '<pre>' . esc_html( $out ) . '</pre>';
726
727 return array(
728 'success' => true,
729 'content' => $out,
730 'file_url' => $file_url,
731 );
732 }
733
734 return array(
735 'success' => false,
736 'content' => '',
737 'file_url' => '',
738 );
739 }
740
741 return array(
742 'success' => false,
743 'content' => '',
744 'file_url' => ''
745 );
746
747
748 }
749
750
751 /**
752 * Send test notification email
753 *
754 * @param $payload
755 *
756 * @return array
757 * @since 3.2.0
758 */
759 public function send_test_notification( $payload ) {
760 if ( ! isset( $payload['email'] ) || ! is_email( $payload['email'] ) ) {
761 return array(
762 'success' => false,
763 'message' => __( 'Please provide a valid email address.', 'wpfnl' )
764 );
765 }
766
767 $settings = Wpfnl_functions::get_notification_settings();
768 $subject_template = isset( $settings['revenue_report_subject'] ) ? $settings['revenue_report_subject'] : 'Store Revenue Report - {period}';
769
770 // Calculate date range for test email (last week Monday to Sunday)
771 $start_date = date( 'Y-m-d', strtotime( 'last monday -1 week' ) );
772 $end_date = date( 'Y-m-d', strtotime( 'last sunday' ) );
773 $date_range = date( 'F j, Y', strtotime( $start_date ) ) . ' - ' . date( 'F j, Y', strtotime( $end_date ) );
774
775 $subject = '[Test] ' . str_replace( '{period}', $date_range, $subject_template );
776
777 $to = sanitize_email( $payload['email'] );
778 $message = $this->get_revenue_report_email_content( 'weekly' );
779 $headers = array( 'Content-Type: text/html; charset=UTF-8' );
780
781 $sent = wp_mail( $to, $subject, $message, $headers );
782
783 if ( $sent ) {
784 return array(
785 'success' => true,
786 'message' => __( 'Test email sent successfully! Please check your inbox.', 'wpfnl' )
787 );
788 } else {
789 return array(
790 'success' => false,
791 'message' => __( 'Failed to send test email. Please check your email configuration.', 'wpfnl' )
792 );
793 }
794 }
795
796
797 /**
798 * Send revenue report email (triggered by Action Scheduler)
799 *
800 * @since 3.2.0
801 */
802 public function send_revenue_report_email() {
803 $settings = Wpfnl_functions::get_notification_settings();
804
805 // Check if still enabled
806 if ( ! isset( $settings['enable_revenue_report'] ) || $settings['enable_revenue_report'] !== 'yes' ) {
807 return;
808 }
809
810 $recipients = isset( $settings['revenue_report_recipient'] ) ? $settings['revenue_report_recipient'] : get_option('admin_email');
811 $subject = isset( $settings['revenue_report_subject'] ) ? $settings['revenue_report_subject'] : 'Store Revenue Report - {period}';
812 $frequency = isset( $settings['revenue_report_frequency'] ) ? $settings['revenue_report_frequency'] : 'weekly';
813
814 // Calculate date range based on frequency
815 if ( $frequency === 'monthly' ) {
816 $start_date = date( 'Y-m-d', strtotime( 'first day of last month' ) );
817 $end_date = date( 'Y-m-d', strtotime( 'last day of last month' ) );
818 } else {
819 // Weekly: Last week Monday to Sunday
820 $start_date = date( 'Y-m-d', strtotime( 'last monday -1 week' ) );
821 $end_date = date( 'Y-m-d', strtotime( 'last sunday' ) );
822 }
823
824 $date_range = date( 'F j, Y', strtotime( $start_date ) ) . ' - ' . date( 'F j, Y', strtotime( $end_date ) );
825
826 // Replace {period} placeholder with date range
827 $subject = str_replace( '{period}', $date_range, $subject );
828
829 // Generate report content
830 $message = $this->get_revenue_report_email_content( $frequency );
831
832 // Prepare headers
833 $headers = array( 'Content-Type: text/html; charset=UTF-8' );
834
835 // Send email to recipients (can be multiple, comma-separated)
836 $recipient_array = array_map( 'trim', explode( ',', $recipients ) );
837
838 foreach ( $recipient_array as $recipient ) {
839 if ( is_email( $recipient ) ) {
840 wp_mail( sanitize_email( $recipient ), $subject, $message, $headers );
841 }
842 }
843 }
844
845
846 /**
847 * Get revenue report email content with actual data
848 *
849 * @param string $frequency
850 * @return string
851 * @since 3.2.0
852 */
853 private function get_revenue_report_email_content( $frequency = 'weekly' ) {
854 $site_name = get_bloginfo( 'name' );
855 $site_url = home_url();
856
857 // Calculate date range
858 if ( $frequency === 'monthly' ) {
859 $start_date = date( 'Y-m-d', strtotime( 'first day of last month' ) );
860 $end_date = date( 'Y-m-d', strtotime( 'last day of last month' ) );
861 $period_text = __( 'Monthly', 'wpfnl' );
862 } else {
863 // Weekly: Last week Monday to Sunday
864 $start_date = date( 'Y-m-d', strtotime( 'last monday -1 week' ) );
865 $end_date = date( 'Y-m-d', strtotime( 'last sunday' ) );
866 $period_text = __( 'Weekly', 'wpfnl' );
867 }
868
869 $date_range = date( 'F j, Y', strtotime( $start_date ) ) . ' - ' . date( 'F j, Y', strtotime( $end_date ) );
870
871 // Calculate previous period for comparison
872 if ( $frequency === 'monthly' ) {
873 $prev_start_date = date( 'Y-m-d', strtotime( 'first day of -2 months' ) );
874 $prev_end_date = date( 'Y-m-d', strtotime( 'last day of -2 months' ) );
875 } else {
876 $prev_start_date = date( 'Y-m-d', strtotime( 'last monday -2 weeks' ) );
877 $prev_end_date = date( 'Y-m-d', strtotime( 'last sunday -1 week' ) );
878 }
879
880 // Get revenue data for current and previous periods
881 $revenue_data = $this->get_revenue_data( $start_date, $end_date );
882 $previous_data = $this->get_revenue_data( $prev_start_date, $prev_end_date );
883
884 // Calculate percentage changes
885 $revenue_data['total_orders_change'] = $this->calculate_percentage_change( $previous_data['total_orders'], $revenue_data['total_orders'] );
886 $revenue_data['total_customers_change'] = $this->calculate_percentage_change( $previous_data['total_customers'], $revenue_data['total_customers'] );
887 $revenue_data['total_revenue_change'] = $this->calculate_percentage_change( $previous_data['total_revenue_raw'], $revenue_data['total_revenue_raw'] );
888 $revenue_data['average_order_value_change'] = $this->calculate_percentage_change( $previous_data['average_order_value_raw'], $revenue_data['average_order_value_raw'] );
889
890 // Build email with FunnelKit-style design
891 $message = '<!DOCTYPE html>';
892 $message .= '<html lang="en">';
893 $message .= '<head>';
894 $message .= '<meta charset="UTF-8">';
895 $message .= '<meta name="viewport" content="width=device-width, initial-scale=1.0">';
896 $message .= '<title>Performance Report</title>';
897 $message .= '</head>';
898 $message .= '<body style="margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, \'Segoe UI\', Roboto, \'Helvetica Neue\', Arial, sans-serif; background-color: #f5f5f5;">';
899
900 // Main container
901 $message .= '<table width="100%" border="0" cellspacing="0" cellpadding="0" style="background-color: #f5f5f5; padding: 40px 20px;">';
902 $message .= '<tr><td align="center">';
903 $message .= '<table width="600" border="0" cellspacing="0" cellpadding="0" style="background-color: #ffffff; border-radius: 8px; overflow: hidden; box-shadow: 0 2px 8px rgba(0,0,0,0.1);">';
904
905 // Top orange banner with text
906 $message .= '<tr><td style="background-color: #6e42d3; padding: 12px 40px; text-align: center;">';
907 $message .= '<div style="font-size: 16px; font-weight: 600; color: #ffffff;">Your ' . esc_html( strtolower( $frequency ) ) . ' summary from WPFunnels.</div>';
908 $message .= '</td></tr>';
909
910 // WPFunnels logo section
911 $message .= '<tr><td style="background-color: #ffffff; padding: 20px 40px 20px; text-align: center;">';
912 $message .= '<svg width="38" height="28" viewBox="0 0 38 28" fill="none" xmlns="http://www.w3.org/2000/svg" style="display: inline-block; margin-right: 10px; vertical-align: middle;">';
913 $message .= '<path d="M7.01532 18H31.9847L34 11H5L7.01532 18Z" fill="#EE8134"/>';
914 $message .= '<path d="M11.9621 27.2975C12.0923 27.7154 12.4792 28 12.9169 28H26.0831C26.5208 28 26.9077 27.7154 27.0379 27.2975L29 21H10L11.9621 27.2975Z" fill="#6E42D3"/>';
915 $message .= '<path d="M37.8161 0.65986C37.61 0.247888 37.2609 0 36.8867 0H1.11326C0.739128 0 0.390003 0.247888 0.183972 0.65986C-0.0220592 1.07193 -0.0573873 1.59277 0.0898627 2.04655L1.69781 7H36.3022L37.9102 2.04655C38.0574 1.59287 38.022 1.07193 37.8161 0.65986Z" fill="#6E42D3"/>';
916 $message .= '</svg>';
917 $message .= '<span style="font-size: 32px; font-weight: bold; color: #231748; vertical-align: middle;">WPFunnels</span>';
918 $message .= '</td></tr>';
919
920 // Date range, Performance Report title, and View Button - all in same background
921 $message .= '<tr><td style="padding: 20px 40px 30px; text-align: center; background-color: #f8f9fa;">';
922 // Date range
923 $message .= '<div style="font-size: 14px; color: #6c757d; font-weight: 500; margin-bottom: 20px;">' . esc_html( $date_range ) . '</div>';
924 // Performance Report title
925 $message .= '<h1 style="margin: 0 0 10px; font-size: 32px; font-weight: bold; color: #212529;">Store Revenue Summary</h1>';
926 $message .= '<p style="margin: 0 0 20px; font-size: 14px; color: #6c757d;">Track your store performance and revenue metrics for this period</p>';
927 // View Dashboard Button
928 $message .= '<a href="' . esc_url( admin_url( 'admin.php?page=wpfunnels' ) ) . '" style="display: inline-block; background-color: #6e42d3; color: #ffffff; text-decoration: none; padding: 12px 30px; border-radius: 5px; font-size: 14px; font-weight: 600;">View Dashboard</a>';
929 $message .= '</td></tr>';
930
931 // Key Performance Metrics section
932 $message .= '<tr><td style="padding: 20px 40px;">';
933 $message .= '<h2 style="margin: 0 0 10px; font-size: 24px; font-weight: bold; color: #212529; text-align: center;">Revenue Overview</h2>';
934 $message .= '<p style="margin: 0 0 30px; font-size: 14px; color: #6c757d; text-align: center;">Your ' . esc_html( strtolower( $frequency ) ) . ' performance snapshot</p>';
935
936 // Metrics grid
937 $message .= '<table width="100%" border="0" cellspacing="0" cellpadding="0">';
938
939 // Row 1: Total orders and Total contacts
940 $message .= '<tr>';
941 $message .= '<td width="50%" style="padding: 20px; vertical-align: top;">';
942 $message .= '<div style="text-align: left;">';
943 $message .= '<div style="font-size: 14px; color: #6c757d; margin-bottom: 10px; font-weight: 500;">Total orders</div>';
944 $message .= '<div style="font-size: 36px; font-weight: bold; color: #212529; margin-bottom: 5px;">' . esc_html( $revenue_data['total_orders'] ) . '</div>';
945 $message .= $revenue_data['total_orders_change'];
946 $message .= '</div>';
947 $message .= '</td>';
948 $message .= '<td width="50%" style="padding: 20px; vertical-align: top;">';
949 $message .= '<div style="text-align: left;">';
950 $message .= '<div style="font-size: 14px; color: #6c757d; margin-bottom: 10px; font-weight: 500;">Total customers</div>';
951 $message .= '<div style="font-size: 36px; font-weight: bold; color: #212529; margin-bottom: 5px;">' . esc_html( $revenue_data['total_customers'] ) . '</div>';
952 $message .= $revenue_data['total_customers_change'];
953 $message .= '</div>';
954 $message .= '</td>';
955 $message .= '</tr>';
956
957 // Row 2: Revenue and Bump revenue
958 $message .= '<tr>';
959 $message .= '<td width="50%" style="padding: 20px; vertical-align: top;">';
960 $message .= '<div style="text-align: left;">';
961 $message .= '<div style="font-size: 14px; color: #6c757d; margin-bottom: 10px; font-weight: 500;">Revenue</div>';
962 $message .= '<div style="font-size: 36px; font-weight: bold; color: #212529; margin-bottom: 5px;">' . wp_strip_all_tags( $revenue_data['total_revenue'] ) . '</div>';
963 $message .= $revenue_data['total_revenue_change'];
964 $message .= '</div>';
965 $message .= '</td>';
966 $message .= '<td width="50%" style="padding: 20px; vertical-align: top;">';
967 $message .= '<div style="text-align: left;">';
968 $message .= '<div style="font-size: 14px; color: #6c757d; margin-bottom: 10px; font-weight: 500;">Bump revenue</div>';
969 if ( Wpfnl_functions::is_wpfnl_pro_activated() ) {
970 $message .= '<div style="font-size: 36px; font-weight: bold; color: #212529; margin-bottom: 5px;">0 <span style="font-size: 18px; font-weight: normal; color: #6c757d;">USD</span></div>';
971 $message .= '<div style="font-size: 12px; color: #6c757d;">0% - Previous period</div>';
972 } else {
973 $message .= '<div style="font-size: 36px; margin-bottom: 5px;"><svg width="32" height="32" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M17 11V7C17 4.79086 15.2091 3 13 3H11C8.79086 3 7 4.79086 7 7V11M12 14V16M8 11H16C17.1046 11 18 11.8954 18 13V19C18 20.1046 17.1046 21 16 21H8C6.89543 21 6 20.1046 6 19V13C6 11.8954 6.89543 11 8 11Z" stroke="#6c757d" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></div>';
974 $message .= '<div style="font-size: 12px; color: #6c757d;">WPFunnels Pro</div>';
975 }
976 $message .= '</div>';
977 $message .= '</td>';
978 $message .= '</tr>';
979
980 // Row 3: Upsell revenue and Average order value
981 $message .= '<tr>';
982 $message .= '<td width="50%" style="padding: 20px; vertical-align: top;">';
983 $message .= '<div style="text-align: left;">';
984 $message .= '<div style="font-size: 14px; color: #6c757d; margin-bottom: 10px; font-weight: 500;">Upsell revenue</div>';
985 if ( Wpfnl_functions::is_wpfnl_pro_activated() ) {
986 $message .= '<div style="font-size: 36px; font-weight: bold; color: #212529; margin-bottom: 5px;">0 <span style="font-size: 18px; font-weight: normal; color: #6c757d;">USD</span></div>';
987 $message .= '<div style="font-size: 12px; color: #6c757d;">0% - Previous period</div>';
988 } else {
989 $message .= '<div style="font-size: 36px; margin-bottom: 5px;"><svg width="32" height="32" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M17 11V7C17 4.79086 15.2091 3 13 3H11C8.79086 3 7 4.79086 7 7V11M12 14V16M8 11H16C17.1046 11 18 11.8954 18 13V19C18 20.1046 17.1046 21 16 21H8C6.89543 21 6 20.1046 6 19V13C6 11.8954 6.89543 11 8 11Z" stroke="#6c757d" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></div>';
990 $message .= '<div style="font-size: 12px; color: #6c757d;">WPFunnels Pro</div>';
991 }
992 $message .= '</div>';
993 $message .= '</td>';
994 $message .= '<td width="50%" style="padding: 20px; vertical-align: top;">';
995 $message .= '<div style="text-align: left;">';
996 $message .= '<div style="font-size: 14px; color: #6c757d; margin-bottom: 10px; font-weight: 500;">Average order value</div>';
997 $message .= '<div style="font-size: 36px; font-weight: bold; color: #212529; margin-bottom: 5px;">' . wp_strip_all_tags( $revenue_data['average_order_value'] ) . '</div>';
998 $message .= $revenue_data['average_order_value_change'];
999 $message .= '</div>';
1000 $message .= '</td>';
1001 $message .= '</tr>';
1002
1003 $message .= '</table>';
1004 $message .= '</td></tr>';
1005
1006 // Additional revenue info
1007 if ( isset( $revenue_data['total_revenue_raw'] ) && $revenue_data['total_revenue_raw'] > 0 ) {
1008 $message .= '<tr><td style="padding: 20px 40px;">';
1009 $message .= '<div style="background-color: #fff3cd; border-left: 4px solid #ffc107; padding: 15px; border-radius: 4px;">';
1010 $message .= '<p style="margin: 0; font-size: 14px; color: #856404;">Since installing WPFunnels you have captured additional revenue of <strong>' . wp_kses_post( wc_price( $revenue_data['total_revenue_raw'] ) ) . '</strong></p>';
1011 $message .= '</div>';
1012 $message .= '</td></tr>';
1013 }
1014
1015 // Footer
1016 $message .= '<tr><td style="padding: 30px 40px; text-align: center; background-color: #ffffff; border-top: 1px solid #e9ecef;">';
1017 $message .= '<p style="margin: 0 0 10px; font-size: 12px; color: #6c757d;">This performance report email was sent from the <a href="' . esc_url( $site_url ) . '" style="color: #007bff; text-decoration: none;">' . esc_html( $site_name ) . '</a> by admin ' . esc_html( date( 'F j, Y' ) ) . '</p>';
1018 $message .= '<p style="margin: 0; font-size: 12px; color: #6c757d;"><a href="' . esc_url( admin_url( 'admin.php?page=wpfnl_settings#notifications-settings' ) ) . '" style="color: #007bff; text-decoration: none;">Click here</a> to change the frequency and recipients.</p>';
1019 $message .= '</td></tr>';
1020
1021 $message .= '</table>';
1022 $message .= '</td></tr>';
1023 $message .= '</table>';
1024
1025 $message .= '</body>';
1026 $message .= '</html>';
1027
1028 return $message;
1029 }
1030
1031
1032 /**
1033 * Get revenue data from WPFunnels stats
1034 *
1035 * @param string $start_date
1036 * @param string $end_date
1037 * @return array
1038 * @since 3.2.0
1039 */
1040 private function get_revenue_data( $start_date, $end_date ) {
1041 global $wpdb;
1042 $table = $wpdb->prefix . 'wpfnl_stats';
1043
1044 // Get total orders count
1045 $total_orders = $wpdb->get_var( $wpdb->prepare(
1046 "SELECT COUNT(id) FROM $table WHERE date_created >= %s AND date_created <= %s AND status = 'completed'",
1047 $start_date,
1048 $end_date . ' 23:59:59'
1049 ) );
1050
1051 // Get total revenue (total_sales includes everything: checkout + order bump + upsell + downsell)
1052 $total_revenue_raw = $wpdb->get_var( $wpdb->prepare(
1053 "SELECT SUM(total_sales) FROM $table WHERE date_created >= %s AND date_created <= %s AND status = 'completed'",
1054 $start_date,
1055 $end_date . ' 23:59:59'
1056 ) );
1057
1058 // Get total customers (unique customer_id)
1059 $total_customers = $wpdb->get_var( $wpdb->prepare(
1060 "SELECT COUNT(DISTINCT customer_id) FROM $table WHERE date_created >= %s AND date_created <= %s AND status = 'completed'",
1061 $start_date,
1062 $end_date . ' 23:59:59'
1063 ) );
1064
1065 // Calculate average order value
1066 $total_orders_int = intval( $total_orders );
1067 $total_revenue_float = floatval( $total_revenue_raw );
1068 $average = $total_orders_int > 0 ? $total_revenue_float / $total_orders_int : 0;
1069
1070 // Format data
1071 $data = array(
1072 'total_revenue' => function_exists( 'wc_price' ) ? wc_price( $total_revenue_float ) : '$' . number_format( $total_revenue_float, 2 ),
1073 'total_revenue_raw' => $total_revenue_float,
1074 'total_orders' => $total_orders_int,
1075 'total_customers' => intval( $total_customers ),
1076 'average_order_value' => function_exists( 'wc_price' ) ? wc_price( $average ) : '$' . number_format( $average, 2 ),
1077 'average_order_value_raw' => $average,
1078 );
1079
1080 return $data;
1081 }
1082
1083
1084 /**
1085 * Calculate percentage change between two values
1086 *
1087 * @param float $old_value
1088 * @param float $new_value
1089 * @return string HTML formatted percentage change
1090 * @since 3.2.0
1091 */
1092 private function calculate_percentage_change( $old_value, $new_value ) {
1093 $old_value = floatval( $old_value );
1094 $new_value = floatval( $new_value );
1095
1096 if ( $old_value == 0 ) {
1097 if ( $new_value > 0 ) {
1098 return '<div style="font-size: 12px; color: #28a745;">+100% - Previous period</div>';
1099 } else {
1100 return '<div style="font-size: 12px; color: #6c757d;">0% - Previous period</div>';
1101 }
1102 }
1103
1104 $change = ( ( $new_value - $old_value ) / $old_value ) * 100;
1105 $change_formatted = number_format( abs( $change ), 1 );
1106
1107 if ( $change > 0 ) {
1108 return '<div style="font-size: 12px; color: #28a745;">+' . $change_formatted . '% - Previous period</div>';
1109 } elseif ( $change < 0 ) {
1110 return '<div style="font-size: 12px; color: #dc3545;">-' . $change_formatted . '% - Previous period</div>';
1111 } else {
1112 return '<div style="font-size: 12px; color: #6c757d;">0% - Previous period</div>';
1113 }
1114 }
1115
1116
1117 /**
1118 * WPFunnels log
1119 *
1120 * @param $payload
1121 *
1122 * @return array
1123 */
1124 public static function wpfnl_delete_log( $payload ) {
1125 if( isset($payload['logKey']) ){
1126 $key = sanitize_file_name( basename( $payload['logKey'] ) );
1127 $upload_dir = wp_upload_dir( null, false );
1128 $log_dir = $upload_dir['basedir'].'/wpfunnels/wpfunnels-logs/';
1129 $file_name = $log_dir . $key;
1130
1131 // Verify the resolved path is within the log directory
1132 $real_file = realpath($file_name);
1133 $real_log_dir = realpath($log_dir);
1134
1135 if ( $real_file && $real_log_dir && strpos( $real_file, $real_log_dir ) === 0 ) {
1136 $response = \Wpfnl_Logger::delete_log_file( $file_name );
1137 if( $response ){
1138 return array('success' => true);
1139 }
1140 }
1141 }
1142
1143 return array(
1144 'success' => false,
1145 'content' => '',
1146 'file_url' => ''
1147 );
1148 }
1149 }
1150