PluginProbe
Better Payment – Instant Payments, Donations, Fundraising with Subscriptions & More / 0.0.2
Better Payment – Instant Payments, Donations, Fundraising with Subscriptions & More v0.0.2
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 / class-better-payment-plugin-usage-tracker.php

class-better-payment-plugin-usage-tracker.php in Better Payment – Instant Payments, Donations, Fundraising with Subscriptions & More 0.0.2, at includes/class-better-payment-plugin-usage-tracker.php

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