PluginProbe
weForms – Easy Drag & Drop Contact Form Builder For WordPress / 1.3.2
weForms – Easy Drag & Drop Contact Form Builder For WordPress v1.3.2
1.6.7 1.6.8 1.6.9 1.6.12 1.6.13 1.6.14 1.6.15 1.6.16 1.6.17 1.6.18 1.6.19 1.6.2 1.6.20 1.6.21 1.6.22 1.6.23 1.6.24 1.6.25 1.6.26 1.6.27 1.6.28 1.6.3 1.6.4 1.6.5 1.6.6 All 74 releases
weforms / includes / admin / class-wedevs-insights.php

class-wedevs-insights.php in weForms – Easy Drag & Drop Contact Form Builder For WordPress 1.3.2, at includes/admin/class-wedevs-insights.php

755 lines 23.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 if ( ! class_exists( 'WeDevs_Insights' ) ) :
4
5 /**
6 * weDevs Tracker
7 *
8 * This is a tracker class to track plugin usage based on if the customer has opted in.
9 * No personal information is being tracked by this class, only general settings, active plugins, environment details
10 * and admin email.
11 *
12 * @version 1.0
13 *
14 * @author Tareq Hasan <tareq@wedevs.com>
15 */
16 class WeDevs_Insights {
17
18 /**
19 * Slug of the plugin
20 *
21 * @var string
22 */
23 public $slug;
24
25 /**
26 * Name of the plugin
27 *
28 * @var string
29 */
30 public $name;
31
32 /**
33 * Main plugin file
34 *
35 * @var string
36 */
37 public $basename;
38
39 /**
40 * The notice text
41 *
42 * @var string
43 */
44 public $notice;
45
46 /**
47 * URL to the API endpoint
48 *
49 * @var string
50 */
51 private static $api_url = 'http://tracking.wedevs.com/';
52
53 /**
54 * Initialize the class
55 *
56 * @param string $slug slug of the plugin
57 * @param string $name readable name of the plugin
58 * @param string $file main plugin file path
59 * @param string $notice the notice texts if needs customizing
60 */
61 public function __construct( $slug, $name, $file, $notice = '' ) {
62 $this->slug = $slug;
63 $this->name = $name;
64 $this->basename = plugin_basename( $file );
65 $this->notice = $notice;
66
67 // tracking notice
68 add_action( 'admin_notices', array( $this, 'admin_notice' ) );
69 add_action( 'admin_init', array( $this, 'handle_optin_optout' ) );
70
71 // plugin deactivate actions
72 add_action( 'plugin_action_links_' . $this->basename, array( $this, 'plugin_action_links' ) );
73 add_action( 'admin_footer', array( $this, 'deactivate_scripts' ) );
74
75 // clean events and options on deactivation
76 register_deactivation_hook( $file, array( $this, 'deactivate_plugin' ) );
77
78 // uninstall reason
79 add_action( 'wp_ajax_' . $this->slug . '_submit-uninstall-reason', array( $this, 'uninstall_reason_submission' ) );
80
81 // cron events
82 add_action( 'cron_schedules', array( $this, 'add_weekly_schedule' ) );
83 add_action( $this->slug . '_tracker_send_event', array( $this, 'send_tracking_data' ) );
84 // add_action( 'admin_init', array( $this, 'send_tracking_data' ) ); // test
85 }
86
87 /**
88 * Send tracking data to weDevs server
89 *
90 * @param boolean $override
91 *
92 * @return void
93 */
94 public function send_tracking_data( $override = false ) {
95 // skip on AJAX Requests
96 if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
97 return;
98 }
99
100 if ( ! $this->tracking_allowed() && ! $override ) {
101 return;
102 }
103
104 // Send a maximum of once per week
105 $last_send = $this->get_last_send();
106 if ( $last_send && $last_send > strtotime( '-1 week' ) ) {
107 return;
108 }
109
110 $this->send_request( $this->get_tracking_data(), 'track' );
111
112 update_option( $this->slug . '_tracking_last_send', time() );
113 }
114
115 /**
116 * Send request to remote endpoint
117 *
118 * @param array $params
119 * @param string $route
120 *
121 * @return void
122 */
123 private function send_request( $params, $route ) {
124 $resp = wp_remote_post( self::$api_url . $route, array(
125 'method' => 'POST',
126 'timeout' => 45,
127 'redirection' => 5,
128 'httpversion' => '1.0',
129 'blocking' => false,
130 'headers' => array( 'user-agent' => 'WeDevsTracker/' . md5( esc_url( home_url() ) ) . ';' ),
131 'body' => $params,
132 'cookies' => array()
133 )
134 );
135 }
136
137 /**
138 * Get the tracking data points
139 *
140 * @return array
141 */
142 protected function get_tracking_data() {
143 $all_plugins = $this->get_all_plugins();
144 $admin_user = get_user_by( 'id', 1 );
145
146 $data = array(
147 'url' => home_url(),
148 'site' => get_bloginfo( 'name' ),
149 'admin_email' => get_option( 'admin_email' ),
150 'user_name' => $admin_user->display_name,
151 'user_email' => $admin_user->user_email,
152 'plugin' => $this->slug,
153 'server' => $this->get_server_info(),
154 'wp' => $this->get_wp_info(),
155 'users' => $this->get_user_counts(),
156 'active_plugins' => count( $all_plugins['active_plugins'] ),
157 'inactive_plugins' => count( $all_plugins['inactive_plugins'] ),
158 );
159
160 // for child classes
161 if ( $extra = $this->get_extra_data() ) {
162 $data['extra'] = $extra;
163 }
164
165 return apply_filters( $this->slug . '_tracker_data', $data );
166 }
167
168 /**
169 * If a child class wants to send extra data
170 *
171 * @return mixed
172 */
173 protected function get_extra_data() {
174 return false;
175 }
176
177 /**
178 * Explain the user which data we collect
179 *
180 * @return string
181 */
182 protected function data_we_collect() {
183 $data = array(
184 'Server environment details (php, mysql, server, WordPress versions)',
185 'Number of users in your site',
186 'Site language',
187 'Number of active and inactive plugins',
188 'Site name and url',
189 'Your name and email address',
190 );
191
192 return $data;
193 }
194
195 /**
196 * Check if the user has opted into tracking
197 *
198 * @return bool
199 */
200 private function tracking_allowed() {
201 $allow_tracking = get_option( $this->slug . '_allow_tracking', 'no' );
202
203 return $allow_tracking == 'yes';
204 }
205
206 /**
207 * Get the last time a tracking was sent
208 *
209 * @return false|string
210 */
211 private function get_last_send() {
212 return get_option( $this->slug . '_tracking_last_send', false );
213 }
214
215 /**
216 * Check if the notice has been dismissed or enabled
217 *
218 * @return boolean
219 */
220 private function notice_dismissed() {
221 $hide_notice = get_option( $this->slug . '_tracking_notice', 'no' );
222
223 if ( 'hide' == $hide_notice ) {
224 return true;
225 }
226
227 return false;
228 }
229
230 /**
231 * Check if the current server is localhost
232 *
233 * @return boolean
234 */
235 private function is_local_server() {
236 return in_array( $_SERVER['REMOTE_ADDR'], array( '127.0.0.1', '::1' ) );
237 }
238
239 /**
240 * Schedule the event weekly
241 *
242 * @return void
243 */
244 private function schedule_event() {
245 wp_schedule_event( time(), 'weekly', $this->slug . '_tracker_send_event' );
246 }
247
248 /**
249 * Clear any scheduled hook
250 *
251 * @return void
252 */
253 private function clear_schedule_event() {
254 wp_clear_scheduled_hook( $this->slug . '_tracker_send_event' );
255 }
256
257 /**
258 * Display the admin notice to users that have not opted-in or out
259 *
260 * @return void
261 */
262 public function admin_notice() {
263
264 if ( $this->notice_dismissed() ) {
265 return;
266 }
267
268 if ( $this->tracking_allowed() ) {
269 return;
270 }
271
272 if ( ! current_user_can( 'manage_options' ) ) {
273 return;
274 }
275
276 if ( get_transient( $this->slug . '_prevent_tracker_notice' ) ) {
277 return;
278 }
279
280 // don't show tracking if a local server
281 if ( ! $this->is_local_server() ) {
282 $optin_url = add_query_arg( $this->slug . '_tracker_optin', 'true' );
283 $optout_url = add_query_arg( $this->slug . '_tracker_optout', 'true' );
284
285 if ( empty( $this->notice ) ) {
286 $notice = sprintf( __( 'Want to help make <strong>%s</strong> even more awesome? Allow weDevs to collect non-sensitive diagnostic data and usage information.', 'weforms' ), $this->name );
287 } else {
288 $notice = $this->notice;
289 }
290
291 $notice .= ' (<a class="insights-data-we-collect" href="#">' . __( 'what we collect', 'weforms' ) . '</a>)';
292 $notice .= '<p class="description" style="display:none;">' . implode( ', ', $this->data_we_collect() ) . '. No sensitive data is tracked.</p>';
293
294 echo '<div class="updated"><p>';
295 echo $notice;
296 echo '</p><p class="submit">';
297 echo '&nbsp;<a href="' . esc_url( $optin_url ) . '" class="button-primary button-large">' . __( 'Allow', 'weforms' ) . '</a>';
298 echo '&nbsp;<a href="' . esc_url( $optout_url ) . '" class="button-secondary button-large">' . __( 'No thanks', 'weforms' ) . '</a>';
299 echo '</p></div>';
300
301 echo "<script type='text/javascript'>jQuery('.insights-data-we-collect').on('click', function(e) {
302 e.preventDefault();
303 jQuery(this).parents('.updated').find('p.description').slideToggle('fast');
304 });
305 </script>
306 ";
307 }
308 }
309
310 /**
311 * handle the optin/optout
312 *
313 * @return void
314 */
315 public function handle_optin_optout() {
316 if ( isset( $_GET[ $this->slug . '_tracker_optin' ] ) && $_GET[ $this->slug . '_tracker_optin' ] == 'true' ) {
317 update_option( $this->slug . '_allow_tracking', 'yes' );
318 update_option( $this->slug . '_tracking_notice', 'hide' );
319
320 $this->clear_schedule_event();
321 $this->schedule_event();
322 $this->send_tracking_data();
323
324 wp_redirect( remove_query_arg( $this->slug . '_tracker_optin' ) );
325 exit;
326 }
327
328 if ( isset( $_GET[ $this->slug . '_tracker_optout' ] ) && $_GET[ $this->slug . '_tracker_optout' ] == 'true' ) {
329 update_option( $this->slug . '_allow_tracking', 'no' );
330 update_option( $this->slug . '_tracking_notice', 'hide' );
331
332 $this->clear_schedule_event();
333
334 wp_redirect( remove_query_arg( $this->slug . '_tracker_optout' ) );
335 exit;
336 }
337 }
338
339 /**
340 * Get the number of post counts
341 *
342 * @param string $post_type
343 *
344 * @return integer
345 */
346 protected function get_post_count( $post_type ) {
347 global $wpdb;
348
349 return (int) $wpdb->get_var( "SELECT count(ID) FROM $wpdb->posts WHERE post_type = '$post_type' and post_status = 'publish'");
350 }
351
352 /**
353 * Get server related info.
354 *
355 * @return array
356 */
357 private static function get_server_info() {
358 global $wpdb;
359
360 $server_data = array();
361
362 if ( isset( $_SERVER['SERVER_SOFTWARE'] ) && ! empty( $_SERVER['SERVER_SOFTWARE'] ) ) {
363 $server_data['software'] = $_SERVER['SERVER_SOFTWARE'];
364 }
365
366 if ( function_exists( 'phpversion' ) ) {
367 $server_data['php_version'] = phpversion();
368 }
369
370 $server_data['mysql_version'] = $wpdb->db_version();
371
372 $server_data['php_max_upload_size'] = size_format( wp_max_upload_size() );
373 $server_data['php_default_timezone'] = date_default_timezone_get();
374 $server_data['php_soap'] = class_exists( 'SoapClient' ) ? 'Yes' : 'No';
375 $server_data['php_fsockopen'] = function_exists( 'fsockopen' ) ? 'Yes' : 'No';
376 $server_data['php_curl'] = function_exists( 'curl_init' ) ? 'Yes' : 'No';
377
378 return $server_data;
379 }
380
381 /**
382 * Get WordPress related data.
383 *
384 * @return array
385 */
386 private function get_wp_info() {
387 $wp_data = array();
388
389 $wp_data['memory_limit'] = WP_MEMORY_LIMIT;
390 $wp_data['debug_mode'] = ( defined('WP_DEBUG') && WP_DEBUG ) ? 'Yes' : 'No';
391 $wp_data['locale'] = get_locale();
392 $wp_data['version'] = get_bloginfo( 'version' );
393 $wp_data['multisite'] = is_multisite() ? 'Yes' : 'No';
394
395 return $wp_data;
396 }
397
398 /**
399 * Get the list of active and inactive plugins
400 *
401 * @return array
402 */
403 private function get_all_plugins() {
404 // Ensure get_plugins function is loaded
405 if ( ! function_exists( 'get_plugins' ) ) {
406 include ABSPATH . '/wp-admin/includes/plugin.php';
407 }
408
409 $plugins = get_plugins();
410 $active_plugins_keys = get_option( 'active_plugins', array() );
411 $active_plugins = array();
412
413 foreach ( $plugins as $k => $v ) {
414 // Take care of formatting the data how we want it.
415 $formatted = array();
416 $formatted['name'] = strip_tags( $v['Name'] );
417
418 if ( isset( $v['Version'] ) ) {
419 $formatted['version'] = strip_tags( $v['Version'] );
420 }
421
422 if ( isset( $v['Author'] ) ) {
423 $formatted['author'] = strip_tags( $v['Author'] );
424 }
425
426 if ( isset( $v['Network'] ) ) {
427 $formatted['network'] = strip_tags( $v['Network'] );
428 }
429
430 if ( isset( $v['PluginURI'] ) ) {
431 $formatted['plugin_uri'] = strip_tags( $v['PluginURI'] );
432 }
433
434 if ( in_array( $k, $active_plugins_keys ) ) {
435 // Remove active plugins from list so we can show active and inactive separately
436 unset( $plugins[$k] );
437 $active_plugins[$k] = $formatted;
438 } else {
439 $plugins[$k] = $formatted;
440 }
441 }
442
443 return array( 'active_plugins' => $active_plugins, 'inactive_plugins' => $plugins );
444 }
445
446 /**
447 * Get user totals based on user role.
448 *
449 * @return array
450 */
451 private function get_user_counts() {
452 $user_count = array();
453 $user_count_data = count_users();
454 $user_count['total'] = $user_count_data['total_users'];
455
456 // Get user count based on user role
457 foreach ( $user_count_data['avail_roles'] as $role => $count ) {
458 $user_count[ $role ] = $count;
459 }
460
461 return $user_count;
462 }
463
464 /**
465 * Add weekly cron schedule
466 *
467 * @param array $schedules
468 *
469 * @return array
470 */
471 public function add_weekly_schedule( $schedules ) {
472
473 $schedules['weekly'] = array(
474 'interval' => DAY_IN_SECONDS * 7,
475 'display' => __( 'Once Weekly', 'weforms' )
476 );
477
478 return $schedules;
479 }
480
481 /**
482 * Clear our options upon deactivation
483 *
484 * @return void
485 */
486 public function deactivate_plugin() {
487 $this->clear_schedule_event();
488
489 delete_option( $this->slug . '_allow_tracking' );
490 delete_option( $this->slug . '_tracking_notice' );
491 delete_option( $this->slug . '_tracking_last_send' );
492 }
493
494 /**
495 * Hook into action links and modify the deactivate link
496 *
497 * @param array $links
498 *
499 * @return array
500 */
501 public function plugin_action_links( $links ) {
502
503 if ( array_key_exists( 'deactivate', $links ) ) {
504 $links['deactivate'] = str_replace( '<a', '<a class="' . $this->slug . '-deactivate-link"', $links['deactivate'] );
505 }
506
507 return $links;
508 }
509
510 private function get_uninstall_reasons() {
511 $reasons = array(
512 array(
513 'id' => 'could-not-understand',
514 'text' => 'I couldn\'t understand how to make it work',
515 'type' => 'textarea',
516 'placeholder' => 'Would you like us to assist you?'
517 ),
518 array(
519 'id' => 'found-better-plugin',
520 'text' => 'I found a better plugin',
521 'type' => 'text',
522 'placeholder' => 'Which plugin?'
523 ),
524 array(
525 'id' => 'not-have-that-feature',
526 'text' => 'The plugin is great, but I need specific feature that you don\'t support',
527 'type' => 'textarea',
528 'placeholder' => 'Could you tell us more about that feature?'
529 ),
530 array(
531 'id' => 'is-not-working',
532 'text' => 'The plugin is not working',
533 'type' => 'textarea',
534 'placeholder' => 'Could you tell us a bit more whats not working?'
535 ),
536 array(
537 'id' => 'looking-for-other',
538 'text' => 'It\'s not what I was looking for',
539 'type' => '',
540 'placeholder' => ''
541 ),
542 array(
543 'id' => 'did-not-work-as-expected',
544 'text' => 'The plugin didn\'t work as expected',
545 'type' => 'textarea',
546 'placeholder' => 'What did you expect?'
547 ),
548 array(
549 'id' => 'other',
550 'text' => 'Other',
551 'type' => 'textarea',
552 'placeholder' => 'Could you tell us a bit more?'
553 ),
554 );
555
556 return $reasons;
557 }
558
559 /**
560 * Plugin deactivation uninstall reason submission
561 *
562 * @return void
563 */
564 public function uninstall_reason_submission() {
565 global $wpdb;
566
567 if ( ! isset( $_POST['reason_id'] ) ) {
568 wp_send_json_error();
569 }
570
571 $current_user = wp_get_current_user();
572
573 $data = array(
574 'reason_id' => sanitize_text_field( $_POST['reason_id'] ),
575 'plugin' => $this->slug,
576 'url' => home_url(),
577 'user_email' => $current_user->user_email,
578 'user_name' => $current_user->display_name,
579 'reason_info' => isset( $_REQUEST['reason_info'] ) ? trim( stripslashes( $_REQUEST['reason_info'] ) ) : '',
580 'software' => $_SERVER['SERVER_SOFTWARE'],
581 'php_version' => phpversion(),
582 'mysql_version' => $wpdb->db_version(),
583 'wp_version' => get_bloginfo( 'version' ),
584 'locale' => get_locale(),
585 'multisite' => is_multisite() ? 'Yes' : 'No'
586 );
587
588 $this->send_request( $data, 'uninstall_reason' );
589
590 wp_send_json_success();
591 }
592
593 /**
594 * Handle the plugin deactivation feedback
595 *
596 * @return void
597 */
598 public function deactivate_scripts() {
599 global $pagenow;
600
601 if ( 'plugins.php' != $pagenow ) {
602 return;
603 }
604
605 $reasons = $this->get_uninstall_reasons();
606 ?>
607
608 <div class="wd-dr-modal" id="<?php echo $this->slug; ?>-wd-dr-modal">
609 <div class="wd-dr-modal-wrap">
610 <div class="wd-dr-modal-header">
611 <h3><?php _e( 'If you have a moment, please let us know why you are deactivating:', 'weforms' ); ?></h3>
612 </div>
613
614 <div class="wd-dr-modal-body">
615 <ul class="reasons">
616 <?php foreach ($reasons as $reason) { ?>
617 <li data-type="<?php echo esc_attr( $reason['type'] ); ?>" data-placeholder="<?php echo esc_attr( $reason['placeholder'] ); ?>">
618 <label><input type="radio" name="selected-reason" value="<?php echo $reason['id']; ?>"> <?php echo $reason['text']; ?></label>
619 </li>
620 <?php } ?>
621 </ul>
622 </div>
623
624 <div class="wd-dr-modal-footer">
625 <a href="#" class="dont-bother-me"><?php _e( 'I rather wouldn\'t say', 'weforms' ); ?></a>
626 <button class="button-secondary"><?php _e( 'Submit & Deactivate', 'weforms' ); ?></button>
627 <button class="button-primary"><?php _e( 'Cancel', 'weforms' ); ?></button>
628 </div>
629 </div>
630 </div>
631
632 <style type="text/css">
633 .wd-dr-modal {
634 position: fixed;
635 z-index: 99999;
636 top: 0;
637 right: 0;
638 bottom: 0;
639 left: 0;
640 background: rgba(0,0,0,0.5);
641 display: none;
642 }
643
644 .wd-dr-modal.modal-active {
645 display: block;
646 }
647
648 .wd-dr-modal-wrap {
649 width: 475px;
650 position: relative;
651 margin: 10% auto;
652 background: #fff;
653 }
654
655 .wd-dr-modal-header {
656 border-bottom: 1px solid #eee;
657 padding: 8px 20px;
658 }
659
660 .wd-dr-modal-header h3 {
661 line-height: 150%;
662 margin: 0;
663 }
664
665 .wd-dr-modal-body {
666 padding: 5px 20px 20px 20px;
667 }
668
669 .wd-dr-modal-body .reason-input {
670 margin-top: 5px;
671 margin-left: 20px;
672 }
673 .wd-dr-modal-footer {
674 border-top: 1px solid #eee;
675 padding: 12px 20px;
676 text-align: right;
677 }
678 </style>
679
680 <script type="text/javascript">
681 (function($) {
682 $(function() {
683 var modal = $( '#<?php echo $this->slug; ?>-wd-dr-modal' );
684 var deactivateLink = '';
685
686 $( '#the-list' ).on('click', 'a.<?php echo $this->slug; ?>-deactivate-link', function(e) {
687 e.preventDefault();
688
689 modal.addClass('modal-active');
690 deactivateLink = $(this).attr('href');
691 modal.find('a.dont-bother-me').attr('href', deactivateLink).css('float', 'left');
692 });
693
694 modal.on('click', 'button.button-primary', function(e) {
695 e.preventDefault();
696
697 modal.removeClass('modal-active');
698 });
699
700 modal.on('click', 'input[type="radio"]', function () {
701 var parent = $(this).parents('li:first');
702
703 modal.find('.reason-input').remove();
704
705 var inputType = parent.data('type'),
706 inputPlaceholder = parent.data('placeholder'),
707 reasonInputHtml = '<div class="reason-input">' + ( ( 'text' === inputType ) ? '<input type="text" size="40" />' : '<textarea rows="5" cols="45"></textarea>' ) + '</div>';
708
709 if ( inputType !== '' ) {
710 parent.append( $(reasonInputHtml) );
711 parent.find('input, textarea').attr('placeholder', inputPlaceholder).focus();
712 }
713 });
714
715 modal.on('click', 'button.button-secondary', function(e) {
716 e.preventDefault();
717
718 var button = $(this);
719
720 if ( button.hasClass('disabled') ) {
721 return;
722 }
723
724 var $radio = $( 'input[type="radio"]:checked', modal );
725
726 var $selected_reason = $radio.parents('li:first'),
727 $input = $selected_reason.find('textarea, input[type="text"]');
728
729 $.ajax({
730 url: ajaxurl,
731 type: 'POST',
732 data: {
733 action: '<?php echo $this->slug; ?>_submit-uninstall-reason',
734 reason_id: ( 0 === $radio.length ) ? 'none' : $radio.val(),
735 reason_info: ( 0 !== $input.length ) ? $input.val().trim() : ''
736 },
737 beforeSend: function() {
738 button.addClass('disabled');
739 button.text('Processing...');
740 },
741 complete: function() {
742 window.location.href = deactivateLink;
743 }
744 });
745 });
746 });
747 }(jQuery));
748 </script>
749
750 <?php
751 }
752 }
753
754 endif;
755