PluginProbe
Better Payment – Instant Payments, Donations, Fundraising with Subscriptions & More / 1.0.0
Better Payment – Instant Payments, Donations, Fundraising with Subscriptions & More v1.0.0
2.4.1 2.4.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 All 68 releases
better-payment / includes / Classes / Better_Payment_Plugin_Usage_Tracker.php

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

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