PluginProbe
Discount Rules for WooCommerce – Disco | Dynamic Pricing, Conditions, Bulk, Bundle, BOGO / 1.4.14
Discount Rules for WooCommerce – Disco | Dynamic Pricing, Conditions, Bulk, Bundle, BOGO v1.4.14
1.4.14 1.4.13 1.4.12 1.4.11 1.4.10 1.4.9 1.4.8 1.4.7 1.4.6 1.4.5 1.4.4 1.4.3 1.4.2 1.4.1 1.4.0 1.3.54 1.3.53 1.3.52 1.3.51 1.3.50 1.3.49 1.3.48 1.3.47 1.3.46 1.3.45 All 177 releases
disco / libs / WebAppick / AppServices / Insights.php

Insights.php in Discount Rules for WooCommerce – Disco | Dynamic Pricing, Conditions, Bulk, Bundle, BOGO 1.4.14, at libs/WebAppick/AppServices/Insights.php

1,418 lines 55.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * WebAppick Insights
4 *
5 * @version 1.0.1
6 * @package Disco
7 * @subpackage AppServices
8 *
9 * This is a tracker class to track plugin usage based on if the customer has opted in.
10 * No personal information is being tracked by this class, only general settings, active plugins, environment details
11 * and admin email.
12 */
13
14 namespace Disco\Libs\WebAppick\AppServices;
15
16 use Exception;
17 use WP_Theme;
18 use WP_User;
19
20 if ( ! defined( 'ABSPATH' ) ) {
21 die();
22 }
23
24 /**
25 * Class Insights
26 */
27 class Insights {
28
29 /**
30 * The notice text
31 *
32 * @var string
33 */
34 protected $notice;
35
36 /**
37 * Whether to the notice or not
38 *
39 * @var boolean
40 */
41 protected $show_notice = true;
42
43 /**
44 * If extra data needs to be sent
45 *
46 * @var array
47 */
48 protected $extra_data = array();
49
50 /**
51 * CTXFeed\AppServices\Client
52 *
53 * @var Client
54 */
55 protected $client;
56
57 /**
58 * Flag for checking if the init method is already called.
59 * @var bool
60 */
61 private $didInit = false;
62
63 /**
64 * Email Message Template For sending Support Ticket
65 * @var string
66 */
67 protected $ticketTemplate = '';
68
69 /**
70 * Ticket Email Recipient
71 * @var string
72 */
73 protected $ticketRecipient = '';
74
75 /**
76 * Response to show after support ticket submitted.
77 * @var string
78 */
79 protected $supportResponse = '';
80
81 /**
82 * Error Response for the support ticket
83 * @var string
84 */
85 protected $supportErrorResponse = '';
86
87 /**
88 * Support Page URL
89 * @var string
90 */
91 protected $supportURL = '';
92
93 /**
94 * Initialize the class
95 *
96 * @param Client $client The client.
97 * @param string $name readable name of the Plugin/Theme.
98 * @param string $file main Plugin/Theme file path.
99 */
100 public function __construct( $client, $name = null, $file = null ) {
101 if ( is_string( $client ) && ! empty( $name ) && ! empty( $file ) ) {
102 $client = new Client( $client, $name, $file );
103 }
104
105 if ( is_object( $client ) && is_a( $client, 'Disco\Libs\WebAppick\AppServices\Client' ) ) {
106 $this->client = $client;
107 }
108 }
109
110 /**
111 * Don't show the notice
112 *
113 * @return Insights
114 */
115 public function hide_notice() {
116 $this->show_notice = false;
117 return $this;
118 }
119
120 /**
121 * Add extra data if needed
122 *
123 * @param array $data Extra data.
124 *
125 * @return Insights
126 */
127 public function add_extra( $data = array() ) {
128 $this->extra_data = $data;
129
130 return $this;
131 }
132
133 /**
134 * Set custom notice text
135 *
136 * @param string $text Admin Notice Test.
137 *
138 * @return Insights
139 */
140 public function notice( $text ) {
141 $this->notice = $text;
142
143 return $this;
144 }
145
146 /**
147 * Initialize insights
148 *
149 * @return void
150 */
151 public function init() {
152 // Env Setup.
153 $projectSlug = $this->client->getSlug();
154 /**
155 * Support Page URL
156 * @param string $supportURL
157 */
158 $supportURL = apply_filters( "WebAppick_{$projectSlug}_Support_Page_URL" , false );
159 if ( FALSE !== $supportURL ) {
160 $supportURL = esc_url_raw( $supportURL, [ 'http', 'https' ] );
161 if ( ! empty( $supportURL ) ) {
162 $this->supportURL = $supportURL;
163 }
164 }
165 /**
166 * Set Ticket Recipient Email
167 * @param string $ticketRecipient
168 */
169 $ticketRecipient = apply_filters( "WebAppick_{$projectSlug}_Support_Ticket_Recipient_Email" , false );
170 if ( FALSE !== $ticketRecipient && is_email( $ticketRecipient ) ) {
171 $this->ticketRecipient = sanitize_email( $ticketRecipient );
172 }
173 /**
174 * Set Support Ticket Template For sending the email query.
175 * @param string $ticketTemplate
176 */
177 $ticketTemplate = apply_filters( "WebAppick_{$projectSlug}_Support_Ticket_Email_Template", false );
178 if ( FALSE !== $ticketTemplate ) {
179 $this->ticketTemplate = $ticketTemplate;
180 }
181
182 // initialize.
183 if ( $this->client->getType() == 'plugin' ) {
184 $this->init_plugin();
185 } elseif ( $this->client->getType() == 'theme' ) {
186 $this->init_theme();
187 }
188 $this->didInit = true;
189 }
190
191 /**
192 * Initialize theme hooks
193 *
194 * @return void
195 */
196 private function init_theme() {
197 $this->init_common();
198
199 add_action( 'switch_theme', [ $this, 'deactivation_cleanup' ] );
200 add_action( 'switch_theme', [ $this, 'theme_deactivated' ], 12, 3 );
201 }
202
203 /**
204 * Initialize plugin hooks
205 *
206 * @return void
207 */
208 private function init_plugin() {
209 // plugin deactivate popup.
210 if ( ! $this->__is_local_server() ) {
211 add_action( 'plugin_action_links_' . $this->client->getBasename(), [ $this, 'plugin_action_links' ] );
212 add_action( 'admin_footer', [ $this, 'deactivate_scripts' ] );
213 }
214
215 $this->init_common();
216
217 register_activation_hook( $this->client->getFile(), [ $this, 'activate_plugin' ] );
218 register_deactivation_hook( $this->client->getFile(), [ $this, 'deactivation_cleanup' ] );
219 }
220
221 /**
222 * Initialize common hooks
223 *
224 * @return void
225 */
226 protected function init_common() {
227 if ( $this->show_notice ) {
228 // tracking notice.
229 add_action( 'admin_notices', [ $this, 'admin_notice' ] );
230 }
231 add_action( 'admin_init', [ $this, 'handle_optIn_optOut' ] );
232 add_action( 'removable_query_args', [ $this, 'add_removable_query_args' ], 10, 1 );
233 // uninstall reason.
234 add_action( 'wp_ajax_' . $this->client->getSlug() . '_submit-uninstall-reason', [ $this, 'uninstall_reason_submission' ] );
235 add_action( 'wp_ajax_' . $this->client->getSlug() . '_submit-support-ticket', [ $this, 'support_ticket_submission' ] );
236 // cron events.
237 add_filter( 'cron_schedules', [ $this, 'add_weekly_schedule' ] );
238 add_action( $this->client->getSlug() . '_tracker_send_event', [ $this, 'send_tracking_data' ] );
239 }
240
241 /**
242 * Send tracking data to WebAppick server
243 *
244 * @param boolean $override override current settings.
245 *
246 * @return void
247 */
248 public function send_tracking_data( $override = false ) {
249 // skip on AJAX Requests.
250 if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
251 return;
252 }
253 if ( ! $this->is_tracking_allowed() && ! $override ) {
254 return;
255 }
256 // Send a maximum of once per week.
257 $last_send = $this->__get_last_send();
258 /**
259 * Tracking interval
260 *
261 * @param string $interval A valid date/time string
262 *
263 * @see strtotime()
264 * @link https://www.php.net/manual/en/function.strtotime.php
265 */
266 $trackingInterval = apply_filters( $this->client->getSlug() . '_tracking_interval', '-1 week' );
267 try {
268 $intervalCheck = strtotime( $trackingInterval );
269 } catch ( Exception $e ) {
270 // fallback to default 1 week if filter returned unusable data.
271 $intervalCheck = strtotime( '-1 week' );
272 }
273 if ( $last_send && $last_send > $intervalCheck && ! $override ) {
274 return;
275 }
276 $this->client->send_request( $this->get_tracking_data(), 'track' );
277 update_option( $this->client->getSlug() . '_tracking_last_send', time(), false );
278 }
279
280 /**
281 * Get the tracking data points
282 *
283 * @return array
284 */
285 protected function get_tracking_data() {
286 $all_plugins = $this->__get_all_plugins();
287 $admin_user = $this->__get_admin();
288 $store_country = get_option('woocommerce_default_country');
289 $admin_emails = [ get_option( 'admin_email' ), $admin_user->user_email ];
290 $admin_emails = array_filter( $admin_emails );
291 $admin_emails = array_unique( $admin_emails );
292 $data = [
293 'version' => $this->client->getProjectVersion(),
294 'url' => esc_url( home_url() ),
295 'site' => $this->__get_site_name(),
296 'admin_email' => implode( ',', $admin_emails ),
297 'first_name' => $admin_user->first_name ? $admin_user->first_name : $admin_user->display_name,
298 'last_name' => $admin_user->last_name,
299 'plugin' => $this->client->getName(),
300 'hash' => $this->client->getHash(),
301 'server' => $this->__get_server_info(),
302 'wp' => $this->__get_wp_info(),
303 'active_plugins' => $all_plugins['active_plugins'],
304 'inactive_plugins' => $all_plugins['inactive_plugins'],
305 'ip_address' => $this->__get_user_ip_address(),
306 'theme' => get_stylesheet(),
307 'country' => $store_country
308 ];
309 // for child classes.
310 $extra = $this->get_extra_data();
311 if ( ! empty( $extra ) ) {
312 $data['extra'] = $extra;
313 }
314
315 return apply_filters( $this->client->getSlug() . '_tracker_data', $data );
316 }
317
318 /**
319 * If a child class wants to send extra data
320 *
321 * @return mixed
322 */
323 protected function get_extra_data() {
324 return $this->extra_data;
325 }
326
327 /**
328 * Explain the user which data we collect
329 *
330 * @return array
331 */
332 protected function data_we_collect() {
333 $data = [
334 esc_html__( 'Server environment details (php, mysql, server, WordPress versions).', 'disco' ),
335 ];
336 $data = apply_filters( $this->client->getSlug() . '_what_tracked', $data );
337
338 return $data;
339 }
340
341 /**
342 * Get the message array of what data being collected
343 * @return array
344 */
345 public function get_data_collection_description() {
346 return $this->data_we_collect();
347 }
348
349 /**
350 * Get Site SuperAdmin
351 * Returns Empty WP_User instance if fails
352 * @return WP_User
353 */
354 private function __get_admin() {
355 $admins = get_users(
356 [
357 'role' => 'administrator',
358 'orderby' => 'ID',
359 'order' => 'ASC',
360 'number' => 1,
361 'paged' => 1,
362 ]
363 );
364
365 return ( is_array( $admins ) && ! empty( $admins ) ) ? $admins[0] : new WP_User();
366 }
367
368 /**
369 * Check if the user has opted into tracking
370 *
371 * @return bool
372 */
373 public function is_tracking_allowed() {
374 return 'yes' == get_option( $this->client->getSlug() . '_allow_tracking', 'no' );
375 }
376
377 /**
378 * Get the last time a tracking was sent
379 *
380 * @return false|int
381 */
382 private function __get_last_send() {
383 return get_option( $this->client->getSlug() . '_tracking_last_send', false );
384 }
385
386 /**
387 * Check if the notice has been dismissed or enabled
388 *
389 * @return boolean
390 */
391 private function __notice_dismissed() {
392 $hide_notice = get_option( $this->client->getSlug() . '_tracking_notice', 'no' );
393 if ( 'hide' == $hide_notice ) {
394 return true;
395 }
396
397 return false;
398 }
399
400 /**
401 * Check if the current server is localhost
402 *
403 * @return boolean
404 */
405 public function __is_local_server() {
406 // phpcs:disable
407 return apply_filters( 'WebAppick_is_local', isset( $_SERVER['REMOTE_ADDR'] ) ? in_array( $_SERVER['REMOTE_ADDR'], [ '127.0.0.1', '::1' ] ) : true );
408 // phpcs:enable
409 }
410
411 /**
412 * Schedule the event weekly
413 *
414 * @return void
415 */
416 private function __schedule_event() {
417 $hook_name = $this->client->getSlug() . '_tracker_send_event';
418 if ( ! wp_next_scheduled( $hook_name ) ) {
419 wp_schedule_event( time(), 'weekly', $hook_name );
420 }
421 }
422
423 /**
424 * Clear any scheduled hook
425 *
426 * @return void
427 */
428 private function __clear_schedule_event() {
429 wp_clear_scheduled_hook( $this->client->getSlug() . '_tracker_send_event' );
430 }
431
432 /**
433 * Display the admin notice to users that have not opted-in or out
434 *
435 * @return void
436 */
437 public function admin_notice() {
438 if ( $this->__notice_dismissed() ) {
439 return;
440 }
441
442 if ( $this->is_tracking_allowed() ) {
443 return;
444 }
445 if ( ! current_user_can( 'manage_options' ) ) {
446 return;
447 }
448
449 // don't show tracking if a local server.
450 if ( ! $this->__is_local_server() ) {
451
452 if ( empty( $this->notice ) ) {
453 $notice = sprintf(
454 apply_filters(
455 $this->client->getSlug() . '_tracking_default_notice_message',
456 /* translators: 1: plugin name */
457 esc_html__( 'Want to help make %1$s even more awesome? Allow %1$s to collect non-sensitive diagnostic data and usage information.', 'disco' )
458 ),
459 '<strong>' . esc_html( $this->client->getName() ) . '</strong>'
460 );
461 } else {
462 $notice = $this->notice;
463 }
464
465 $notice .= ' (<a class="' . $this->client->getSlug() . '-insights-data-we-collect" href="#">' . esc_html__( 'what we collect', 'disco' ) . '</a>)';
466 $notice .= '<p class="description" style="display:none;">' . implode( ', ', $this->data_we_collect() ) . '. ' . esc_html__( 'No sensitive data is tracked.', 'disco' ) . '</p>';
467 echo '<div class="updated"><p>';
468 echo wp_kses_post($notice); // phpcs:ignore xss ok
469 echo '</p><p class="submit">';
470 echo '&nbsp;<a href="' . esc_url( $this->get_opt_out_url() ) . '" class="disco-notice-secondary-button">' . esc_html__( 'No thanks', 'disco' ) . '</a>';
471 echo '&nbsp;<a href="' . esc_url( $this->get_opt_in_url() ) . '" class="disco-notice-primary-button">' . esc_html__( 'Allow', 'disco' ) . '</a>';
472 echo '</p></div>';
473 echo "<script type='text/javascript'>jQuery('." . esc_attr( $this->client->getSlug() ) . "-insights-data-we-collect').on('click', function(e) {
474 e.preventDefault();
475 jQuery(this).parents('.updated').find('p.description').slideToggle('fast');
476 });</script>";
477 }
478 }
479
480 /**
481 * Tracking Opt In URL
482 * @return string
483 */
484 public function get_opt_in_url() {
485 return add_query_arg(
486 [
487 $this->client->getSlug() . '_tracker_optIn' => 'true',
488 '_wpnonce' => wp_create_nonce( $this->client->getSlug() . '_insight_action' ),
489 ]
490 );
491 }
492
493 /**
494 * Tracking Opt Out URL
495 * @return string
496 */
497 public function get_opt_out_url() {
498 return add_query_arg(
499 [
500 $this->client->getSlug() . '_tracker_optOut' => 'true',
501 '_wpnonce' => wp_create_nonce( $this->client->getSlug() . '_insight_action' ),
502 ]
503 );
504 }
505
506 /**
507 * handle the optIn/optOut
508 *
509 * @return void
510 */
511 public function handle_optIn_optOut() {
512 if ( isset( $_REQUEST['_wpnonce'] ) && ( isset( $_GET[ $this->client->getSlug() . '_tracker_optIn' ] ) || isset( $_GET[ $this->client->getSlug() . '_tracker_optOut' ] ) ) ) {
513 check_admin_referer( $this->client->getSlug() . '_insight_action' );
514 if ( isset( $_GET[ $this->client->getSlug() . '_tracker_optIn' ] ) && 'true' == $_GET[ $this->client->getSlug() . '_tracker_optIn' ] ) {
515 $this->optIn();
516 wp_safe_redirect( remove_query_arg( $this->client->getSlug() . '_tracker_optIn' ) );
517 exit;
518 }
519 if ( isset( $_GET[ $this->client->getSlug() . '_tracker_optOut' ] ) && 'true' == $_GET[ $this->client->getSlug() . '_tracker_optOut' ] ) {
520 $this->optOut();
521 wp_safe_redirect( remove_query_arg( $this->client->getSlug() . '_tracker_optOut' ) );
522 exit;
523 }
524 }
525 }
526
527 /**
528 * Add query vars to removable query args array
529 *
530 * @param array $removable_query_args array of removable args.
531 *
532 * @return array
533 */
534 public function add_removable_query_args( $removable_query_args ) {
535 return array_merge(
536 $removable_query_args,
537 [ $this->client->getSlug() . '_tracker_optIn', $this->client->getSlug() . '_tracker_optOut', '_wpnonce' ]
538 );
539 }
540
541 /**
542 * Tracking optIn
543 *
544 * @param bool $override optional. set send tracking data override setting, ignore last send datetime setting if true.
545 *
546 * @return void
547 * @see Insights::send_tracking_data()
548 */
549 public function optIn( $override = false ) {
550 update_option( $this->client->getSlug() . '_allow_tracking', 'yes', false );
551 update_option( $this->client->getSlug() . '_tracking_notice', 'hide', false );
552 $this->__clear_schedule_event();
553 $this->__schedule_event();
554 $this->send_tracking_data( $override );
555 }
556
557 /**
558 * optOut from tracking
559 *
560 * @return void
561 */
562 public function optOut() {
563 update_option( $this->client->getSlug() . '_allow_tracking', 'no', false );
564 update_option( $this->client->getSlug() . '_tracking_notice', 'hide', false );
565 $this->__clear_schedule_event();
566 }
567
568 /**
569 * Get the number of post counts
570 *
571 * @param string $post_type PostType name to get count for.
572 *
573 * @return integer
574 */
575 public function get_post_count( $post_type ) {
576 global $wpdb;
577 // phpcs:disable
578 return (int) $wpdb->get_var(
579 $wpdb->prepare(
580 "SELECT count(ID) FROM $wpdb->posts WHERE post_type = %s and post_status = 'publish'",
581 $post_type
582 )
583 );
584 // phpcs:enable
585 }
586
587 /**
588 * Get server related info.
589 *
590 * @return array
591 */
592 private function __get_server_info() {
593 global $wpdb;
594 $server_data = [
595 'software' => ( isset( $_SERVER['SERVER_SOFTWARE'] ) && ! empty( $_SERVER['SERVER_SOFTWARE'] ) ) ? sanitize_text_field( $_SERVER['SERVER_SOFTWARE'] ) : 'N/A',
596 'php_version' => ( function_exists( 'phpversion' ) ) ? phpversion() : 'N/A',
597 'mysql_version' => $wpdb->db_version(),
598 'php_execution_time' => @ini_get( 'max_execution_time' ), // phpcs:ignore
599 'php_max_upload_size' => size_format( wp_max_upload_size() ),
600 'php_default_timezone' => date_default_timezone_get(),
601 'php_soap' => class_exists( 'SoapClient' ) ? 'Yes' : 'No',
602 'php_fsockopen' => function_exists( 'fsockopen' ) ? 'Yes' : 'No',
603 'php_curl' => function_exists( 'curl_init' ) ? 'Yes' : 'No',
604 'php_ftp' => function_exists( 'ftp_connect' ) ? 'Yes' : 'No',
605 'php_sftp' => function_exists( 'ssh2_connect' ) ? 'Yes' : 'No',
606 ];
607
608 return $server_data;
609 }
610
611 /**
612 * Get WordPress related data.
613 *
614 * @return array
615 */
616 private function __get_wp_info() {
617 $wp_data = [
618 'memory_limit' => WP_MEMORY_LIMIT,
619 'debug_mode' => ( defined( 'WP_DEBUG' ) && WP_DEBUG ) ? 'Yes' : 'No',
620 'locale' => get_locale(),
621 'version' => get_bloginfo( 'version' ),
622 'multisite' => is_multisite() ? 'Yes' : 'No',
623 ];
624
625 return $wp_data;
626 }
627
628 /**
629 * Get the list of active and inactive plugins
630 * @return array
631 */
632 private function __get_all_plugins() {
633 if ( ! function_exists( 'get_plugins' ) ) {
634 include ABSPATH . '/wp-admin/includes/plugin.php';
635 }
636 $plugins = get_plugins();
637 $active_plugins = [];
638 $active_plugins_keys = get_option( 'active_plugins', [] );
639 foreach ( $plugins as $k => $v ) {
640 // Take care of formatting the data how we want it.
641 $formatted = [
642 'name' => isset( $v['Name'] ) ? wp_strip_all_tags( $v['Name'] ) : '',
643 'version' => isset( $v['Version'] ) ? wp_strip_all_tags( $v['Version'] ) : 'N/A',
644 'author' => isset( $v['Author'] ) ? wp_strip_all_tags( $v['Author'] ) : 'N/A',
645 'network' => isset( $v['Network'] ) ? wp_strip_all_tags( $v['Network'] ) : 'N/A',
646 'plugin_uri' => isset( $v['PluginURI'] ) ? wp_strip_all_tags( $v['PluginURI'] ) : 'N/A',
647 ];
648 if ( in_array( $k, $active_plugins_keys ) ) {
649 unset( $plugins[ $k ] ); // Remove active plugins from list so we can show active and inactive separately0
650 $active_plugins[ $k ] = $formatted;
651 } else {
652 $plugins[ $k ] = $formatted;
653 }
654 }
655
656 return [
657 'active_plugins' => $active_plugins,
658 'inactive_plugins' => $plugins,
659 ];
660 }
661
662 /**
663 * Get user totals based on user role.
664 *
665 * @return array
666 */
667 public function __get_user_counts() {
668 $user_count = [];
669 $user_count_data = count_users();
670 $user_count['total'] = $user_count_data['total_users'];
671 // Get user count based on user role.
672 foreach ( $user_count_data['avail_roles'] as $role => $count ) {
673 $user_count[ $role ] = $count;
674 }
675
676 return $user_count;
677 }
678
679 /**
680 * Add weekly cron schedule
681 *
682 * @param array $schedules Cron Schedules.
683 *
684 * @return array
685 */
686 public function add_weekly_schedule( $schedules ) {
687 $schedules['weekly'] = [
688 'interval' => DAY_IN_SECONDS * 7,
689 'display' => __( 'Once Weekly', 'disco' ),
690 ];
691
692 return $schedules;
693 }
694
695 /**
696 * Plugin activation hook
697 *
698 * @return void
699 */
700 public function activate_plugin() {
701 $allowed = get_option( $this->client->getSlug() . '_allow_tracking', 'no' );
702 // if it wasn't allowed before, do nothing.
703 if ( 'yes' !== $allowed ) {
704 return;
705 }
706 // re-schedule and delete the last sent time so we could force send again.
707 wp_schedule_event( time(), 'weekly', $this->client->getSlug() . '_tracker_send_event' );
708 delete_option( $this->client->getSlug() . '_tracking_last_send' );
709 $this->send_tracking_data( true );
710 }
711
712 /**
713 * Clear our options upon deactivation
714 *
715 * @return void
716 */
717 public function deactivation_cleanup() {
718 $this->__clear_schedule_event();
719 if ( 'theme' == $this->client->getType() ) {
720 delete_option( $this->client->getSlug() . '_tracking_last_send' );
721 delete_option( $this->client->getSlug() . '_allow_tracking' );
722 }
723 delete_option( $this->client->getSlug() . '_tracking_notice' );
724 }
725
726 /**
727 * Hook into action links and modify the deactivate link
728 *
729 * @param array $links Plugin Action Links.
730 *
731 * @return array
732 */
733 public function plugin_action_links( $links ) {
734
735 if ( array_key_exists( 'deactivate', $links ) ) {
736 $links['deactivate'] = str_replace( '<a', '<a class="' . $this->client->getSlug() . '-deactivate-link"', $links['deactivate'] );
737 }
738
739 return $links;
740 }
741
742 /**
743 * Deactivation reasons
744 * @return array
745 */
746 private function __get_uninstall_reasons() {
747
748 $reasons = [
749 [
750 'id' => 'could-not-understand',
751 'text' => esc_html__( 'I couldn\'t understand how to make it work', 'disco' ),
752 'type' => 'textarea',
753 'placeholder' => esc_html__( 'Would you like us to assist you?', 'disco' ),
754 ],
755 [
756 'id' => 'found-better-plugin',
757 'text' => esc_html__( 'I found a better plugin', 'disco' ),
758 'type' => 'text',
759 'placeholder' => esc_html__( 'Which plugin?', 'disco' ),
760 ],
761 [
762 'id' => 'not-have-that-feature',
763 'text' => esc_html__( 'The plugin is great, but I need specific feature that you don\'t support', 'disco' ),
764 'type' => 'textarea',
765 'placeholder' => esc_html__( 'Could you tell us more about that feature?', 'disco' ),
766 ],
767 [
768 'id' => 'is-not-working',
769 'text' => esc_html__( 'The plugin is not working', 'disco' ),
770 'type' => 'textarea',
771 'placeholder' => esc_html__( 'Could you tell us a bit more whats not working?', 'disco' ),
772 ],
773 [
774 'id' => 'looking-for-other',
775 'text' => esc_html__( 'It\'s not what I was looking for', 'disco' ),
776 'type' => '',
777 'placeholder' => '',
778 ],
779 [
780 'id' => 'did-not-work-as-expected',
781 'text' => esc_html__( 'The plugin didn\'t work as expected', 'disco' ),
782 'type' => 'textarea',
783 'placeholder' => esc_html__( 'What did you expect?', 'disco' ),
784 ],
785 [
786 'id' => 'debugging',
787 'text' => esc_html__( 'Temporary deactivation for debugging', 'disco' ),
788 'type' => '',
789 'placeholder' => '',
790 ],
791 [
792 'id' => 'other',
793 'text' => esc_html__( 'Other', 'disco' ),
794 'type' => 'textarea',
795 'placeholder' => esc_html__( 'Could you tell us a bit more?', 'disco' ),
796 ],
797 ];
798 $extra = apply_filters( $this->client->getSlug() . '_extra_uninstall_reasons', [], $reasons );
799 if ( is_array( $extra ) && ! empty( $extra ) ) {
800 // extract the last (other) reason and add after extras.
801 $other = array_pop( $reasons );
802 $reasons = array_merge( $reasons, $extra, [ $other ] );
803 }
804 return $reasons;
805 }
806
807 /**
808 * Plugin deactivation uninstall reason submission
809 *
810 * @return void
811 */
812 public function uninstall_reason_submission() {
813 check_ajax_referer( $this->client->getSlug() . '_insight_action' );
814 if ( ! isset( $_POST['reason_id'] ) ) {
815 wp_send_json_error( esc_html__( 'Invalid Request', 'disco' ) );
816 wp_die();
817 }
818 $current_user = wp_get_current_user();
819 global $wpdb;
820 // @TODO remove deprecated data after server update
821 $data = [
822 'hash' => $this->client->getHash(),
823 'reason_id' => isset( $_REQUEST['reason_id'] ) && ! empty( $_REQUEST['reason_id'] ) ? sanitize_text_field( $_REQUEST['reason_id'] ) : '',
824 'reason_info' => isset( $_REQUEST['reason_info'] ) ? trim( sanitize_textarea_field( $_REQUEST['reason_info'] ) ) : '',
825 'plugin' => $this->client->getName(),
826 'site' => $this->__get_site_name(),
827 'url' => esc_url( home_url() ),
828 'admin_email' => get_option( 'admin_email' ),
829 'user_email' => $current_user->user_email,
830 'user_name' => $current_user->display_name,
831 // deprecated.
832 'first_name' => ( ! empty( $current_user->first_name ) ) ? $current_user->first_name : $current_user->display_name,
833 'last_name' => $current_user->last_name,
834 'server' => $this->__get_server_info(),
835 'software' => isset( $_SERVER['SERVER_SOFTWARE'] ) ? sanitize_text_field( $_SERVER['SERVER_SOFTWARE'] ) : 'Generic', // deprecated, using $data['server'] for wp info.
836 'php_version' => phpversion(), // deprecated, using $data['server'] for wp info.
837 'mysql_version' => $wpdb->db_version(), // deprecated, using $data['server'] for wp info.
838 'wp' => $this->__get_wp_info(),
839 'wp_version' => get_bloginfo( 'version' ), // deprecated, using $data['wp'] for wp info.
840 'locale' => get_locale(), // deprecated, using $data['wp'] for wp info.
841 'multisite' => is_multisite() ? 'Yes' : 'No', // deprecated, using $data['wp'] for wp info.
842 'ip_address' => $this->__get_user_ip_address(),
843 'version' => $this->client->getProjectVersion(),
844 ];
845 // Add extra data.
846 $extra = $this->get_extra_data();
847 if ( ! empty( $extra ) ) {
848 $data['extra'] = $extra;
849 }
850 $this->client->send_request( $data, 'reason' );
851 wp_send_json_success();
852 wp_die();
853 }
854
855 /**
856 * Handle Support Ticket Submission
857 * @return void
858 */
859 public function support_ticket_submission() {
860 check_ajax_referer( $this->client->getSlug() . '_insight_action' );
861 if ( empty( $this->ticketTemplate ) || empty( $this->ticketRecipient ) || empty( $this->supportURL ) ) {
862 wp_send_json_error(
863 sprintf(
864 '<p class="mui-error">%s<br>%s</p>',
865 esc_html__( 'Something Went Wrong.', 'disco' ),
866 esc_html__( 'Please try again after sometime.', 'disco' )
867 )
868 );
869 wp_die();
870 }
871 if (
872 isset( $_REQUEST['name'], $_REQUEST['email'], $_REQUEST['subject'], $_REQUEST['website'], $_REQUEST['message'] ) &&
873 (
874 ! empty( sanitize_text_field( $_REQUEST['name'] ) ) &&
875 ! empty( sanitize_email( $_REQUEST['email'] ) ) &&
876 ! empty( sanitize_text_field( $_REQUEST['subject'] ) ) &&
877 ! empty( sanitize_text_field( $_REQUEST['website'] ) ) &&
878 ! empty( sanitize_text_field( $_REQUEST['message'] ) )
879 )
880 ) {
881 $headers = [
882 'Content-Type: text/html; charset=UTF-8',
883 sprintf(
884 'From: %s <%s>',
885 sanitize_text_field( $_REQUEST['name'] ),
886 sanitize_email( $_REQUEST['email'] )
887 ),
888 sprintf(
889 'Reply-To: %s <%s>',
890 sanitize_text_field( $_REQUEST['name'] ),
891 sanitize_text_field( $_REQUEST['email'] )
892 ),
893 ];
894
895 foreach ( $_REQUEST as $k => $v ) {
896 $sanitizer = 'sanitize_text_field';
897 if ( 'email' == $k ) {
898 $sanitizer = 'sanitize_email';
899 }
900 if ( 'website' == $k ) {
901 $sanitizer = 'esc_url';
902 }
903 $v = call_user_func_array( $sanitizer, [ $v ] );
904 $_REQUEST[ $k ] = $v; // phpcs: sanitize ok.
905 $k = '__' . strtoupper( $k ) . '__';
906 $this->ticketTemplate = str_replace( [ $k ], [ $v ], $this->ticketTemplate );
907 }
908 $projectSlug = $this->client->getSlug();
909 $isSent = wp_mail( $this->ticketRecipient, sanitize_text_field( $_REQUEST['subject'] ), sprintf( '<div>%s</div>', $this->ticketTemplate ), $headers );// phpcs:ignore WordPressVIPMinimum.Functions.RestrictedFunctions.wp_mail_wp_mail
910 if ( $isSent ) {
911 /**
912 * Set Ajax Success Response for Support Ticket Submission
913 * @param string $supportResponse
914 * @param array $_REQUEST
915 */
916 $supportResponse = apply_filters( "WebAppick_{$projectSlug}_Support_Request_Ajax_Success_Response" , false, $_REQUEST );
917 if ( false !== $supportResponse ) {
918 $this->supportResponse = $supportResponse;
919 } else {
920 $this->supportResponse = sprintf(
921 '<h3>%s</h3>',
922 esc_html__( 'Thank you -- Support Ticket Submitted.', 'disco' )
923 );
924 }
925 wp_send_json_success( $this->supportResponse );
926 wp_die();
927 } else {
928 /**
929 * Set Support Ticket Ajax Error Response.
930 * @param string $supportErrorResponse
931 * @param array $_REQUEST
932 */
933 $supportErrorResponse = apply_filters( "WebAppick_{$projectSlug}_Support_Request_Ajax_Error_Response" , false, $_REQUEST );
934 if ( false !== $supportErrorResponse ) {
935 $this->supportErrorResponse = $supportErrorResponse;
936 } else {
937 $this->supportErrorResponse = sprintf(
938 '<div class="mui-error"><p>%s</p></div>',
939 esc_html__( 'Something Went Wrong. Please Try Again After Sometime.', 'disco' )
940 );
941 }
942 wp_send_json_error( $this->supportErrorResponse );
943 }
944 } else {
945 wp_send_json_error( sprintf( '<p class="mui-error">%s</p>', esc_html__( 'Missing Required Fields.', 'disco' ) ) );
946 }
947 wp_die();
948 }
949
950 /**
951 * Handle the plugin deactivation feedback
952 *
953 * @return void
954 */
955 public function deactivate_scripts() {
956 global $pagenow;
957 if ( 'plugins.php' !== $pagenow ) {
958 return;
959 }
960 $reasons = $this->__get_uninstall_reasons();
961 $admin_user = $this->__get_admin();
962 $displayName = ( ! empty( $admin_user->first_name ) && ! empty( $admin_user->last_name ) ) ? $admin_user->first_name . ' ' . $admin_user->last_name : $admin_user->display_name;
963 $showSupportTicket = ( ! empty( $this->ticketTemplate ) && ! empty( $this->ticketRecipient ) && ! empty( $this->supportURL ) );
964 ?>
965 <div class="wapk-dr-modal" id="<?php echo esc_attr( $this->client->getSlug() ); ?>-wapk-dr-modal" aria-label="<?php /* translators: 1: Plugin Name */ printf( esc_attr__( '&ldquo;%s&rdquo; Uninstall Confirmation', 'disco' ), esc_attr( $this->client->getName() ) ); ?>" role="dialog" aria-modal="true">
966 <?php if ( $showSupportTicket ) { ?>
967 <div class="disco-deactivation-modal wapk-dr-modal-wrap support" style="display: none;">
968 <div class="wapk-dr-modal-header">
969 <h3><?php esc_html_e( 'Submit Support Ticket.', 'disco' ); ?></h3>
970 <a href="javascript:void 0;" class="wapk-dr-modal-close" aria-label="<?php esc_attr_e( 'Close', 'disco' ); ?>">
971 <!--suppress HtmlUnknownAttribute -->
972 <svg class="" focusable="false" viewBox="0 0 24 24" aria-hidden="true" role="presentation">
973 <path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"></path>
974 </svg>
975 </a>
976 </div>
977 <div class="wapk-dr-modal-body">
978 <div class="wapk-row mui col-2 col-left">
979 <label for="wapk-support-name" class="<?php echo ! empty( $displayName ) ? 'shrink' : ''; ?>"><?php esc_html_e( 'Name', 'disco' ); ?></label>
980 <div class="wapk-form-control">
981 <input type="text" name="name" id="wapk-support-name" value="<?php echo esc_attr( $displayName ); ?>" required>
982 </div>
983 </div>
984 <div class="wapk-row mui col-2 col-right">
985 <label for="wapk-support-email" class="shrink"><?php esc_html_e( 'Email', 'disco' ); ?></label>
986 <div class="wapk-form-control">
987 <input type="email" name="email" id="wapk-support-email" value="<?php echo esc_attr( $admin_user->user_email ); ?>" required>
988 </div>
989 </div>
990 <div class="clear"></div>
991 <div class="wapk-row mui col-2 col-left">
992 <label for="wapk-support-subject"><?php esc_html_e( 'Subject', 'disco' ); ?></label>
993 <div class="wapk-form-control">
994 <input type="text" name="subject" id="wapk-support-subject" required>
995 </div>
996 </div>
997 <div class="wapk-row mui col-2 col-right">
998 <label for="wapk-support-website" class="shrink"><?php esc_html_e( 'Website', 'disco' ); ?></label>
999 <div class="wapk-form-control">
1000 <input type="url" name="website" id="wapk-support-website" value="<?php echo esc_url( site_url() ); ?>" required>
1001 </div>
1002 </div>
1003 <div class="clear"></div>
1004 <div class="wapk-row mui">
1005 <label for="wapk-support-message"><?php esc_html_e( 'Message', 'disco' ); ?></label>
1006 <div class="wapk-form-control">
1007 <textarea id="wapk-support-message" name='message' rows="11" required></textarea>
1008 </div>
1009 </div>
1010 <div class="response">
1011 <div class="wrapper"></div>
1012 </div>
1013 </div>
1014 <div class="wapk-dr-modal-footer">
1015 <button class="disco-notice-primary-button send-ticket"><?php esc_html_e( 'Send Message', 'disco' ); ?></button>
1016 <button class="disco-notice-secondary-button close-ticket"><?php esc_html_e( 'Cancel', 'disco' ); ?></button>
1017 </div>
1018 </div>
1019 <?php } ?>
1020 <div class="disco-deactivation-modal wapk-dr-modal-wrap reason">
1021 <div class="wapk-dr-modal-header">
1022 <h3><?php esc_html_e( 'If you have a moment, please let us know why you are deactivating:', 'disco' ); ?></h3>
1023 <a href="javascript:void 0;" class="wapk-dr-modal-close" aria-label="<?php esc_attr_e( 'Close', 'disco' ); ?>">
1024 <!--suppress HtmlUnknownAttribute -->
1025 <svg class="" focusable="false" viewBox="0 0 24 24" aria-hidden="true" role="presentation">
1026 <path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"></path>
1027 </svg>
1028 </a>
1029 </div>
1030 <div class="wapk-dr-modal-body">
1031 <ul class="reasons">
1032 <?php foreach ( $reasons as $reason ) { ?>
1033 <li data-type="<?php echo esc_attr( $reason['type'] ); ?>" data-placeholder="<?php echo esc_attr( $reason['placeholder'] ); ?>">
1034 <label><input type="radio" name="selected-reason" value="<?php echo esc_attr( $reason['id'] ); ?>"> <?php echo esc_html( $reason['text'] ); ?></label>
1035 </li>
1036 <?php } ?>
1037 </ul>
1038 <div class="response" style="<?php echo ( $showSupportTicket ) ? 'display: block;' : ''; ?>">
1039 <div class="disco-deactivation-modal wrapper">
1040 <?php if ( $showSupportTicket ) { ?>
1041 <p><?php esc_html_e( 'In trouble? Please submit a support request.', 'disco' ); ?></p>
1042 <p>
1043 <a href="#" class="disco-notice-secondary-button not-interested"><?php esc_html_e( 'Not Interested', 'disco' ); ?></a>
1044 <button class="disco-notice-primary-button open-ticket-form"><?php esc_html_e( 'Open Support Ticket', 'disco' ); ?></button>
1045 </p>
1046 <?php } ?>
1047 </div>
1048 </div>
1049 </div>
1050 <div class="wapk-dr-modal-footer">
1051 <a style="background:transparent !important;" href="#" class="button button-link dont-bother-me disabled"><?php esc_html_e( 'I rather wouldn\'t say', 'disco' ); ?></a>
1052 <button class="disco-notice-secondary-button deactivate"><?php esc_html_e( 'Submit & Deactivate', 'disco' ); ?></button>
1053 <button class="disco-notice-primary-button modal-close"><?php esc_html_e( 'Cancel', 'disco' ); ?></button>
1054 </div>
1055 </div>
1056 </div>
1057 <!--suppress CssUnusedSymbol, CssInvalidPseudoSelector, CssFloatPxLength -->
1058 <style type="text/css">
1059 .wapk-dr-modal, .wapk-dr-modal * { box-sizing: border-box; }
1060 .wapk-dr-modal { position: fixed; z-index: 99999; top: 0; right: 0; bottom: 0; left: 0; background: rgba(0, 0, 0, 0.5); display: none; }
1061 .wapk-dr-modal.modal-active { display: block; }
1062 .wapk-dr-modal strong, .wapk-dr-modal b { font-weight: bold; }
1063 .wapk-dr-modal-wrap { width: 475px; position: relative; margin: 10% auto; background: #fff; }
1064 .wapk-dr-modal-wrap { position: absolute; display: block; top: 0; left: 0; right: 0; /*bottom: 0;*/ z-index: 99; }
1065 .wapk-dr-modal-wrap.support { z-index: 999; margin: 6% auto; }
1066 .wapk-dr-modal-wrap .response { position: absolute; display: none; background: rgba(0, 150, 136, 0.68); top: 0; left: 0; right: 0; bottom: 0; overflow: hidden; }
1067 .wapk-dr-modal .response.show { display: block; }
1068 .wapk-dr-modal-wrap .response .wrapper { display: flex; align-items: center; justify-content: center; width: calc(100% - 40px); height: calc(100% - 40px); flex-flow: column; padding: 40px 40px; margin: 20px 20px; text-align: center; background: #FFF; }
1069 .wapk-dr-modal .reason .response .wrapper { width: calc(100% - 80px); height: calc(100% - 80px); flex-flow: column; padding: 40px 40px; margin: 40px; }
1070 .wapk-dr-modal .button .dashicons { margin: 4px 0; }
1071 .wapk-dr-modal-header { border-bottom: 1px solid #eee; padding: 8px 40px 8px 20px; position: relative; display: block; width: 100%; float: left; }
1072 .wapk-dr-modal-header h3 { line-height: 150%; margin: 0; }
1073 .wapk-dr-modal-close { position: absolute; top: 50%; right: 10px; transform: translateY(-50%); width: 20px; height: 20px; line-height: 0; }
1074 .wapk-dr-modal-close svg { font-size: 20px; display: inline-block; width: 1em; height: 1em; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; }
1075 .wapk-dr-modal-body { padding: 5px 20px 20px 20px; position: relative; display: block; width: 100%; float: left; box-sizing: border-box; }
1076 .wapk-dr-modal-body .reason-input { margin-top: 5px; margin-left: 20px; }
1077 .wapk-dr-modal-footer { border-top: 1px solid #eee; padding: 12px 20px; text-align: right; position: relative; display: block; width: 100%; float: left; }
1078 .wapk-dr-modal-footer a, .wapk-dr-modal-footer button { vertical-align: middle; }
1079 .support .wapk-dr-modal-footer { text-align: left; }
1080 .support .wapk-dr-modal-footer button { float: right; margin-left: 10px; }
1081 .wapk-dr-modal .wapk-row { position: relative; width: 100%; display: block; box-sizing: border-box; float: left; margin: 4px auto; }
1082 .mui { border: 0; margin: 0; display: inline-flex; padding: 0; min-width: 0; flex-direction: column; vertical-align: top; }
1083 .wapk-dr-modal .wapk-row.col-2 { width: calc(50% - 16px); }
1084 .wapk-dr-modal .wapk-row.col-3 { width: calc(calc(100% / 3) - 16px); }
1085 .wapk-dr-modal .wapk-row.col-left { margin-right: 8px; }
1086 .wapk-dr-modal .wapk-row.col-center { margin-left: 8px; margin-right: 8px; }
1087 .wapk-dr-modal .wapk-row.col-right { margin-left: 8px; }
1088 .wapk-dr-modal .mui .wapk-form-control { cursor: text; display: inline-flex; position: relative; font-size: 1rem; box-sizing: border-box; align-items: center; line-height: 1.1875em; width: 100%; }
1089 .wapk-dr-modal .mui label { color: rgba(0, 0, 0, 0.54); padding: 0; font-size: 1rem; font-weight: 400; line-height: 1; letter-spacing: 0.00938em; display: block; transform-origin: top left; top: 0; left: 0; position: absolute; transform: translate(0, 24px) scale(1); transition: color 200ms cubic-bezier(0.0, 0, 0.2, 1) 0ms, transform 200ms cubic-bezier(0.0, 0, 0.2, 1) 0ms; }
1090 .wapk-dr-modal .mui label.focused { color: #007cba; }
1091 p:not(.helper-text).mui-error, div:not(.helper-text).mui-error, .wapk-dr-modal .mui label.mui-error { color: #f44336; }
1092 p:not(.helper-text).mui-error, div:not(.helper-text).mui-error { padding: 5px 10px; border: 1px solid #f44336; font-weight: bold; }
1093 .wapk-dr-modal .mui label.shrink { transform: translate(0, 1.5px) scale(0.75); transform-origin: top left; }
1094 .wapk-dr-modal .mui label + .wapk-form-control { margin-top: 16px; }
1095 .wapk-dr-modal .mui .wapk-form-control:before { left: 0; right: 0; bottom: 0; content: "\00a0"; position: absolute; transition: border-bottom-color 200ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; border-bottom: 1px solid rgba(0, 0, 0, 0.42); pointer-events: none; }
1096 .wapk-dr-modal .mui .wapk-form-control:hover:not(.disabled):before { border-bottom: 2px solid rgba(0, 0, 0, 0.87); }
1097 .wapk-dr-modal .mui .wapk-form-control:after { left: 0; right: 0; bottom: 0; content: ""; position: absolute; transform: scaleX(0); transition: transform 200ms cubic-bezier(0.0, 0, 0.2, 1) 0ms; border-bottom: 2px solid #007cba; pointer-events: none; }
1098 .wapk-dr-modal .mui .wapk-form-control.focused:after { transform: scaleX(1); }
1099 .wapk-dr-modal .mui .wapk-form-control.mui-error:after { transform: scaleX(1); border-bottom-color: #f44336; }
1100 .wapk-dr-modal .mui .wapk-form-control input,
1101 .wapk-dr-modal .mui .wapk-form-control textarea { font: inherit; color: currentColor; width: 100%; border: 0; height: 1.1875em; min-height: auto; margin: 0; display: block; padding: 6px 0 7px; min-width: 0; background: none; box-sizing: content-box; -webkit-tap-highlight-color: transparent; }
1102 .wapk-dr-modal .mui .wapk-form-control input { animation-name: mui-keyframes-auto-fill-cancel; }
1103 .wapk-dr-modal .mui .wapk-form-control input:-moz-autofill,
1104 .wapk-dr-modal .mui .wapk-form-control input:-webkit-autofill { animation-name: mui-keyframes-auto-fill; animation-duration: 5000s; }
1105 @-webkit-keyframes mui-keyframes-auto-fill {}
1106 @-webkit-keyframes mui-keyframes-auto-fill-cancel {}
1107 .wapk-dr-modal .mui .wapk-form-control textarea { height: auto; resize: none; padding: 0; }
1108 .wapk-dr-modal .mui .wapk-form-control input::-webkit-search-decoration,
1109 .wapk-dr-modal .mui .wapk-form-control textarea::-webkit-search-decoration { -webkit-appearance: none; }
1110 .wapk-dr-modal .mui .wapk-form-control input::-webkit-input-placeholder,
1111 .wapk-dr-modal .mui .wapk-form-control textarea::-webkit-input-placeholder { color: currentColor; opacity: 0.42; transition: opacity 200ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; }
1112 .wapk-dr-modal .mui .wapk-form-control input::-moz-placeholder,
1113 .wapk-dr-modal .mui .wapk-form-control textarea::-moz-placeholder { color: currentColor; opacity: 0.42; transition: opacity 200ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; }
1114 .wapk-dr-modal .mui .wapk-form-control input:-ms-input-placeholder,
1115 .wapk-dr-modal .mui .wapk-form-control textarea:-ms-input-placeholder { color: currentColor; opacity: 0.42; transition: opacity 200ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; }
1116 .wapk-dr-modal .mui .wapk-form-control input::-ms-input-placeholder,
1117 .wapk-dr-modal .mui .wapk-form-control textarea::-ms-input-placeholder { color: currentColor; opacity: 0.42; transition: opacity 200ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; }
1118 .wapk-dr-modal .mui .wapk-form-control input:focus,
1119 .wapk-dr-modal .mui .wapk-form-control input:invalid,
1120 .wapk-dr-modal .mui .wapk-form-control textarea:focus,
1121 .wapk-dr-modal .mui .wapk-form-control textarea:invalid { outline: 0; box-shadow: none; }
1122 .wapk-dr-modal .mui .helper-text { color: rgba(0, 0, 0, 0.54); margin: 8px 0 0 0; font-size: 0.75rem; min-height: 1em; text-align: left; font-weight: 400; line-height: 1em; letter-spacing: 0.03333em; }
1123 .wapk-dr-modal .mui .helper-text.contained { margin: 8px 14px 0; }
1124 .wapk-dr-modal .mui .helper-text.mui-error { color: #f44336; }
1125 .wapk-dr-modal .button.disabled, .wapk-dr-modal button.disabled { cursor: not-allowed !important; }
1126 /*.wapk-dr-modal .wapk-row input, .wapk-dr-modal .wapk-row textarea { width: calc( 100% - 10px ); margin: 0 5px; display: block; vertical-align: middle; box-sizing: border-box; float: left; }*/
1127 </style>
1128 <!--suppress ES6ConvertVarToLetConst, JSUnresolvedVariable -->
1129 <script type="text/javascript">
1130 (function ($) {
1131 $(function () {
1132 /**
1133 * Ajax Helper For Submitting Deactivation Reasons
1134 * @param {Object} data
1135 * @param {*|jQuery|HTMLElement} buttonElem
1136 * @param {String|Function} cb
1137 * @returns {*|jQuery}
1138 * @private
1139 */
1140 function _ajax(data, buttonElem, cb) {
1141 if (buttonElem.hasClass('disabled')) return;
1142 buttonElem.attr('data-label', buttonElem.text());
1143 return $.ajax({
1144 url: ajaxurl,
1145 type: 'POST',
1146 data: $.fn.extend( {}, {
1147 action: '<?php echo esc_attr( $this->client->getSlug() ); ?>_submit-uninstall-reason',
1148 _wpnonce: '<?php echo esc_attr( wp_create_nonce( $this->client->getSlug() . '_insight_action' ) ); ?>'
1149 }, data ), // add default action if action is empty.
1150 beforeSend: function () {
1151 buttonElem.addClass("disabled");
1152 buttonElem.text('<?php esc_html_e( 'Processing...', 'disco' ); ?>');
1153 },
1154 complete: function (event, xhr, options) {
1155 if ('string' === typeof cb) {
1156 window.location.href = cb;
1157 } else if ('function' === typeof cb) {
1158 cb({event: event, xhr: xhr, options: options});
1159 }
1160 }
1161 });
1162 }
1163 // Variables.
1164 var modal = $('#<?php echo esc_attr( $this->client->getSlug() ); ?>-wapk-dr-modal'),
1165 deactivateLink = '',
1166 reason = modal.find('.reason'),
1167 support = modal.find('.support'),
1168 supportResponse = support.find('.response'),
1169 reasonResponse = reason.find('.response'),
1170 mui = $('.mui input, .mui textarea, .mui select'),
1171 // sendButton = modal.find('.send-ticket'),
1172 validMessage = false,
1173 preventDefault = function ( e ) { e && e.preventDefault() },
1174 responseButtons = modal.find('.reason .wapk-dr-modal-footer .button'),
1175 supportURL = '<?php echo esc_url( $this->supportURL ); ?>',
1176 closeModal = function (e) {
1177 preventDefault(e);
1178 var buttons = modal.find('.button');
1179 modal.removeClass('modal-active');
1180 // modal.find('.wapk-dr-modal-wrap').show();
1181 supportResponse.hide().find('.wrapper').html('');
1182 reasonResponse.show();
1183 support.hide();
1184 // enable buttons and restore original labels
1185 buttons.removeClass('disabled');
1186 responseButtons.addClass('disabled');
1187 buttons.each(function () {
1188 var self = $(this), label = self.attr('data-label');
1189 if (label) self.text(label);
1190 });
1191 modal.find('input[type="radio"]').prop('checked', false );
1192 $('.reason-input').remove();
1193 },
1194 checkMessageValidity = function (e) {
1195 // e.target.checkValidity();
1196 var target = e && e.target ? e.target : this;
1197 var self = $(this), currentMui = self.closest('.mui'),
1198 label = currentMui.find('label'),
1199 control = currentMui.find('.wapk-form-control');
1200 if (target.checkValidity()) {
1201 if (label.hasClass('mui-error')) label.removeClass('mui-error');
1202 if (control.hasClass('mui-error')) control.removeClass('mui-error');
1203 currentMui.find('p.helper-text').hide().remove();
1204 validMessage = true;
1205 }
1206 },
1207 resetTicketForm = function( clearValues, clearAll ) {
1208 $('p.helper-text.mui-error').remove();
1209 $('.mui-error').removeClass('mui-error');
1210 if( clearValues ) {
1211 if( clearAll ) mui.val('');
1212 else modal.find('#wapk-support-message,#wapk-support-subject').val('');
1213 }
1214 };
1215 // The MUI
1216 {
1217 // any input el except radio, checkbox and select
1218 mui
1219 .not('select')
1220 .not('[type="checkbox"]')
1221 .not('[type="radio"]')
1222 .on('focus', function () {
1223 var self = $(this), currentMui = self.closest('.mui'),
1224 label = currentMui.find('label'),
1225 control = currentMui.find('.wapk-form-control');
1226 control.addClass('focused');
1227 label.addClass('focused');
1228 label.addClass('shrink');
1229 })
1230 .on('blur', function () {
1231 var self = $(this), currentMui = self.closest('.mui'),
1232 label = currentMui.find('label'),
1233 control = currentMui.find('.wapk-form-control');
1234 control.removeClass('focused');
1235 label.removeClass('focused');
1236 if (self.val() === '') {
1237 label.removeClass('shrink');
1238 }
1239 });
1240 // any input el in mui
1241 mui
1242 .on('blur', checkMessageValidity)
1243 .on('invalid', function (e) {
1244 preventDefault(e);
1245 var self = $(this), currentMui = self.closest('.mui'),
1246 label = currentMui.find('label'),
1247 control = currentMui.find('.wapk-form-control');
1248 currentMui.find('p.helper-text').remove();
1249 validMessage = false;
1250 if (!label.hasClass('mui-error')) label.addClass('mui-error');
1251 if (!control.hasClass('mui-error')) control.addClass('mui-error');
1252 control.after('<p class="helper-text mui-error">' + e.target.validationMessage + '</p>');
1253 });
1254 }
1255 // the clicker
1256 $('#the-list').on('click', 'a.<?php echo esc_attr( $this->client->getSlug() ); ?>-deactivate-link', function (e) {
1257 preventDefault(e);
1258 modal.addClass('modal-active');
1259 deactivateLink = $(this).attr('href');
1260 modal.find('a.dont-bother-me').attr('href', deactivateLink).css('float', 'left');
1261 });
1262 // The Modal
1263 modal
1264 .on( 'click', '.not-interested', function(e) {
1265 preventDefault(e);
1266 $( this ).closest('.response').slideUp( function() {
1267 responseButtons.removeClass('disabled');
1268 } );
1269 } )
1270 .on( 'click', '.open-ticket-form', function(e){
1271 preventDefault(e);
1272 support.slideDown();
1273 resetTicketForm( true );
1274 } )
1275 .on( 'click', '.close-ticket', function (e) {
1276 preventDefault(e);
1277 support.slideUp();
1278 //if( ! reasonResponse.is(':visible') ) responseButtons.removeClass('disabled');
1279 } )
1280 .on( 'click', '.modal-close, .wapk-dr-modal-close', closeModal )
1281 .on( 'click', 'input[type="radio"]', function () {
1282 modal.find('.reason-input').remove();
1283 var parent = $(this).parents('li:first'),
1284 inputType = parent.data('type'),
1285 inputPlaceholder = parent.data('placeholder'),
1286 reasonInputHtml = '<div class="reason-input">' + (('text' === inputType) ? '<input type="text" size="40" />' : '<textarea rows="5" cols="45"></textarea>') + '</div>';
1287 if (inputType !== '') {
1288 parent.append($(reasonInputHtml));
1289 parent.find('input, textarea').attr('placeholder', inputPlaceholder).focus();
1290 }
1291 } )
1292 .on( 'click', '.dont-bother-me', function (e) {
1293 preventDefault(e);
1294 _ajax({
1295 reason_id: 'no-comment',
1296 reason_info: 'I rather wouldn\'t say'
1297 }, $(this), deactivateLink);
1298 } )
1299 .on( 'click', '.deactivate', function (e) {
1300 preventDefault(e);
1301 var $radio = $('input[type="radio"]:checked', modal),
1302 $selected_reason = $radio.parents('li:first'),
1303 $input = $selected_reason.find('textarea, input[type="text"]');
1304 _ajax({
1305 reason_id: (0 === $radio.length) ? 'none' : $radio.val(),
1306 reason_info: (0 !== $input.length) ? $input.val().trim() : ''
1307 }, $(this), deactivateLink);
1308 } )
1309 .on( 'click', '.send-ticket', function (e) {
1310 preventDefault(e);
1311 mui.each(checkMessageValidity);
1312 if (!validMessage) return;
1313 var buttonElem = $(this),
1314 __BTN_TEXT__ = buttonElem.text(),
1315 data = {action: '<?php echo esc_attr( $this->client->getSlug() ); ?>_submit-support-ticket',};
1316 mui.each( function () { data[$(this).attr('name')] = $(this).val() } );
1317 _ajax(data, $(this), function (jqXhr) {
1318 var response = jqXhr.event.responseJSON;
1319 if ( response.hasOwnProperty('data') ) {
1320 supportResponse.find('.wrapper').html(response.data);
1321 supportResponse.show();
1322 }
1323 if( response.success ) {
1324 modal.find('#wapk-support-message,#wapk-support-subject').val('');
1325 } else {
1326 setTimeout( function() {
1327 window.open( supportURL, '_blank' );
1328 // supportResponse.slideUp();
1329 buttonElem.hasClass('disabled') && buttonElem.removeClass('disabled');
1330 }, 5000 );
1331 }
1332 buttonElem.text(__BTN_TEXT__);
1333 });
1334 });
1335 });
1336 }(jQuery));
1337 </script>
1338 <?php
1339 }
1340
1341 /**
1342 * Run after theme deactivated
1343 *
1344 * @param string $new_name New Theme Name.
1345 * @param WP_Theme $new_theme New Theme WP_Theme Object.
1346 * @param WP_Theme $old_theme Old Theme WP_Theme Object.
1347 *
1348 * @return void
1349 */
1350 public function theme_deactivated( $new_name, $new_theme, $old_theme ) {
1351 // Make sure this is WebAppick theme.
1352 if ( $old_theme->get_template() == $this->client->getSlug() ) {
1353 $current_user = wp_get_current_user();
1354 /** @noinspection PhpUndefinedFieldInspection */
1355 $data = [
1356 'hash' => $this->client->getHash(),
1357 'reason_id' => 'none',
1358 'reason_info' => wp_json_encode(
1359 [
1360 'new_theme' => [
1361 'name' => $new_name,
1362 'version' => $new_theme->version,
1363 'parent_theme' => $new_name->parent_theme,
1364 'author' => $new_name->parent_theme,
1365 ],
1366 ]
1367 ),
1368 'site' => $this->__get_site_name(),
1369 'url' => esc_url( home_url() ),
1370 'admin_email' => get_option( 'admin_email' ),
1371 'user_email' => $current_user->user_email,
1372 'first_name' => $current_user->first_name,
1373 'last_name' => $current_user->last_name,
1374 'server' => $this->__get_server_info(),
1375 'wp' => $this->__get_wp_info(),
1376 'ip_address' => $this->__get_user_ip_address(),
1377 'version' => $this->client->getProjectVersion(),
1378 ];
1379 $this->client->send_request( $data, 'reason' );
1380 }
1381 }
1382
1383 /**
1384 * Get user IP Address
1385 * @return string
1386 */
1387 private function __get_user_ip_address() {
1388 $response = wp_safe_remote_get( 'https://icanhazip.com/' );
1389 if ( is_wp_error( $response ) ) {
1390 return '';
1391 }
1392 $ip = trim( wp_remote_retrieve_body( $response ) );
1393 if ( ! filter_var( $ip, FILTER_VALIDATE_IP ) ) {
1394 return '';
1395 }
1396
1397 return $ip;
1398 }
1399
1400 /**
1401 * Get site name
1402 * @return string
1403 */
1404 private function __get_site_name() {
1405 $site_name = get_bloginfo( 'name' );
1406 if ( empty( $site_name ) ) {
1407 $site_name = get_bloginfo( 'description' );
1408 $site_name = wp_trim_words( $site_name, 3, '' );
1409 }
1410 if ( empty( $site_name ) ) {
1411 $site_name = get_bloginfo( 'url' );
1412 }
1413
1414 return $site_name;
1415 }
1416 }
1417 // End of file Insights.php.
1418