client = $client; } } /** * Don't show the notice * * @return \self */ public function hide_notice() { $this->show_notice = false; return $this; } /** * Add extra data if needed * * @param array $data * * @return \self */ public function add_extra( $data = array() ) { $this->extra_data = $data; return $this; } /** * Set custom notice text * * @param string $text * * @return \self */ public function notice( $text ) { $this->notice = $text; return $this; } /** * Initialize insights * * @return void */ public function init() { if ( $this->client->type == 'plugin' ) { $this->init_plugin(); } else if ( $this->client->type == 'theme' ) { $this->init_theme(); } } /** * Initialize theme hooks * * @return void */ public function init_theme() { $this->init_common(); add_action( 'switch_theme', array( $this, 'deactivation_cleanup' ) ); add_action( 'switch_theme', array( $this, 'theme_deactivated' ), 12, 3 ); } /** * Initialize plugin hooks * * @return void */ public function init_plugin() { // plugin deactivate popup if ( ! $this->is_local_server() ) { add_filter( 'plugin_action_links_' . $this->client->basename, array( $this, 'plugin_action_links' ) ); add_action( 'admin_footer', array( $this, 'deactivate_scripts' ) ); } $this->init_common(); register_activation_hook( $this->client->file, array( $this, 'activate_plugin' ) ); register_deactivation_hook( $this->client->file, array( $this, 'deactivation_cleanup' ) ); } /** * Initialize common hooks * * @return void */ protected function init_common() { if ( $this->show_notice ) { // tracking notice add_action( 'admin_notices', array( $this, 'admin_notice' ) ); } add_action( 'admin_init', array( $this, 'handle_optin_optout' ) ); // uninstall reason add_action( 'wp_ajax_' . $this->client->slug . '_submit-uninstall-reason', array( $this, 'uninstall_reason_submission' ) ); // cron events add_filter( 'cron_schedules', array( $this, 'add_weekly_schedule' ) ); add_action( $this->client->slug . '_tracker_send_event', array( $this, 'send_tracking_data' ) ); // add_action( 'admin_init', array( $this, 'send_tracking_data' ) ); // test } /** * Send tracking data to AppSero server * * @param boolean $override * * @return void */ public function send_tracking_data( $override = false ) { // skip on AJAX Requests if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) { return; } if ( ! $this->tracking_allowed() && ! $override ) { return; } // Send a maximum of once per week $last_send = $this->get_last_send(); if ( $last_send && $last_send > strtotime( '-1 week' ) ) { return; } $response = $this->client->send_request( $this->get_tracking_data(), 'track' ); update_option( $this->client->slug . '_tracking_last_send', time() ); } /** * Get the tracking data points * * @return array */ protected function get_tracking_data() { $all_plugins = $this->get_all_plugins(); $users = get_users( array( 'role' => 'administrator', 'orderby' => 'ID', 'order' => 'ASC', 'number' => 1, 'paged' => 1, ) ); $admin_user = ( is_array( $users ) && ! empty( $users ) ) ? $users[0] : false; $first_name = $last_name = ''; if ( $admin_user ) { $first_name = $admin_user->first_name ? $admin_user->first_name : $admin_user->display_name; $last_name = $admin_user->last_name; } $data = array( 'version' => $this->client->project_version, 'url' => esc_url( home_url() ), 'site' => $this->get_site_name(), 'admin_email' => get_option( 'admin_email' ), 'first_name' => $first_name, 'last_name' => $last_name, 'hash' => $this->client->hash, 'server' => $this->get_server_info(), 'wp' => $this->get_wp_info(), 'users' => $this->get_user_counts(), 'active_plugins' => count( $all_plugins['active_plugins'] ), 'inactive_plugins' => count( $all_plugins['inactive_plugins'] ), 'ip_address' => $this->get_user_ip_address(), 'theme' => get_stylesheet(), 'version' => $this->client->project_version, ); // Add metadata if ( $extra = $this->get_extra_data() ) { $data['extra'] = $extra; } return apply_filters( $this->client->slug . '_tracker_data', $data ); } /** * If a child class wants to send extra data * * @return mixed */ protected function get_extra_data() { if ( is_callable( $this->extra_data ) ) { return call_user_func( $this->extra_data ); } if ( is_array( $this->extra_data ) ) { return $this->extra_data; } return array(); } /** * Explain the user which data we collect * * @return string */ protected function data_we_collect() { $data = array( 'Server environment details (php, mysql, server, WordPress versions)', 'Number of users in your site', 'Site language', 'Number of active and inactive plugins', 'Site name and url', 'Your name and email address', ); return $data; } /** * Check if the user has opted into tracking * * @return bool */ public function tracking_allowed() { $allow_tracking = get_option( $this->client->slug . '_allow_tracking', 'no' ); return $allow_tracking == 'yes'; } /** * Get the last time a tracking was sent * * @return false|string */ private function get_last_send() { return get_option( $this->client->slug . '_tracking_last_send', false ); } /** * Check if the notice has been dismissed or enabled * * @return boolean */ private function notice_dismissed() { $hide_notice = get_option( $this->client->slug . '_tracking_notice', null ); if ( 'hide' == $hide_notice ) { return true; } return false; } /** * Check if the current server is localhost * * @return boolean */ private function is_local_server() { return false; $is_local = in_array( $_SERVER['REMOTE_ADDR'], array( '127.0.0.1', '::1' ) ); return apply_filters( 'appsero_is_local', $is_local ); } /** * Schedule the event weekly * * @return void */ private function schedule_event() { $hook_name = $this->client->slug . '_tracker_send_event'; if ( ! wp_next_scheduled( $hook_name ) ) { wp_schedule_event( time(), 'weekly', $hook_name ); } } /** * Clear any scheduled hook * * @return void */ private function clear_schedule_event() { wp_clear_scheduled_hook( $this->client->slug . '_tracker_send_event' ); } /** * Display the admin notice to users that have not opted-in or out * * @return void */ public function admin_notice() { if ( $this->notice_dismissed() ) { return; } if ( $this->tracking_allowed() ) { return; } if ( ! current_user_can( 'manage_options' ) ) { return; } // don't show tracking if a local server if ( ! $this->is_local_server() ) { $optin_url = add_query_arg( $this->client->slug . '_tracker_optin', 'true' ); $optout_url = add_query_arg( $this->client->slug . '_tracker_optout', 'true' ); if ( empty( $this->notice ) ) { $notice = sprintf( $this->client->__trans( 'Want to help make %1$s even more awesome? Allow %1$s to collect non-sensitive diagnostic data and usage information.' ), $this->client->name ); } else { $notice = $this->notice; } $policy_url = 'https://' . 'appsero.com/privacy-policy/'; $notice .= ' (' . $this->client->__trans( 'what we collect' ) . ')'; $notice .= ''; echo '

'; echo $notice; echo '

'; echo ' ' . $this->client->__trans( 'Allow' ) . ''; echo ' ' . $this->client->__trans( 'No thanks' ) . ''; echo '

'; echo " "; } } /** * handle the optin/optout * * @return void */ public function handle_optin_optout() { if ( isset( $_GET[ $this->client->slug . '_tracker_optin' ] ) && $_GET[ $this->client->slug . '_tracker_optin' ] == 'true' ) { $this->optin(); wp_redirect( remove_query_arg( $this->client->slug . '_tracker_optin' ) ); exit; } if ( isset( $_GET[ $this->client->slug . '_tracker_optout' ] ) && $_GET[ $this->client->slug . '_tracker_optout' ] == 'true' ) { $this->optout(); wp_redirect( remove_query_arg( $this->client->slug . '_tracker_optout' ) ); exit; } } /** * Tracking optin * * @return void */ public function optin() { update_option( $this->client->slug . '_allow_tracking', 'yes' ); update_option( $this->client->slug . '_tracking_notice', 'hide' ); $this->clear_schedule_event(); $this->schedule_event(); $this->send_tracking_data(); } /** * Optout from tracking * * @return void */ public function optout() { update_option( $this->client->slug . '_allow_tracking', 'no' ); update_option( $this->client->slug . '_tracking_notice', 'hide' ); $this->clear_schedule_event(); } /** * Get the number of post counts * * @param string $post_type * * @return integer */ public function get_post_count( $post_type ) { global $wpdb; return (int) $wpdb->get_var( "SELECT count(ID) FROM $wpdb->posts WHERE post_type = '$post_type' and post_status = 'publish'"); } /** * Get server related info. * * @return array */ private static function get_server_info() { global $wpdb; $server_data = array(); if ( isset( $_SERVER['SERVER_SOFTWARE'] ) && ! empty( $_SERVER['SERVER_SOFTWARE'] ) ) { $server_data['software'] = $_SERVER['SERVER_SOFTWARE']; } if ( function_exists( 'phpversion' ) ) { $server_data['php_version'] = phpversion(); } $server_data['mysql_version'] = $wpdb->db_version(); $server_data['php_max_upload_size'] = size_format( wp_max_upload_size() ); $server_data['php_default_timezone'] = date_default_timezone_get(); $server_data['php_soap'] = class_exists( 'SoapClient' ) ? 'Yes' : 'No'; $server_data['php_fsockopen'] = function_exists( 'fsockopen' ) ? 'Yes' : 'No'; $server_data['php_curl'] = function_exists( 'curl_init' ) ? 'Yes' : 'No'; return $server_data; } /** * Get WordPress related data. * * @return array */ private function get_wp_info() { $wp_data = array(); $wp_data['memory_limit'] = WP_MEMORY_LIMIT; $wp_data['debug_mode'] = ( defined('WP_DEBUG') && WP_DEBUG ) ? 'Yes' : 'No'; $wp_data['locale'] = get_locale(); $wp_data['version'] = get_bloginfo( 'version' ); $wp_data['multisite'] = is_multisite() ? 'Yes' : 'No'; return $wp_data; } /** * Get the list of active and inactive plugins * * @return array */ private function get_all_plugins() { // Ensure get_plugins function is loaded if ( ! function_exists( 'get_plugins' ) ) { include ABSPATH . '/wp-admin/includes/plugin.php'; } $plugins = get_plugins(); $active_plugins_keys = get_option( 'active_plugins', array() ); $active_plugins = array(); foreach ( $plugins as $k => $v ) { // Take care of formatting the data how we want it. $formatted = array(); $formatted['name'] = strip_tags( $v['Name'] ); if ( isset( $v['Version'] ) ) { $formatted['version'] = strip_tags( $v['Version'] ); } if ( isset( $v['Author'] ) ) { $formatted['author'] = strip_tags( $v['Author'] ); } if ( isset( $v['Network'] ) ) { $formatted['network'] = strip_tags( $v['Network'] ); } if ( isset( $v['PluginURI'] ) ) { $formatted['plugin_uri'] = strip_tags( $v['PluginURI'] ); } if ( in_array( $k, $active_plugins_keys ) ) { // Remove active plugins from list so we can show active and inactive separately unset( $plugins[$k] ); $active_plugins[$k] = $formatted; } else { $plugins[$k] = $formatted; } } return array( 'active_plugins' => $active_plugins, 'inactive_plugins' => $plugins ); } /** * Get user totals based on user role. * * @return array */ public function get_user_counts() { $user_count = array(); $user_count_data = count_users(); $user_count['total'] = $user_count_data['total_users']; // Get user count based on user role foreach ( $user_count_data['avail_roles'] as $role => $count ) { $user_count[ $role ] = $count; } return $user_count; } /** * Add weekly cron schedule * * @param array $schedules * * @return array */ public function add_weekly_schedule( $schedules ) { $schedules['weekly'] = array( 'interval' => DAY_IN_SECONDS * 7, 'display' => 'Once Weekly', ); return $schedules; } /** * Plugin activation hook * * @return void */ public function activate_plugin() { $allowed = get_option( $this->client->slug . '_allow_tracking', 'no' ); // if it wasn't allowed before, do nothing if ( 'yes' !== $allowed ) { return; } // re-schedule and delete the last sent time so we could force send again $hook_name = $this->client->slug . '_tracker_send_event'; if ( ! wp_next_scheduled( $hook_name ) ) { wp_schedule_event( time(), 'weekly', $hook_name ); } delete_option( $this->client->slug . '_tracking_last_send' ); $this->send_tracking_data( true ); } /** * Clear our options upon deactivation * * @return void */ public function deactivation_cleanup() { $this->clear_schedule_event(); if ( 'theme' == $this->client->type ) { delete_option( $this->client->slug . '_tracking_last_send' ); delete_option( $this->client->slug . '_allow_tracking' ); } delete_option( $this->client->slug . '_tracking_notice' ); } /** * Hook into action links and modify the deactivate link * * @param array $links * * @return array */ public function plugin_action_links( $links ) { if ( array_key_exists( 'deactivate', $links ) ) { $links['deactivate'] = str_replace( ' 'could-not-understand', 'text' => "I couldn't understand how to make it work", 'type' => 'textarea', 'placeholder' => 'Would you like us to assist you?' ), array( 'id' => 'found-better-plugin', 'text' => 'I found a better plugin', 'type' => 'text', 'placeholder' => 'Which plugin?' ), array( 'id' => 'not-have-that-feature', 'text' => 'The plugin is great, but I need specific feature that you don\'t support', 'type' => 'textarea', 'placeholder' => 'Could you tell us more about that feature?' ), array( 'id' => 'is-not-working', 'text' => 'The plugin is not working', 'type' => 'textarea', 'placeholder' => 'Could you tell us a bit more whats not working?' ), array( 'id' => 'looking-for-other', 'text' => "It's not what I was looking for", 'type' => '', 'placeholder' => '' ), array( 'id' => 'did-not-work-as-expected', 'text' => "The plugin didn't work as expected", 'type' => 'textarea', 'placeholder' => 'What did you expect?' ), array( 'id' => 'other', 'text' => 'Other', 'type' => 'textarea', 'placeholder' => 'Could you tell us a bit more?' ), ); return $reasons; } /** * Plugin deactivation uninstall reason submission * * @return void */ public function uninstall_reason_submission() { if ( ! isset( $_POST['reason_id'] ) ) { wp_send_json_error(); } $current_user = wp_get_current_user(); $data = array( 'hash' => $this->client->hash, 'reason_id' => sanitize_text_field( $_POST['reason_id'] ), 'reason_info' => isset( $_REQUEST['reason_info'] ) ? trim( stripslashes( $_REQUEST['reason_info'] ) ) : '', 'site' => $this->get_site_name(), 'url' => esc_url( home_url() ), 'admin_email' => get_option( 'admin_email' ), 'user_email' => $current_user->user_email, 'first_name' => $current_user->first_name, 'last_name' => $current_user->last_name, 'server' => $this->get_server_info(), 'wp' => $this->get_wp_info(), 'ip_address' => $this->get_user_ip_address(), 'theme' => get_stylesheet(), 'version' => $this->client->project_version, ); // Add metadata if ( $extra = $this->get_extra_data() ) { $data['extra'] = $extra; } $this->client->send_request( $data, 'deactivate' ); wp_send_json_success(); } /** * Handle the plugin deactivation feedback * * @return void */ public function deactivate_scripts() { global $pagenow; if ( 'plugins.php' != $pagenow ) { return; } $reasons = $this->get_uninstall_reasons(); ?>

client->_etrans( 'If you have a moment, please let us know why you are deactivating:' ); ?>

We share your data with Appsero to troubleshoot problems & make product improvements. Learn more about how Appsero handles your data.

get_template() == $this->client->slug ) { $current_user = wp_get_current_user(); $data = array( 'hash' => $this->client->hash, 'reason_id' => 'none', 'reason_info' => '', 'site' => $this->get_site_name(), 'url' => esc_url( home_url() ), 'admin_email' => get_option( 'admin_email' ), 'user_email' => $current_user->user_email, 'first_name' => $current_user->first_name, 'last_name' => $current_user->last_name, 'server' => $this->get_server_info(), 'wp' => $this->get_wp_info(), 'ip_address' => $this->get_user_ip_address(), 'theme' => get_stylesheet(), 'version' => $this->client->project_version, ); $this->client->send_request( $data, 'deactivate' ); } } /** * Get user IP Address */ private function get_user_ip_address() { $response = wp_remote_get( 'https://icanhazip.com/' ); if ( is_wp_error( $response ) ) { return ''; } $ip = trim( wp_remote_retrieve_body( $response ) ); if ( ! filter_var( $ip, FILTER_VALIDATE_IP ) ) { return ''; } return $ip; } /** * Get site name */ private function get_site_name() { $site_name = get_bloginfo( 'name' ); if ( empty( $site_name ) ) { $site_name = get_bloginfo( 'description' ); $site_name = wp_trim_words( $site_name, 3, '' ); } if ( empty( $site_name ) ) { $site_name = esc_url( home_url() ); } return $site_name; } }