PluginProbe
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot / 2.5.2
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot v2.5.2
4.9.1 4.9.0 4.8.2 4.8.1 4.8.0 4.7.0 4.6.2 4.6.1 4.6.0 4.5.6 4.5.5 4.5.4 4.5.3 4.5.2 4.5.1 4.5.0 4.4.1 4.4.0 3.3.4 3.4.0 3.4.1 3.4.2 3.5.0 3.5.1 3.5.2 All 199 releases
betterdocs / includes / Utils / Insights.php

Insights.php in BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot 2.5.2, at includes/Utils/Insights.php

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