PluginProbe
Better Payment – Instant Payments, Donations, Fundraising with Subscriptions & More / 2.2.0
Better Payment – Instant Payments, Donations, Fundraising with Subscriptions & More v2.2.0
2.3.4 2.3.3 2.3.2 2.3.1 2.3.0 2.2.2 2.2.1 2.2.0 2.1.2 2.1.1 trunk 0.0.1 0.0.2 0.0.3 0.0.4 0.0.5 0.0.6 0.0.7 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 All 66 releases
better-payment / includes / Classes / Plugin_Usage_Tracker.php

Plugin_Usage_Tracker.php in Better Payment – Instant Payments, Donations, Fundraising with Subscriptions & More 2.2.0, at includes/Classes/Plugin_Usage_Tracker.php

948 lines 38.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Better_Payment\Lite\Classes;
4
5 use Better_Payment\Lite\Traits\Helper;
6
7 /**
8 * Exit if accessed directly
9 */
10 if (!defined('ABSPATH')) {
11 exit;
12 }
13
14 /**
15 * Plugin_Usage_Tracker
16 * This class is responsible for data sending to insights.
17 * @version 0.0.2
18 */
19
20 /**
21 * Main SDK for Plugin_Usage_Tracker.
22 */
23 class Plugin_Usage_Tracker
24 {
25 use Helper;
26
27 /**
28 * WP Insights Version
29 */
30 const WPINS_VERSION = '3.0.3';
31 /**
32 * API URL
33 */
34 const API_URL = 'https://send.wpinsight.com/process-plugin-data';
35 /**
36 * Installed Plugin File
37 *
38 * @var string
39 */
40 private $plugin_file = null;
41 /**
42 * Installed Plugin Name
43 *
44 * @var string
45 */
46 private $plugin_name = null;
47 /**
48 * How often the event should subsequently
49 * @var string
50 */
51 public $recurrence = 'daily';
52 private $event_hook = null;
53 /**
54 * Instace of Plugin_Usage_Tracker
55 * @var Plugin_Usage_Tracker
56 */
57 private static $_instance = null;
58
59 private $disabled_wp_cron;
60 private $enable_self_cron;
61 private $require_optin;
62 private $include_goodbye_form;
63 private $marketing;
64 private $options;
65 private $item_id;
66 private $notice_options;
67
68 /**
69 * Get Instance of Plugin_Usage_Tracker
70 * @return Plugin_Usage_Tracker
71 */
72 public static function get_instance($plugin_file, $args = [])
73 {
74 if (is_null(static::$_instance)) {
75 static::$_instance = new static($plugin_file, $args);
76 }
77 return static::$_instance;
78 }
79 /**
80 * Automatically Invoked when initialized.
81 *
82 * @param array $args
83 */
84 public function __construct($plugin_file, $args = [])
85 {
86 $this->plugin_file = $plugin_file;
87 $this->plugin_name = basename($this->plugin_file, '.php');
88 $this->disabled_wp_cron = defined('DISABLE_WP_CRON') && DISABLE_WP_CRON == true;
89 $this->enable_self_cron = $this->disabled_wp_cron == true ? true : false;
90
91 $this->event_hook = 'put_do_weekly_action';
92
93 $this->require_optin = isset($args['opt_in']) ? $args['opt_in'] : true;
94 $this->include_goodbye_form = isset($args['goodbye_form']) ? $args['goodbye_form'] : true;
95 $this->marketing = isset($args['email_marketing']) ? $args['email_marketing'] : true;
96 $this->options = isset($args['options']) ? $args['options'] : [];
97 $this->item_id = isset($args['item_id']) ? $args['item_id'] : false;
98 /**
99 * Activation Hook
100 */
101 register_activation_hook($this->plugin_file, array($this, 'activate_this_plugin'));
102 /**
103 * Deactivation Hook
104 */
105 register_deactivation_hook($this->plugin_file, array($this, 'deactivate_this_plugin'));
106 }
107 /**
108 * When user agreed to opt-in tracking schedule is enabled.
109 * @since 3.0.0
110 */
111 public function schedule_tracking()
112 {
113 if ($this->disabled_wp_cron) {
114 return;
115 }
116 if (!wp_next_scheduled($this->event_hook)) {
117 wp_schedule_event(time(), $this->recurrence, $this->event_hook);
118 }
119 }
120 /**
121 * Add the schedule event if the plugin is tracked.
122 *
123 * @return void
124 */
125 public function activate_this_plugin()
126 {
127 $allow_tracking = $this->is_tracking_allowed();
128 if (!$allow_tracking) {
129 return;
130 }
131 $this->schedule_tracking();
132 }
133 /**
134 * Remove the schedule event when plugin is deactivated and send the deactivated reason to inishghts if user submitted.
135 * @since 3.0.0
136 */
137 public function deactivate_this_plugin()
138 {
139 /**
140 * Check tracking is allowed or not.
141 */
142 $allow_tracking = $this->is_tracking_allowed();
143 if (!$allow_tracking) {
144 return;
145 }
146 $body = $this->get_data();
147 $body['status'] = 'Deactivated';
148 $body['deactivated_date'] = time();
149
150 // Check deactivation reason and add for insights data.
151 if (false !== get_option('wpins_deactivation_reason_' . $this->plugin_name)) {
152 $body['deactivation_reason'] = get_option('wpins_deactivation_reason_' . $this->plugin_name);
153 }
154 if (false !== get_option('wpins_deactivation_details_' . $this->plugin_name)) {
155 $body['deactivation_details'] = get_option('wpins_deactivation_details_' . $this->plugin_name);
156 }
157
158 $this->send_data($body);
159 delete_option('wpins_deactivation_reason_' . $this->plugin_name);
160 delete_option('wpins_deactivation_details_' . $this->plugin_name);
161 /**
162 * Clear the event schedule.
163 */
164 if (!$this->disabled_wp_cron) {
165 wp_clear_scheduled_hook($this->event_hook);
166 }
167 }
168 /**
169 * Initial Method to Hook Everything.
170 * @return void
171 */
172 public function init()
173 {
174 // $this->clicked();
175 add_action('wpdeveloper_notice_clicked_for_' . $this->plugin_name, array($this, 'clicked'));
176 add_action($this->event_hook, array($this, 'do_tracking'));
177 // For Test
178 // add_action( 'admin_init', array( $this, 'force_tracking' ) );
179 // add_action( 'admin_notices', array( $this, 'notice' ) );
180 add_action('wpdeveloper_optin_notice_for_' . $this->plugin_name, array($this, 'notice'));
181 /**
182 * Deactivation Reason Form and Submit Data to Insights.
183 */
184 add_filter('plugin_action_links_' . plugin_basename($this->plugin_file), array($this, 'deactivate_action_links'));
185 add_action('admin_footer-plugins.php', array($this, 'deactivate_reasons_form'));
186 add_action('wp_ajax_deactivation_form_' . esc_attr($this->plugin_name), array($this, 'deactivate_reasons_form_submit'));
187 }
188 /**
189 * For Redirecting Current Page without Arguments!
190 *
191 * @return void
192 */
193 private function redirect_to()
194 {
195 $request_uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
196 $query_string = parse_url($_SERVER['REQUEST_URI'], PHP_URL_QUERY);
197 parse_str($query_string, $current_url);
198
199 $unset_array = array('dismiss', 'plugin', '_wpnonce', 'later', 'plugin_action', 'marketing_optin');
200
201 foreach ($unset_array as $value) {
202 if (isset($current_url[$value])) {
203 unset($current_url[$value]);
204 }
205 }
206
207 $current_url = http_build_query($current_url);
208 $redirect_url = $request_uri . '?' . $current_url;
209 return $redirect_url;
210 }
211 /**
212 * This method forcing the do_tracking method to execute instant.
213 * @return void
214 */
215 public function force_tracking()
216 {
217 $this->do_tracking(true);
218 }
219 /**
220 * This method is responsible for all the magic from the front of the plugin.
221 * @since 3.0.0
222 * @param $force Force tracking if it's not the correct time to track/
223 */
224 public function do_tracking($force = false)
225 {
226 /**
227 * Check URL is set or not.
228 */
229 if (empty(self::API_URL)) {
230 return;
231 }
232 /**
233 * Check is tracking allowed or not.
234 */
235 if (!$this->is_tracking_allowed()) {
236 return;
237 }
238 /**
239 * Check is this the correct time to track or not.
240 * or Force to track.
241 */
242 if (!$this->is_time_to_track() && !$force) {
243 return;
244 }
245 /**
246 * Get All Data.
247 */
248 $body = $this->get_data();
249 /**
250 * Send all data.
251 */
252 return $this->send_data($body);
253 }
254 /**
255 * Is tracking allowed?
256 * @since 1.0.0
257 */
258 private function is_tracking_allowed()
259 {
260 // First, check if the user has changed their mind and opted out of tracking
261 if ($this->has_user_opted_out()) {
262 $this->set_is_tracking_allowed(false, $this->plugin_name);
263 return false;
264 }
265 // The wpins_allow_tracking option is an array of plugins that are being tracked
266 $allow_tracking = get_option('wpins_allow_tracking');
267 // If this plugin is in the array, then tracking is allowed
268 if (isset($allow_tracking[$this->plugin_name])) {
269 return true;
270 }
271 return false;
272 }
273 /**
274 * Set a flag in DB If tracking is allowed.
275 *
276 * @since 3.0.0
277 * @param $is_allowed Boolean true if is allowed.
278 */
279 public function set_is_tracking_allowed($is_allowed, $plugin = null)
280 {
281 if (empty($plugin)) {
282 $plugin = $this->plugin_name;
283 }
284 /**
285 * Get All Tracked Plugin List using this Tracker.
286 */
287 $allow_tracking = get_option('wpins_allow_tracking');
288 /**
289 * Check user is opted out for tracking or not.
290 */
291 if ($this->has_user_opted_out()) {
292 if (isset($allow_tracking[$plugin])) {
293 unset($allow_tracking[$plugin]);
294 }
295 } else if ($is_allowed || !$this->require_optin) {
296 /**
297 * If user has agreed to allow tracking
298 */
299 if (empty($allow_tracking) || !is_array($allow_tracking)) {
300 $allow_tracking = array($plugin => $plugin);
301 } else {
302 $allow_tracking[$plugin] = $plugin;
303 }
304 } else {
305 if (isset($allow_tracking[$plugin])) {
306 unset($allow_tracking[$plugin]);
307 }
308 }
309 update_option('wpins_allow_tracking', $allow_tracking);
310 }
311
312 /**
313 * Check the user has opted out or not.
314 *
315 * @since 3.0.0
316 * @return Boolean
317 */
318 protected function has_user_opted_out()
319 {
320 if (!empty($this->options)) {
321 foreach ($this->options as $option_name) {
322 $options = get_option($option_name);
323 if (!empty($options['wpins_opt_out'])) {
324 return true;
325 }
326 }
327 }
328 return false;
329 }
330 /**
331 * Check if it's time to track
332 *
333 * @since 3.0.0
334 */
335 public function is_time_to_track()
336 {
337 $track_times = get_option('wpins_last_track_time', array());
338 return !isset($track_times[$this->plugin_name]) ? true : ((isset($track_times[$this->plugin_name]) && $track_times[$this->plugin_name]) < strtotime('-1 day') ? true : false);
339 }
340 /**
341 * Set tracking time.
342 *
343 * @since 3.0.0
344 */
345 public function set_track_time()
346 {
347 $track_times = get_option('wpins_last_track_time', array());
348 $track_times[$this->plugin_name] = time();
349 update_option('wpins_last_track_time', $track_times);
350 }
351 /**
352 * This method is responsible for collecting all data.
353 *
354 * @since 3.0.0
355 */
356 public function get_data()
357 {
358 $body = array(
359 'plugin_slug' => sanitize_text_field($this->plugin_name),
360 'url' => get_bloginfo('url'),
361 'site_name' => get_bloginfo('name'),
362 'site_version' => get_bloginfo('version'),
363 'site_language' => get_bloginfo('language'),
364 'charset' => get_bloginfo('charset'),
365 'wpins_version' => self::WPINS_VERSION,
366 'php_version' => phpversion(),
367 'multisite' => is_multisite(),
368 'file_location' => __FILE__
369 );
370
371 // Collect the email if the correct option has been set
372 if ($this->marketing) {
373 if (!function_exists('wp_get_current_user')) {
374 include ABSPATH . 'wp-includes/pluggable.php';
375 }
376 $current_user = wp_get_current_user();
377 $email = $current_user->user_email;
378 if (is_email($email)) {
379 $body['email'] = $email;
380 } else {
381 $email = get_option('admin_email');
382 if (is_email($email)) {
383 $body['email'] = $email;
384 }
385 }
386 }
387 $body['marketing_method'] = $this->marketing;
388 $body['server'] = isset($_SERVER['SERVER_SOFTWARE']) ? $_SERVER['SERVER_SOFTWARE'] : '';
389
390 /**
391 * Collect all active and inactive plugins
392 */
393 if (!function_exists('get_plugins')) {
394 include ABSPATH . '/wp-admin/includes/plugin.php';
395 }
396 $plugins = array_keys(get_plugins());
397 $active_plugins = is_network_admin() ? array_keys(get_site_option('active_sitewide_plugins', array())) : get_option('active_plugins', array());
398 foreach ($plugins as $key => $plugin) {
399 if (in_array($plugin, $active_plugins)) {
400 unset($plugins[$key]);
401 }
402 }
403 $body['active_plugins'] = $active_plugins;
404 $body['inactive_plugins'] = $plugins;
405
406 /**
407 * Text Direction.
408 */
409 $body['text_direction'] = (function_exists('is_rtl') ? (is_rtl() ? 'RTL' : 'LTR') : 'NOT SET');
410 /**
411 * Get Our Plugin Data.
412 * @since 3.0.0
413 */
414 $plugin = $this->plugin_data();
415 if (empty($plugin)) {
416 $body['message'] .= __('We can\'t detect any plugin information. This is most probably because you have not included the code in the plugin main file.', 'better-payment');
417 $body['status'] = 'NOT FOUND';
418 } else {
419 if (isset($plugin['Name'])) {
420 $body['plugin'] = sanitize_text_field($plugin['Name']);
421 }
422 if (isset($plugin['Version'])) {
423 $body['version'] = sanitize_text_field($plugin['Version']);
424 }
425 $body['status'] = 'Active';
426 }
427
428 /**
429 * Get active theme name and version
430 * @since 3.0.0
431 */
432 $theme = wp_get_theme();
433 if ($theme->Name) {
434 $body['theme'] = sanitize_text_field($theme->Name);
435 }
436 if ($theme->Version) {
437 $body['theme_version'] = sanitize_text_field($theme->Version);
438 }
439 return $body;
440 }
441
442 /**
443 * Collect plugin data,
444 * Retrieve current plugin information
445 *
446 * @since 3.0.0
447 */
448 public function plugin_data()
449 {
450 if (!function_exists('get_plugin_data')) {
451 include ABSPATH . '/wp-admin/includes/plugin.php';
452 }
453 $plugin = get_plugin_data($this->plugin_file);
454 return $plugin;
455 }
456 /**
457 * Send the data to insights.
458 * @since 3.0.0
459 */
460 public function send_data($body)
461 {
462 /**
463 * Get SITE ID
464 */
465 $site_id_key = "wpins_{$this->plugin_name}_site_id";
466 $site_id = get_option($site_id_key, false);
467 $failed_data = [];
468 $site_url = get_bloginfo('url');
469 $original_site_url = get_option("wpins_{$this->plugin_name}_original_url", false);
470
471 if (($original_site_url === false || $original_site_url != $site_url) && version_compare($body['wpins_version'], '3.0.1', '>=')) {
472 $site_id = false;
473 }
474 /**
475 * Send Initial Data to API
476 */
477 if ($site_id == false && $this->item_id !== false) {
478 if (isset($_SERVER['REMOTE_ADDR']) && !empty($_SERVER['REMOTE_ADDR'] && $_SERVER['REMOTE_ADDR'] != '127.0.0.1')) {
479 $country_request = wp_remote_get('http://ip-api.com/json/' . $_SERVER['REMOTE_ADDR'] . '?fields=country');
480 if (!is_wp_error($country_request) && $country_request['response']['code'] == 200) {
481 $ip_data = json_decode($country_request["body"]);
482 $body['country'] = isset($ip_data->country) ? $ip_data->country : 'NOT SET';
483 }
484 }
485
486 $body['plugin_slug'] = $this->plugin_name;
487 $body['url'] = $site_url;
488 $body['item_id'] = $this->item_id;
489
490 $request = $this->remote_post($body);
491 if (!is_wp_error($request) && $request['response']['code'] == 200) {
492 $retrieved_body = json_decode(wp_remote_retrieve_body($request), true);
493 if (is_array($retrieved_body) && isset($retrieved_body['siteId'])) {
494 update_option($site_id_key, $retrieved_body['siteId']);
495 update_option("wpins_{$this->plugin_name}_original_url", $site_url);
496 update_option("wpins_{$this->plugin_name}_{$retrieved_body['siteId']}", $body);
497 }
498 } else {
499 $failed_data = $body;
500 }
501 }
502
503 $site_id_data_key = "wpins_{$this->plugin_name}_{$site_id}";
504 $site_id_data_failed_key = "wpins_{$this->plugin_name}_{$site_id}_send_failed";
505
506 if ($site_id != false) {
507 $old_sent_data = get_option($site_id_data_key, []);
508 $diff_data = $this->diff($body, $old_sent_data);
509 $failed_data = get_option($site_id_data_failed_key, []);
510 if (!empty($failed_data) && $diff_data != $failed_data) {
511 $failed_data = array_merge($failed_data, $diff_data);
512 }
513 }
514
515 if (!empty($failed_data) && $site_id != false) {
516 $failed_data['plugin_slug'] = $this->plugin_name;
517 $failed_data['url'] = $site_url;
518 $failed_data['site_id'] = $site_id;
519 if ($original_site_url != false) {
520 $failed_data['original_url'] = $original_site_url;
521 }
522
523 $request = $this->remote_post($failed_data);
524 if (!is_wp_error($request)) {
525 delete_option($site_id_data_failed_key);
526 $replaced_data = array_merge($old_sent_data, $failed_data);
527 update_option($site_id_data_key, $replaced_data);
528 }
529 }
530
531 if (!empty($diff_data) && $site_id != false && empty($failed_data)) {
532 $diff_data['plugin_slug'] = $this->plugin_name;
533 $diff_data['url'] = $site_url;
534 $diff_data['site_id'] = $site_id;
535 if ($original_site_url != false) {
536 $diff_data['original_url'] = $original_site_url;
537 }
538
539 $request = $this->remote_post($diff_data);
540 if (is_wp_error($request)) {
541 update_option($site_id_data_failed_key, $diff_data);
542 } else {
543 $replaced_data = array_merge($old_sent_data, $diff_data);
544 update_option($site_id_data_key, $replaced_data);
545 }
546 }
547
548 $this->set_track_time();
549
550 if (isset($request) && is_wp_error($request)) {
551 return $request;
552 }
553
554 if (isset($request)) {
555 return true;
556 }
557 return false;
558 }
559 /**
560 * WP_REMOTE_POST method responsible for send data to the API_URL
561 *
562 * @param array $data
563 * @param array $args
564 * @return void
565 */
566 protected function remote_post($data = array(), $args = array())
567 {
568 if (empty($data)) {
569 return;
570 }
571
572 $args = wp_parse_args($args, array(
573 'method' => 'POST',
574 'timeout' => 30,
575 'redirection' => 5,
576 'httpversion' => '1.1',
577 'blocking' => true,
578 'body' => $data,
579 'user-agent' => 'PUT/1.0.0; ' . get_bloginfo('url')
580 ));
581 $request = wp_remote_post(esc_url(self::API_URL), $args);
582 if (is_wp_error($request) || (isset($request['response'], $request['response']['code']) && $request['response']['code'] != 200)) {
583 return new \WP_Error(500, 'Something went wrong.');
584 }
585 return $request;
586 }
587 /**
588 * Difference between old and new data
589 *
590 * @param array $new_data
591 * @param array $old_data
592 * @return void
593 */
594 protected function diff($new_data, $old_data)
595 {
596 $data = [];
597 if (!empty($new_data)) {
598 foreach ($new_data as $key => $value) {
599 if (isset($old_data[$key])) {
600 if ($old_data[$key] == $value) {
601 continue;
602 }
603 }
604 $data[$key] = $value;
605 }
606 }
607 return $data;
608 }
609 /**
610 * Display the admin notice to users to allow them to opt in
611 *
612 * @since 3.0.0
613 */
614 public function notice()
615 {
616 /**
617 * Return if notice is not set.
618 */
619 if (!isset($this->notice_options['notice'])) {
620 return;
621 }
622 /**
623 * Check is allowed or blocked for notice.
624 */
625 $block_notice = get_option('wpins_block_notice');
626 if (isset($block_notice[$this->plugin_name])) {
627 return;
628 }
629 if (!current_user_can('manage_options')) {
630 return;
631 }
632
633 $url_yes = add_query_arg([
634 'plugin' => $this->plugin_name,
635 'plugin_action' => 'yes',
636 ]);
637 $url_no = add_query_arg(array(
638 'plugin' => $this->plugin_name,
639 'plugin_action' => 'no'
640 ));
641
642 $url_yes = wp_nonce_url( $url_yes, '_wpnonce_optin_' . $this->plugin_name );
643 $url_no = wp_nonce_url( $url_no, '_wpnonce_optin_' . $this->plugin_name );
644
645 // Decide on notice text
646 $notice_text = $this->notice_options['notice'] . ' <a href="#" class="wpinsights-' . $this->plugin_name . '-collect">' . $this->notice_options['consent_button_text'] . '</a>';
647 $extra_notice_text = $this->notice_options['extra_notice'];
648
649 $output = '';
650 $output .= '<div class="notice notice-info updated put-dismiss-notice">';
651 $output .= '<p>' . $notice_text . '</p>';
652 $output .= '<div class="wpinsights-data" style="display: none;">';
653 $output .= '<p>' . $extra_notice_text . '</p>';
654 $output .= '</div>';
655 $output .= '<p>';
656 $output .= '<a href="' . esc_url($url_yes) . '" class="button-primary">' . $this->notice_options['yes'] . '</a>&nbsp;';
657 $output .= '<a href="' . esc_url($url_no) . '" class="button-secondary">' . $this->notice_options['no'] . '</a>';
658 $output .= '</p>';
659 $output .= "<script type='text/javascript'>jQuery('.wpinsights-" . $this->plugin_name . "-collect').on('click', function(e) {e.preventDefault();jQuery('.wpinsights-data').slideToggle('fast');});</script>";
660 $output .= '</div>';
661
662 printf( '%1$s', $output );
663 }
664 /**
665 * Set all notice options to customized notice.
666 *
667 * @since 3.0.0
668 * @param array $options
669 * @return void
670 */
671 public function set_notice_options($options = [])
672 {
673 $default_options = [
674 'consent_button_text' => 'What we collect.',
675 'yes' => 'Sure, I\'d like to help',
676 'no' => 'No Thanks.',
677 ];
678 $options = wp_parse_args($options, $default_options);
679 $this->notice_options = $options;
680 }
681 /**
682 * Responsible for track the click from Notice.
683 * @return void
684 */
685 public function clicked()
686 {
687 if ( isset( $_GET['_wpnonce'] ) && isset( $_GET['plugin'] ) && trim( $_GET['plugin'] ) === $this->plugin_name && isset( $_GET['plugin_action'] ) ) {
688 if ( ! wp_verify_nonce( $_GET['_wpnonce'], '_wpnonce_optin_' . $this->plugin_name ) ) {
689 return;
690 }
691
692 if( isset( $_GET['tab'] ) && $_GET['tab'] === 'plugin-information' ) {
693 return;
694 }
695 $plugin = sanitize_text_field( $_GET['plugin'] );
696 $action = sanitize_text_field( $_GET['plugin_action'] );
697 if( $action == 'yes' ) {
698 $this->schedule_tracking();
699 $this->set_is_tracking_allowed( true, $plugin );
700 if( $this->do_tracking( true ) ) {
701 $this->update_block_notice( $plugin );
702 }
703 /**
704 * Redirect User To the Current URL, but without set query arguments.
705 */
706 wp_safe_redirect( $this->redirect_to() );
707 } else {
708 $this->set_is_tracking_allowed( false, $plugin );
709 $this->update_block_notice( $plugin );
710 }
711 }
712 }
713 /**
714 * Set if we should block the opt-in notice for this plugin
715 *
716 * @since 3.0.0
717 */
718 public function update_block_notice($plugin = null)
719 {
720 if (empty($plugin)) {
721 $plugin = $this->plugin_name;
722 }
723 $block_notice = get_option('wpins_block_notice');
724 if (empty($block_notice) || !is_array($block_notice)) {
725 $block_notice = array($plugin => $plugin);
726 } else {
727 $block_notice[$plugin] = $plugin;
728 }
729 update_option('wpins_block_notice', $block_notice);
730 }
731 /**
732 * AJAX callback when the deactivated form is submitted.
733 * @since 3.0.0
734 */
735 public function deactivate_reasons_form_submit()
736 {
737 check_ajax_referer('wpins_deactivation_nonce', 'security');
738 if (isset($_POST['values'])) {
739 $values = $_POST['values'];
740 update_option('wpins_deactivation_reason_' . $this->plugin_name, $values);
741 }
742 if (isset($_POST['details'])) {
743 $details = sanitize_text_field($_POST['details']);
744 update_option('wpins_deactivation_details_' . $this->plugin_name, $details);
745 }
746 echo 'success';
747 wp_die();
748 }
749 /**
750 * Filter the deactivation link to allow us to present a form when the user deactivates the plugin
751 * @since 3.0.0
752 */
753 public function deactivate_action_links($links)
754 {
755 /**
756 * Check is tracking allowed or not.
757 */
758 if (!$this->is_tracking_allowed()) {
759 return $links;
760 }
761 if (isset($links['deactivate']) && $this->include_goodbye_form) {
762 $deactivation_link = $links['deactivate'];
763 /**
764 * Change the default deactivate button link.
765 */
766 $deactivation_link = str_replace('<a ', '<div class="wpinsights-goodbye-form-wrapper-' . esc_attr($this->plugin_name) . '"><div class="wpinsights-goodbye-form-bg"></div><span class="wpinsights-goodbye-form" id="wpinsights-goodbye-form"></span></div><a onclick="javascript:event.preventDefault();" id="wpinsights-goodbye-link-' . esc_attr($this->plugin_name) . '" ', $deactivation_link);
767 $links['deactivate'] = $deactivation_link;
768 }
769 return $links;
770 }
771 /**
772 * ALL Deactivate Reasons.
773 * @since 3.0.0
774 */
775 public function deactivation_reasons()
776 {
777 $form = array();
778 $form['heading'] = esc_html__('Sorry to see you go', 'better-payment');
779 $form['body'] = esc_html__('Before you deactivate the plugin, would you quickly give us your reason for doing so?', 'better-payment');
780
781 $form['options'] = array(
782 esc_html__('I no longer need the plugin', 'better-payment'),
783 [
784 'label' => esc_html__('I found a better plugin', 'better-payment'),
785 'extra_field' => esc_html__('Please share which plugin', 'better-payment')
786 ],
787 esc_html__("I couldn't get the plugin to work", 'better-payment'),
788 esc_html__('It\'s a temporary deactivation', 'better-payment'),
789 [
790 'label' => esc_html__('Other', 'better-payment'),
791 'extra_field' => esc_html__('Please share the reason', 'better-payment'),
792 'type' => 'textarea'
793 ]
794 );
795 return apply_filters('wpins_form_text_' . $this->plugin_name, $form);
796 }
797 /**
798 * Deactivate Reasons Form.
799 * This form will appears when user wants to deactivate the plugin to send you deactivated reasons.
800 *
801 * @since 3.0.0
802 */
803 public function deactivate_reasons_form()
804 {
805 $form = $this->deactivation_reasons();
806 $class_plugin_name = esc_attr( $this->plugin_name );
807 $html = '<div class="wpinsights-goodbye-form-head"><strong>' . esc_html($form['heading']) . '</strong></div>';
808 $html .= '<div class="wpinsights-goodbye-form-body"><p class="wpinsights-goodbye-form-caption">' . esc_html($form['body']) . '</p>';
809 if (is_array($form['options'])) {
810 $html .= '<div id="wpinsights-goodbye-options" class="wpinsights-goodbye-options"><ul>';
811 foreach ($form['options'] as $option) {
812 if (is_array($option)) {
813 $id = strtolower(str_replace(" ", "_", esc_attr($option['label'])));
814 $id = $id . '_' . esc_attr( $class_plugin_name );
815 $html .= '<li class="has-goodbye-extra">';
816 $html .= '<input type="radio" name="wpinsights-' . esc_attr( $class_plugin_name ) . '-goodbye-options" id="' . $id . '" value="' . esc_attr($option['label']) . '">';
817 $html .= '<div><label for="' . $id . '">' . esc_attr($option['label']) . '</label>';
818 if (isset($option['extra_field']) && !isset($option['type'])) {
819 $html .= '<input type="text" style="display: none" name="' . $id . '" id="' . str_replace(" ", "", esc_attr($option['extra_field'])) . '" placeholder="' . esc_attr($option['extra_field']) . '">';
820 }
821 if (isset($option['extra_field']) && isset($option['type'])) {
822 $html .= '<' . $option['type'] . ' style="display: none" type="text" name="' . $id . '" id="' . str_replace(" ", "", esc_attr($option['extra_field'])) . '" placeholder="' . esc_attr($option['extra_field']) . '"></' . $option['type'] . '>';
823 }
824 $html .= '</div></li>';
825 } else {
826 $id = strtolower(str_replace(" ", "_", esc_attr($option)));
827 $id = $id . '_' . esc_attr( $class_plugin_name );
828 $html .= '<li><input type="radio" name="wpinsights-' . esc_attr( $class_plugin_name ) . '-goodbye-options" id="' . $id . '" value="' . esc_attr($option) . '"> <label for="' . $id . '">' . esc_attr($option) . '</label></li>';
829 }
830 }
831 $html .= '</ul></div><!-- .wpinsights-' . esc_attr( $class_plugin_name ) . '-goodbye-options -->';
832 }
833 $html .= '</div><!-- .wpinsights-goodbye-form-body -->';
834 $html .= '<p class="deactivating-spinner"><span class="spinner"></span> ' . esc_html__('Submitting form', 'better-payment') . '</p>';
835
836 $wrapper_class = '.wpinsights-goodbye-form-wrapper-' . esc_attr( $class_plugin_name );
837
838 $styles = '';
839 $styles .= '<style type="text/css">';
840 $styles .= '.wpinsights-form-active-' . esc_attr( $class_plugin_name ) . ' .wpinsights-goodbye-form-bg {';
841 $styles .= 'background: rgba( 0, 0, 0, .8 );position: fixed;top: 0;left: 0;width: 100%;height: 100%;z-index: 9;';
842 $styles .= '}';
843 $styles .= $wrapper_class . '{';
844 $styles .= 'position: relative; display: none;';
845 $styles .= '}';
846 $styles .= '.wpinsights-form-active-' . esc_attr( $class_plugin_name ) . ' ' . $wrapper_class . '{';
847 $styles .= 'display: flex !important; position: fixed;top: 0;left: 0;width: 100%;height: 100%; justify-content: center; align-items: center; z-index: 99999';
848 $styles .= '}';
849 $styles .= $wrapper_class . ' .wpinsights-goodbye-form { display: none; }';
850 $styles .= '.wpinsights-form-active-' . esc_attr( $class_plugin_name ) . ' .wpinsights-goodbye-form {';
851 $styles .= 'position: relative !important; width: 550px; max-width: 80%; background: #fff; box-shadow: 2px 8px 23px 3px rgba(0,0,0,.2); border-radius: 3px; white-space: normal; overflow: hidden; display: block; z-index: 999999;';
852 $styles .= '}';
853 $styles .= $wrapper_class . ' .wpinsights-goodbye-form-head {';
854 $styles .= 'background: #fff; color: #495157; padding: 18px; box-shadow: 0 0 8px rgba(0,0,0,.1); font-size: 15px;';
855 $styles .= '}';
856 $styles .= $wrapper_class . ' .wpinsights-goodbye-form .wpinsights-goodbye-form-head strong { font-size: 15px; }';
857 $styles .= $wrapper_class . ' .wpinsights-goodbye-form-body { padding: 8px 18px; color: #333; }';
858 $styles .= $wrapper_class . ' .wpinsights-goodbye-form-body label { padding-left: 5px; color: #6d7882; }';
859 $styles .= $wrapper_class . ' .wpinsights-goodbye-form-body .wpinsights-goodbye-form-caption {';
860 $styles .= 'font-weight: 500; font-size: 15px; color: #495157; line-height: 1.4;';
861 $styles .= '}';
862 $styles .= $wrapper_class . ' .wpinsights-goodbye-form-body #wpinsights-goodbye-options { padding-top: 5px; }';
863 $styles .= $wrapper_class . ' .wpinsights-goodbye-form-body #wpinsights-goodbye-options ul > li { margin-bottom: 15px; }';
864 $styles .= $wrapper_class . ' .wpinsights-goodbye-form-body #wpinsights-goodbye-options input[type=radio] { border-color: #6B59EE; box-shadow: none; outline: 0; }';
865 $styles .= $wrapper_class . ' .wpinsights-goodbye-form-body #wpinsights-goodbye-options input[type=radio]:checked::before { content: ""; border-radius: 50%; width: .6rem; height: .6rem; margin: 2.45px; background-color: #6B59EE; line-height: 1.14285714; outline: 0; }';
866 $styles .= $wrapper_class . ' .wpinsights-goodbye-form-body #wpinsights-goodbye-options ul > li > div { display: inline; padding-left: 3px; }';
867 $styles .= $wrapper_class . ' .wpinsights-goodbye-form-body #wpinsights-goodbye-options ul > li > div > input, ' . $wrapper_class . ' .wpinsights-goodbye-form-body #wpinsights-goodbye-options ul > li > div > textarea {';
868 $styles .= 'margin: 10px 18px; padding: 8px; width: 80%;';
869 $styles .= '}';
870 $styles .= $wrapper_class . ' .deactivating-spinner { display: none; padding-bottom: 20px !important; }';
871 $styles .= $wrapper_class . ' .deactivating-spinner .spinner { float: none; margin: 4px 4px 0 18px; vertical-align: bottom; visibility: visible; }';
872 $styles .= $wrapper_class . ' .wpinsights-goodbye-form-footer { padding: 8px 18px; margin-bottom: 15px; }';
873 $styles .= $wrapper_class . ' .wpinsights-goodbye-form-footer > .wpinsights-goodbye-form-buttons { display: flex; align-items: center; justify-content: space-between; }';
874 $styles .= $wrapper_class . ' .wpinsights-goodbye-form-footer .wpinsights-submit-btn {';
875 $styles .= 'background-color: #6B59EE; -webkit-border-radius: 8px; border-radius: 8px; color: #fff; line-height: 1; padding: 12px 18px; font-size: 13px;';
876 $styles .= '}';
877 $styles .= $wrapper_class . ' .wpinsights-goodbye-form-footer .wpsp-put-deactivate-btn {';
878 $styles .= 'font-size: 13px; color: #a4afb7; background: none; float: right; padding-right: 10px; width: auto; text-decoration: underline;';
879 $styles .= '}';
880 $styles .= $wrapper_class . ' .test {';
881 $styles .= '}';
882 $styles .= '</style>';
883 $styles .= '';
884
885 echo $styles;
886 ?>
887 <script type="text/javascript">
888 jQuery(document).ready(function($) {
889 $("#wpinsights-goodbye-link-<?php echo esc_attr( $class_plugin_name ); ?>").on("click", function() {
890 // We'll send the user to this deactivation link when they've completed or dismissed the form
891 var url = document.getElementById("wpinsights-goodbye-link-<?php echo esc_attr( $class_plugin_name ); ?>");
892 $('body').toggleClass('wpinsights-form-active-<?php echo esc_attr( $class_plugin_name ); ?>');
893 $(".wpinsights-goodbye-form-wrapper-<?php echo esc_attr( $class_plugin_name ); ?> #wpinsights-goodbye-form").fadeIn();
894 $(".wpinsights-goodbye-form-wrapper-<?php echo esc_attr( $class_plugin_name ); ?> #wpinsights-goodbye-form").html('<?php echo $html; ?>' + '<div class="wpinsights-goodbye-form-footer"><div class="wpinsights-goodbye-form-buttons"><a id="wpinsights-submit-form-<?php echo esc_attr( $class_plugin_name ); ?>" class="wpinsights-submit-btn" href="#"><?php esc_html_e('Submit and Deactivate', 'better-payment'); ?></a>&nbsp;<a class="wpsp-put-deactivate-btn" href="' + url + '"><?php esc_html_e('Just Deactivate', 'better-payment'); ?></a></div></div>');
895 $('#wpinsights-submit-form-<?php echo esc_attr( $class_plugin_name ); ?>').on('click', function(e) {
896 // As soon as we click, the body of the form should disappear
897 $("#wpinsights-goodbye-form-<?php echo esc_attr( $class_plugin_name ); ?> .wpinsights-goodbye-form-body").fadeOut();
898 $("#wpinsights-goodbye-form-<?php echo esc_attr( $class_plugin_name ); ?> .wpinsights-goodbye-form-footer").fadeOut();
899 // Fade in spinner
900 $("#wpinsights-goodbye-form-<?php echo esc_attr( $class_plugin_name ); ?> .deactivating-spinner").fadeIn();
901 e.preventDefault();
902 var checkedInput = $("input[name='wpinsights-<?php echo esc_attr( $class_plugin_name ); ?>-goodbye-options']:checked"),
903 checkedInputVal, details;
904 if (checkedInput.length > 0) {
905 checkedInputVal = checkedInput.val();
906 details = $('input[name="' + checkedInput[0].id + '"], textarea[name="' + checkedInput[0].id + '"]').val();
907 }
908
909 if (typeof details === 'undefined') {
910 details = '';
911 }
912 if (typeof checkedInputVal === 'undefined') {
913 checkedInputVal = 'No Reason';
914 }
915
916 var data = {
917 'action': 'deactivation_form_<?php echo esc_attr( $class_plugin_name ); ?>',
918 'values': checkedInputVal,
919 'details': details,
920 'security': "<?php echo esc_attr( wp_create_nonce('wpins_deactivation_nonce') ); ?>",
921 'dataType': "json"
922 }
923
924 $.post(
925 ajaxurl,
926 data,
927 function(response) {
928 // Redirect to original deactivation URL
929 window.location.href = url;
930 }
931 );
932 });
933 $('#wpinsights-goodbye-options > ul ').on('click', 'li label, li > input', function(e) {
934 var parent = $(this).parents('li');
935 parent.siblings().find('label').next('input, textarea').css('display', 'none');
936 parent.find('label').next('input, textarea').css('display', 'block');
937 });
938 // If we click outside the form, the form will close
939 $('.wpinsights-goodbye-form-bg').on('click', function() {
940 $("#wpinsights-goodbye-form").fadeOut();
941 $('body').removeClass('wpinsights-form-active-<?php echo esc_attr( $class_plugin_name ); ?>');
942 });
943 });
944 });
945 </script>
946 <?php }
947 }
948