PluginProbe
WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell / 3.12.2
WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell v3.12.2
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.2, at admin/modules/settings/class-wpfnl-settings.php

1,129 lines 42.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 $key = $payload['logKey'];
704 $upload_dir = wp_upload_dir( null, false );
705 $log_url = $upload_dir['basedir'].'/wpfunnels/wpfunnels-logs/';
706 $file_url = $log_url . $key;
707
708 ob_start();
709 include_once $file_url;
710 $out = ob_get_clean();
711 ob_end_clean();
712
713 return array(
714 'success' => true,
715 'content' => $out,
716 'file_url' => $log_url. $key
717 );
718 }
719
720 return array(
721 'success' => false,
722 'content' => '',
723 'file_url' => ''
724 );
725
726
727 }
728
729
730 /**
731 * Send test notification email
732 *
733 * @param $payload
734 *
735 * @return array
736 * @since 3.2.0
737 */
738 public function send_test_notification( $payload ) {
739 if ( ! isset( $payload['email'] ) || ! is_email( $payload['email'] ) ) {
740 return array(
741 'success' => false,
742 'message' => __( 'Please provide a valid email address.', 'wpfnl' )
743 );
744 }
745
746 $settings = Wpfnl_functions::get_notification_settings();
747 $subject_template = isset( $settings['revenue_report_subject'] ) ? $settings['revenue_report_subject'] : 'Store Revenue Report - {period}';
748
749 // Calculate date range for test email (last week Monday to Sunday)
750 $start_date = date( 'Y-m-d', strtotime( 'last monday -1 week' ) );
751 $end_date = date( 'Y-m-d', strtotime( 'last sunday' ) );
752 $date_range = date( 'F j, Y', strtotime( $start_date ) ) . ' - ' . date( 'F j, Y', strtotime( $end_date ) );
753
754 $subject = '[Test] ' . str_replace( '{period}', $date_range, $subject_template );
755
756 $to = sanitize_email( $payload['email'] );
757 $message = $this->get_revenue_report_email_content( 'weekly' );
758 $headers = array( 'Content-Type: text/html; charset=UTF-8' );
759
760 $sent = wp_mail( $to, $subject, $message, $headers );
761
762 if ( $sent ) {
763 return array(
764 'success' => true,
765 'message' => __( 'Test email sent successfully! Please check your inbox.', 'wpfnl' )
766 );
767 } else {
768 return array(
769 'success' => false,
770 'message' => __( 'Failed to send test email. Please check your email configuration.', 'wpfnl' )
771 );
772 }
773 }
774
775
776 /**
777 * Send revenue report email (triggered by Action Scheduler)
778 *
779 * @since 3.2.0
780 */
781 public function send_revenue_report_email() {
782 $settings = Wpfnl_functions::get_notification_settings();
783
784 // Check if still enabled
785 if ( ! isset( $settings['enable_revenue_report'] ) || $settings['enable_revenue_report'] !== 'yes' ) {
786 return;
787 }
788
789 $recipients = isset( $settings['revenue_report_recipient'] ) ? $settings['revenue_report_recipient'] : get_option('admin_email');
790 $subject = isset( $settings['revenue_report_subject'] ) ? $settings['revenue_report_subject'] : 'Store Revenue Report - {period}';
791 $frequency = isset( $settings['revenue_report_frequency'] ) ? $settings['revenue_report_frequency'] : 'weekly';
792
793 // Calculate date range based on frequency
794 if ( $frequency === 'monthly' ) {
795 $start_date = date( 'Y-m-d', strtotime( 'first day of last month' ) );
796 $end_date = date( 'Y-m-d', strtotime( 'last day of last month' ) );
797 } else {
798 // Weekly: Last week Monday to Sunday
799 $start_date = date( 'Y-m-d', strtotime( 'last monday -1 week' ) );
800 $end_date = date( 'Y-m-d', strtotime( 'last sunday' ) );
801 }
802
803 $date_range = date( 'F j, Y', strtotime( $start_date ) ) . ' - ' . date( 'F j, Y', strtotime( $end_date ) );
804
805 // Replace {period} placeholder with date range
806 $subject = str_replace( '{period}', $date_range, $subject );
807
808 // Generate report content
809 $message = $this->get_revenue_report_email_content( $frequency );
810
811 // Prepare headers
812 $headers = array( 'Content-Type: text/html; charset=UTF-8' );
813
814 // Send email to recipients (can be multiple, comma-separated)
815 $recipient_array = array_map( 'trim', explode( ',', $recipients ) );
816
817 foreach ( $recipient_array as $recipient ) {
818 if ( is_email( $recipient ) ) {
819 wp_mail( sanitize_email( $recipient ), $subject, $message, $headers );
820 }
821 }
822 }
823
824
825 /**
826 * Get revenue report email content with actual data
827 *
828 * @param string $frequency
829 * @return string
830 * @since 3.2.0
831 */
832 private function get_revenue_report_email_content( $frequency = 'weekly' ) {
833 $site_name = get_bloginfo( 'name' );
834 $site_url = home_url();
835
836 // Calculate date range
837 if ( $frequency === 'monthly' ) {
838 $start_date = date( 'Y-m-d', strtotime( 'first day of last month' ) );
839 $end_date = date( 'Y-m-d', strtotime( 'last day of last month' ) );
840 $period_text = __( 'Monthly', 'wpfnl' );
841 } else {
842 // Weekly: Last week Monday to Sunday
843 $start_date = date( 'Y-m-d', strtotime( 'last monday -1 week' ) );
844 $end_date = date( 'Y-m-d', strtotime( 'last sunday' ) );
845 $period_text = __( 'Weekly', 'wpfnl' );
846 }
847
848 $date_range = date( 'F j, Y', strtotime( $start_date ) ) . ' - ' . date( 'F j, Y', strtotime( $end_date ) );
849
850 // Calculate previous period for comparison
851 if ( $frequency === 'monthly' ) {
852 $prev_start_date = date( 'Y-m-d', strtotime( 'first day of -2 months' ) );
853 $prev_end_date = date( 'Y-m-d', strtotime( 'last day of -2 months' ) );
854 } else {
855 $prev_start_date = date( 'Y-m-d', strtotime( 'last monday -2 weeks' ) );
856 $prev_end_date = date( 'Y-m-d', strtotime( 'last sunday -1 week' ) );
857 }
858
859 // Get revenue data for current and previous periods
860 $revenue_data = $this->get_revenue_data( $start_date, $end_date );
861 $previous_data = $this->get_revenue_data( $prev_start_date, $prev_end_date );
862
863 // Calculate percentage changes
864 $revenue_data['total_orders_change'] = $this->calculate_percentage_change( $previous_data['total_orders'], $revenue_data['total_orders'] );
865 $revenue_data['total_customers_change'] = $this->calculate_percentage_change( $previous_data['total_customers'], $revenue_data['total_customers'] );
866 $revenue_data['total_revenue_change'] = $this->calculate_percentage_change( $previous_data['total_revenue_raw'], $revenue_data['total_revenue_raw'] );
867 $revenue_data['average_order_value_change'] = $this->calculate_percentage_change( $previous_data['average_order_value_raw'], $revenue_data['average_order_value_raw'] );
868
869 // Build email with FunnelKit-style design
870 $message = '<!DOCTYPE html>';
871 $message .= '<html lang="en">';
872 $message .= '<head>';
873 $message .= '<meta charset="UTF-8">';
874 $message .= '<meta name="viewport" content="width=device-width, initial-scale=1.0">';
875 $message .= '<title>Performance Report</title>';
876 $message .= '</head>';
877 $message .= '<body style="margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, \'Segoe UI\', Roboto, \'Helvetica Neue\', Arial, sans-serif; background-color: #f5f5f5;">';
878
879 // Main container
880 $message .= '<table width="100%" border="0" cellspacing="0" cellpadding="0" style="background-color: #f5f5f5; padding: 40px 20px;">';
881 $message .= '<tr><td align="center">';
882 $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);">';
883
884 // Top orange banner with text
885 $message .= '<tr><td style="background-color: #6e42d3; padding: 12px 40px; text-align: center;">';
886 $message .= '<div style="font-size: 16px; font-weight: 600; color: #ffffff;">Your ' . esc_html( strtolower( $frequency ) ) . ' summary from WPFunnels.</div>';
887 $message .= '</td></tr>';
888
889 // WPFunnels logo section
890 $message .= '<tr><td style="background-color: #ffffff; padding: 20px 40px 20px; text-align: center;">';
891 $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;">';
892 $message .= '<path d="M7.01532 18H31.9847L34 11H5L7.01532 18Z" fill="#EE8134"/>';
893 $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"/>';
894 $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"/>';
895 $message .= '</svg>';
896 $message .= '<span style="font-size: 32px; font-weight: bold; color: #231748; vertical-align: middle;">WPFunnels</span>';
897 $message .= '</td></tr>';
898
899 // Date range, Performance Report title, and View Button - all in same background
900 $message .= '<tr><td style="padding: 20px 40px 30px; text-align: center; background-color: #f8f9fa;">';
901 // Date range
902 $message .= '<div style="font-size: 14px; color: #6c757d; font-weight: 500; margin-bottom: 20px;">' . esc_html( $date_range ) . '</div>';
903 // Performance Report title
904 $message .= '<h1 style="margin: 0 0 10px; font-size: 32px; font-weight: bold; color: #212529;">Store Revenue Summary</h1>';
905 $message .= '<p style="margin: 0 0 20px; font-size: 14px; color: #6c757d;">Track your store performance and revenue metrics for this period</p>';
906 // View Dashboard Button
907 $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>';
908 $message .= '</td></tr>';
909
910 // Key Performance Metrics section
911 $message .= '<tr><td style="padding: 20px 40px;">';
912 $message .= '<h2 style="margin: 0 0 10px; font-size: 24px; font-weight: bold; color: #212529; text-align: center;">Revenue Overview</h2>';
913 $message .= '<p style="margin: 0 0 30px; font-size: 14px; color: #6c757d; text-align: center;">Your ' . esc_html( strtolower( $frequency ) ) . ' performance snapshot</p>';
914
915 // Metrics grid
916 $message .= '<table width="100%" border="0" cellspacing="0" cellpadding="0">';
917
918 // Row 1: Total orders and Total contacts
919 $message .= '<tr>';
920 $message .= '<td width="50%" style="padding: 20px; vertical-align: top;">';
921 $message .= '<div style="text-align: left;">';
922 $message .= '<div style="font-size: 14px; color: #6c757d; margin-bottom: 10px; font-weight: 500;">Total orders</div>';
923 $message .= '<div style="font-size: 36px; font-weight: bold; color: #212529; margin-bottom: 5px;">' . esc_html( $revenue_data['total_orders'] ) . '</div>';
924 $message .= $revenue_data['total_orders_change'];
925 $message .= '</div>';
926 $message .= '</td>';
927 $message .= '<td width="50%" style="padding: 20px; vertical-align: top;">';
928 $message .= '<div style="text-align: left;">';
929 $message .= '<div style="font-size: 14px; color: #6c757d; margin-bottom: 10px; font-weight: 500;">Total customers</div>';
930 $message .= '<div style="font-size: 36px; font-weight: bold; color: #212529; margin-bottom: 5px;">' . esc_html( $revenue_data['total_customers'] ) . '</div>';
931 $message .= $revenue_data['total_customers_change'];
932 $message .= '</div>';
933 $message .= '</td>';
934 $message .= '</tr>';
935
936 // Row 2: Revenue and Bump revenue
937 $message .= '<tr>';
938 $message .= '<td width="50%" style="padding: 20px; vertical-align: top;">';
939 $message .= '<div style="text-align: left;">';
940 $message .= '<div style="font-size: 14px; color: #6c757d; margin-bottom: 10px; font-weight: 500;">Revenue</div>';
941 $message .= '<div style="font-size: 36px; font-weight: bold; color: #212529; margin-bottom: 5px;">' . wp_strip_all_tags( $revenue_data['total_revenue'] ) . '</div>';
942 $message .= $revenue_data['total_revenue_change'];
943 $message .= '</div>';
944 $message .= '</td>';
945 $message .= '<td width="50%" style="padding: 20px; vertical-align: top;">';
946 $message .= '<div style="text-align: left;">';
947 $message .= '<div style="font-size: 14px; color: #6c757d; margin-bottom: 10px; font-weight: 500;">Bump revenue</div>';
948 if ( Wpfnl_functions::is_wpfnl_pro_activated() ) {
949 $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>';
950 $message .= '<div style="font-size: 12px; color: #6c757d;">0% - Previous period</div>';
951 } else {
952 $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>';
953 $message .= '<div style="font-size: 12px; color: #6c757d;">WPFunnels Pro</div>';
954 }
955 $message .= '</div>';
956 $message .= '</td>';
957 $message .= '</tr>';
958
959 // Row 3: Upsell revenue and Average order value
960 $message .= '<tr>';
961 $message .= '<td width="50%" style="padding: 20px; vertical-align: top;">';
962 $message .= '<div style="text-align: left;">';
963 $message .= '<div style="font-size: 14px; color: #6c757d; margin-bottom: 10px; font-weight: 500;">Upsell revenue</div>';
964 if ( Wpfnl_functions::is_wpfnl_pro_activated() ) {
965 $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>';
966 $message .= '<div style="font-size: 12px; color: #6c757d;">0% - Previous period</div>';
967 } else {
968 $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>';
969 $message .= '<div style="font-size: 12px; color: #6c757d;">WPFunnels Pro</div>';
970 }
971 $message .= '</div>';
972 $message .= '</td>';
973 $message .= '<td width="50%" style="padding: 20px; vertical-align: top;">';
974 $message .= '<div style="text-align: left;">';
975 $message .= '<div style="font-size: 14px; color: #6c757d; margin-bottom: 10px; font-weight: 500;">Average order value</div>';
976 $message .= '<div style="font-size: 36px; font-weight: bold; color: #212529; margin-bottom: 5px;">' . wp_strip_all_tags( $revenue_data['average_order_value'] ) . '</div>';
977 $message .= $revenue_data['average_order_value_change'];
978 $message .= '</div>';
979 $message .= '</td>';
980 $message .= '</tr>';
981
982 $message .= '</table>';
983 $message .= '</td></tr>';
984
985 // Additional revenue info
986 if ( isset( $revenue_data['total_revenue_raw'] ) && $revenue_data['total_revenue_raw'] > 0 ) {
987 $message .= '<tr><td style="padding: 20px 40px;">';
988 $message .= '<div style="background-color: #fff3cd; border-left: 4px solid #ffc107; padding: 15px; border-radius: 4px;">';
989 $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>';
990 $message .= '</div>';
991 $message .= '</td></tr>';
992 }
993
994 // Footer
995 $message .= '<tr><td style="padding: 30px 40px; text-align: center; background-color: #ffffff; border-top: 1px solid #e9ecef;">';
996 $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>';
997 $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>';
998 $message .= '</td></tr>';
999
1000 $message .= '</table>';
1001 $message .= '</td></tr>';
1002 $message .= '</table>';
1003
1004 $message .= '</body>';
1005 $message .= '</html>';
1006
1007 return $message;
1008 }
1009
1010
1011 /**
1012 * Get revenue data from WPFunnels stats
1013 *
1014 * @param string $start_date
1015 * @param string $end_date
1016 * @return array
1017 * @since 3.2.0
1018 */
1019 private function get_revenue_data( $start_date, $end_date ) {
1020 global $wpdb;
1021 $table = $wpdb->prefix . 'wpfnl_stats';
1022
1023 // Get total orders count
1024 $total_orders = $wpdb->get_var( $wpdb->prepare(
1025 "SELECT COUNT(id) FROM $table WHERE date_created >= %s AND date_created <= %s AND status = 'completed'",
1026 $start_date,
1027 $end_date . ' 23:59:59'
1028 ) );
1029
1030 // Get total revenue (total_sales includes everything: checkout + order bump + upsell + downsell)
1031 $total_revenue_raw = $wpdb->get_var( $wpdb->prepare(
1032 "SELECT SUM(total_sales) FROM $table WHERE date_created >= %s AND date_created <= %s AND status = 'completed'",
1033 $start_date,
1034 $end_date . ' 23:59:59'
1035 ) );
1036
1037 // Get total customers (unique customer_id)
1038 $total_customers = $wpdb->get_var( $wpdb->prepare(
1039 "SELECT COUNT(DISTINCT customer_id) FROM $table WHERE date_created >= %s AND date_created <= %s AND status = 'completed'",
1040 $start_date,
1041 $end_date . ' 23:59:59'
1042 ) );
1043
1044 // Calculate average order value
1045 $total_orders_int = intval( $total_orders );
1046 $total_revenue_float = floatval( $total_revenue_raw );
1047 $average = $total_orders_int > 0 ? $total_revenue_float / $total_orders_int : 0;
1048
1049 // Format data
1050 $data = array(
1051 'total_revenue' => function_exists( 'wc_price' ) ? wc_price( $total_revenue_float ) : '$' . number_format( $total_revenue_float, 2 ),
1052 'total_revenue_raw' => $total_revenue_float,
1053 'total_orders' => $total_orders_int,
1054 'total_customers' => intval( $total_customers ),
1055 'average_order_value' => function_exists( 'wc_price' ) ? wc_price( $average ) : '$' . number_format( $average, 2 ),
1056 'average_order_value_raw' => $average,
1057 );
1058
1059 return $data;
1060 }
1061
1062
1063 /**
1064 * Calculate percentage change between two values
1065 *
1066 * @param float $old_value
1067 * @param float $new_value
1068 * @return string HTML formatted percentage change
1069 * @since 3.2.0
1070 */
1071 private function calculate_percentage_change( $old_value, $new_value ) {
1072 $old_value = floatval( $old_value );
1073 $new_value = floatval( $new_value );
1074
1075 if ( $old_value == 0 ) {
1076 if ( $new_value > 0 ) {
1077 return '<div style="font-size: 12px; color: #28a745;">+100% - Previous period</div>';
1078 } else {
1079 return '<div style="font-size: 12px; color: #6c757d;">0% - Previous period</div>';
1080 }
1081 }
1082
1083 $change = ( ( $new_value - $old_value ) / $old_value ) * 100;
1084 $change_formatted = number_format( abs( $change ), 1 );
1085
1086 if ( $change > 0 ) {
1087 return '<div style="font-size: 12px; color: #28a745;">+' . $change_formatted . '% - Previous period</div>';
1088 } elseif ( $change < 0 ) {
1089 return '<div style="font-size: 12px; color: #dc3545;">-' . $change_formatted . '% - Previous period</div>';
1090 } else {
1091 return '<div style="font-size: 12px; color: #6c757d;">0% - Previous period</div>';
1092 }
1093 }
1094
1095
1096 /**
1097 * WPFunnels log
1098 *
1099 * @param $payload
1100 *
1101 * @return array
1102 */
1103 public static function wpfnl_delete_log( $payload ) {
1104 if( isset($payload['logKey']) ){
1105 $key = sanitize_file_name( basename( $payload['logKey'] ) );
1106 $upload_dir = wp_upload_dir( null, false );
1107 $log_dir = $upload_dir['basedir'].'/wpfunnels/wpfunnels-logs/';
1108 $file_name = $log_dir . $key;
1109
1110 // Verify the resolved path is within the log directory
1111 $real_file = realpath($file_name);
1112 $real_log_dir = realpath($log_dir);
1113
1114 if ( $real_file && $real_log_dir && strpos( $real_file, $real_log_dir ) === 0 ) {
1115 $response = \Wpfnl_Logger::delete_log_file( $file_name );
1116 if( $response ){
1117 return array('success' => true);
1118 }
1119 }
1120 }
1121
1122 return array(
1123 'success' => false,
1124 'content' => '',
1125 'file_url' => ''
1126 );
1127 }
1128 }
1129