/includes/class-wc-tracker.php

  1. <?php 
  2. /** 
  3. * WooCommerce Tracker 
  4. * 
  5. * The WooCommerce tracker class adds functionality to track WooCommerce usage based on if the customer opted in. 
  6. * No personal information is tracked, only general WooCommerce settings, general product, order and user counts and admin email for discount code. 
  7. * 
  8. * @class WC_Tracker 
  9. * @version 2.3.0 
  10. * @package WooCommerce/Classes 
  11. * @category Class 
  12. * @author WooThemes 
  13. */ 
  14.  
  15. if ( ! defined( 'ABSPATH' ) ) { 
  16. exit; 
  17.  
  18. class WC_Tracker { 
  19.  
  20. /** 
  21. * URL to the WooThemes Tracker API endpoint. 
  22. * @var string 
  23. */ 
  24. private static $api_url = 'https://tracking.woocommerce.com/v1/'; 
  25.  
  26. /** 
  27. * Hook into cron event. 
  28. */ 
  29. public static function init() { 
  30. add_action( 'woocommerce_tracker_send_event', array( __CLASS__, 'send_tracking_data' ) ); 
  31.  
  32. /** 
  33. * Decide whether to send tracking data or not. 
  34. * 
  35. * @param boolean $override 
  36. */ 
  37. public static function send_tracking_data( $override = false ) { 
  38. // Don't trigger this on AJAX Requests 
  39. if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) { 
  40. return; 
  41.  
  42. if ( ! apply_filters( 'woocommerce_tracker_send_override', $override ) ) { 
  43. // Send a maximum of once per week by default. 
  44. $last_send = self::get_last_send_time(); 
  45. if ( $last_send && $last_send > apply_filters( 'woocommerce_tracker_last_send_interval', strtotime( '-1 week' ) ) ) { 
  46. return; 
  47. } else { 
  48. // Make sure there is at least a 1 hour delay between override sends, we don't want duplicate calls due to double clicking links. 
  49. $last_send = self::get_last_send_time(); 
  50. if ( $last_send && $last_send > strtotime( '-1 hours' ) ) { 
  51. return; 
  52.  
  53. // Update time first before sending to ensure it is set 
  54. update_option( 'woocommerce_tracker_last_send', time() ); 
  55.  
  56. $params = self::get_tracking_data(); 
  57. wp_safe_remote_post( self::$api_url, array( 
  58. 'method' => 'POST',  
  59. 'timeout' => 45,  
  60. 'redirection' => 5,  
  61. 'httpversion' => '1.0',  
  62. 'blocking' => false,  
  63. 'headers' => array( 'user-agent' => 'WooCommerceTracker/' . md5( esc_url( home_url( '/' ) ) ) . ';' ),  
  64. 'body' => json_encode( $params ),  
  65. 'cookies' => array(),  
  66. ); 
  67.  
  68. /** 
  69. * Get the last time tracking data was sent. 
  70. * @return int|bool 
  71. */ 
  72. private static function get_last_send_time() { 
  73. return apply_filters( 'woocommerce_tracker_last_send_time', get_option( 'woocommerce_tracker_last_send', false ) ); 
  74.  
  75. /** 
  76. * Get all the tracking data. 
  77. * @return array 
  78. */ 
  79. private static function get_tracking_data() { 
  80. $data = array(); 
  81.  
  82. // General site info 
  83. $data['url'] = home_url(); 
  84. $data['email'] = apply_filters( 'woocommerce_tracker_admin_email', get_option( 'admin_email' ) ); 
  85. $data['theme'] = self::get_theme_info(); 
  86.  
  87. // WordPress Info 
  88. $data['wp'] = self::get_wordpress_info(); 
  89.  
  90. // Server Info 
  91. $data['server'] = self::get_server_info(); 
  92.  
  93. // Plugin info 
  94. $all_plugins = self::get_all_plugins(); 
  95. $data['active_plugins'] = $all_plugins['active_plugins']; 
  96. $data['inactive_plugins'] = $all_plugins['inactive_plugins']; 
  97.  
  98. // Jetpack & WooCommerce Connect 
  99. $data['jetpack_version'] = defined( 'JETPACK__VERSION' ) ? JETPACK__VERSION : 'none'; 
  100. $data['jetpack_connected'] = ( class_exists( 'Jetpack' ) && is_callable( 'Jetpack::is_active' ) && Jetpack::is_active() ) ? 'yes' : 'no'; 
  101. $data['jetpack_is_staging'] = ( class_exists( 'Jetpack' ) && is_callable( 'Jetpack::is_staging_site' ) && Jetpack::is_staging_site() ) ? 'yes' : 'no'; 
  102. $data['connect_installed'] = class_exists( 'WC_Connect_Loader' ) ? 'yes' : 'no'; 
  103. $data['connect_active'] = ( class_exists( 'WC_Connect_Loader' ) && wp_next_scheduled( 'wc_connect_fetch_service_schemas' ) ) ? 'yes' : 'no'; 
  104.  
  105. // Store count info 
  106. $data['users'] = self::get_user_counts(); 
  107. $data['products'] = self::get_product_counts(); 
  108. $data['orders'] = self::get_order_counts(); 
  109.  
  110. // Payment gateway info 
  111. $data['gateways'] = self::get_active_payment_gateways(); 
  112.  
  113. // Shipping method info 
  114. $data['shipping_methods'] = self::get_active_shipping_methods(); 
  115.  
  116. // Get all WooCommerce options info 
  117. $data['settings'] = self::get_all_woocommerce_options_values(); 
  118.  
  119. // Template overrides 
  120. $data['template_overrides'] = self::get_all_template_overrides(); 
  121.  
  122. // Template overrides 
  123. $data['admin_user_agents'] = self::get_admin_user_agents(); 
  124.  
  125. return apply_filters( 'woocommerce_tracker_data', $data ); 
  126.  
  127. /** 
  128. * Get the current theme info, theme name and version. 
  129. * @return array 
  130. */ 
  131. public static function get_theme_info() { 
  132. $theme_data = wp_get_theme(); 
  133. $theme_child_theme = is_child_theme() ? 'Yes' : 'No'; 
  134. $theme_wc_support = ( ! current_theme_supports( 'woocommerce' ) && ! in_array( $theme_data->template, wc_get_core_supported_themes() ) ) ? 'No' : 'Yes'; 
  135.  
  136. return array( 'name' => $theme_data->Name, 'version' => $theme_data->Version, 'child_theme' => $theme_child_theme, 'wc_support' => $theme_wc_support ); 
  137.  
  138. /** 
  139. * Get WordPress related data. 
  140. * @return array 
  141. */ 
  142. private static function get_wordpress_info() { 
  143. $wp_data = array(); 
  144.  
  145. $memory = wc_let_to_num( WP_MEMORY_LIMIT ); 
  146.  
  147. if ( function_exists( 'memory_get_usage' ) ) { 
  148. $system_memory = wc_let_to_num( @ini_get( 'memory_limit' ) ); 
  149. $memory = max( $memory, $system_memory ); 
  150.  
  151. $wp_data['memory_limit'] = size_format( $memory ); 
  152. $wp_data['debug_mode'] = ( defined( 'WP_DEBUG' ) && WP_DEBUG ) ? 'Yes' : 'No'; 
  153. $wp_data['locale'] = get_locale(); 
  154. $wp_data['version'] = get_bloginfo( 'version' ); 
  155. $wp_data['multisite'] = is_multisite() ? 'Yes' : 'No'; 
  156.  
  157. return $wp_data; 
  158.  
  159. /** 
  160. * Get server related info. 
  161. * @return array 
  162. */ 
  163. private static function get_server_info() { 
  164. $server_data = array(); 
  165.  
  166. if ( isset( $_SERVER['SERVER_SOFTWARE'] ) && ! empty( $_SERVER['SERVER_SOFTWARE'] ) ) { 
  167. $server_data['software'] = $_SERVER['SERVER_SOFTWARE']; 
  168.  
  169. if ( function_exists( 'phpversion' ) ) { 
  170. $server_data['php_version'] = phpversion(); 
  171.  
  172. if ( function_exists( 'ini_get' ) ) { 
  173. $server_data['php_post_max_size'] = size_format( wc_let_to_num( ini_get( 'post_max_size' ) ) ); 
  174. $server_data['php_time_limt'] = ini_get( 'max_execution_time' ); 
  175. $server_data['php_max_input_vars'] = ini_get( 'max_input_vars' ); 
  176. $server_data['php_suhosin'] = extension_loaded( 'suhosin' ) ? 'Yes' : 'No'; 
  177.  
  178. global $wpdb; 
  179. $server_data['mysql_version'] = $wpdb->db_version(); 
  180.  
  181. $server_data['php_max_upload_size'] = size_format( wp_max_upload_size() ); 
  182. $server_data['php_default_timezone'] = date_default_timezone_get(); 
  183. $server_data['php_soap'] = class_exists( 'SoapClient' ) ? 'Yes' : 'No'; 
  184. $server_data['php_fsockopen'] = function_exists( 'fsockopen' ) ? 'Yes' : 'No'; 
  185. $server_data['php_curl'] = function_exists( 'curl_init' ) ? 'Yes' : 'No'; 
  186.  
  187. return $server_data; 
  188.  
  189. /** 
  190. * Get all plugins grouped into activated or not. 
  191. * @return array 
  192. */ 
  193. private static function get_all_plugins() { 
  194. // Ensure get_plugins function is loaded 
  195. if ( ! function_exists( 'get_plugins' ) ) { 
  196. include ABSPATH . '/wp-admin/includes/plugin.php'; 
  197.  
  198. $plugins = get_plugins(); 
  199. $active_plugins_keys = get_option( 'active_plugins', array() ); 
  200. $active_plugins = array(); 
  201.  
  202. foreach ( $plugins as $k => $v ) { 
  203. // Take care of formatting the data how we want it. 
  204. $formatted = array(); 
  205. $formatted['name'] = strip_tags( $v['Name'] ); 
  206. if ( isset( $v['Version'] ) ) { 
  207. $formatted['version'] = strip_tags( $v['Version'] ); 
  208. if ( isset( $v['Author'] ) ) { 
  209. $formatted['author'] = strip_tags( $v['Author'] ); 
  210. if ( isset( $v['Network'] ) ) { 
  211. $formatted['network'] = strip_tags( $v['Network'] ); 
  212. if ( isset( $v['PluginURI'] ) ) { 
  213. $formatted['plugin_uri'] = strip_tags( $v['PluginURI'] ); 
  214. if ( in_array( $k, $active_plugins_keys ) ) { 
  215. // Remove active plugins from list so we can show active and inactive separately 
  216. unset( $plugins[ $k ] ); 
  217. $active_plugins[ $k ] = $formatted; 
  218. } else { 
  219. $plugins[ $k ] = $formatted; 
  220.  
  221. return array( 'active_plugins' => $active_plugins, 'inactive_plugins' => $plugins ); 
  222.  
  223. /** 
  224. * Get user totals based on user role. 
  225. * @return array 
  226. */ 
  227. private static function get_user_counts() { 
  228. $user_count = array(); 
  229. $user_count_data = count_users(); 
  230. $user_count['total'] = $user_count_data['total_users']; 
  231.  
  232. // Get user count based on user role 
  233. foreach ( $user_count_data['avail_roles'] as $role => $count ) { 
  234. $user_count[ $role ] = $count; 
  235.  
  236. return $user_count; 
  237.  
  238. /** 
  239. * Get product totals based on product type. 
  240. * @return array 
  241. */ 
  242. private static function get_product_counts() { 
  243. $product_count = array(); 
  244. $product_count_data = wp_count_posts( 'product' ); 
  245. $product_count['total'] = $product_count_data->publish; 
  246.  
  247. $product_statuses = get_terms( 'product_type', array( 'hide_empty' => 0 ) ); 
  248. foreach ( $product_statuses as $product_status ) { 
  249. $product_count[ $product_status->name ] = $product_status->count; 
  250.  
  251. return $product_count; 
  252.  
  253. /** 
  254. * Get order counts based on order status. 
  255. * @return array 
  256. */ 
  257. private static function get_order_counts() { 
  258. $order_count = array(); 
  259. $order_count_data = wp_count_posts( 'shop_order' ); 
  260.  
  261. foreach ( wc_get_order_statuses() as $status_slug => $status_name ) { 
  262. $order_count[ $status_slug ] = $order_count_data->{ $status_slug }; 
  263.  
  264. return $order_count; 
  265.  
  266. /** 
  267. * Get a list of all active payment gateways. 
  268. * @return array 
  269. */ 
  270. private static function get_active_payment_gateways() { 
  271. $active_gateways = array(); 
  272. $gateways = WC()->payment_gateways->payment_gateways(); 
  273. foreach ( $gateways as $id => $gateway ) { 
  274. if ( isset( $gateway->enabled ) && 'yes' === $gateway->enabled ) { 
  275. $active_gateways[ $id ] = array( 'title' => $gateway->title, 'supports' => $gateway->supports ); 
  276.  
  277. return $active_gateways; 
  278.  
  279. /** 
  280. * Get a list of all active shipping methods. 
  281. * @return array 
  282. */ 
  283. private static function get_active_shipping_methods() { 
  284. $active_methods = array(); 
  285. $shipping_methods = WC()->shipping->get_shipping_methods(); 
  286. foreach ( $shipping_methods as $id => $shipping_method ) { 
  287. if ( isset( $shipping_method->enabled ) && 'yes' === $shipping_method->enabled ) { 
  288. $active_methods[ $id ] = array( 'title' => $shipping_method->title, 'tax_status' => $shipping_method->tax_status ); 
  289.  
  290. return $active_methods; 
  291.  
  292. /** 
  293. * Get all options starting with woocommerce_ prefix. 
  294. * @return array 
  295. */ 
  296. private static function get_all_woocommerce_options_values() { 
  297. return array( 
  298. 'version' => WC()->version,  
  299. 'currency' => get_woocommerce_currency(),  
  300. 'base_location' => WC()->countries->get_base_country(),  
  301. 'selling_locations' => WC()->countries->get_allowed_countries(),  
  302. 'api_enabled' => get_option( 'woocommerce_api_enabled' ),  
  303. 'weight_unit' => get_option( 'woocommerce_weight_unit' ),  
  304. 'dimension_unit' => get_option( 'woocommerce_dimension_unit' ),  
  305. 'download_method' => get_option( 'woocommerce_file_download_method' ),  
  306. 'download_require_login' => get_option( 'woocommerce_downloads_require_login' ),  
  307. 'calc_taxes' => get_option( 'woocommerce_calc_taxes' ),  
  308. 'coupons_enabled' => get_option( 'woocommerce_enable_coupons' ),  
  309. 'guest_checkout' => get_option( 'woocommerce_enable_guest_checkout' ),  
  310. 'secure_checkout' => get_option( 'woocommerce_force_ssl_checkout' ),  
  311. 'enable_signup_and_login_from_checkout' => get_option( 'woocommerce_enable_signup_and_login_from_checkout' ),  
  312. 'enable_myaccount_registration' => get_option( 'woocommerce_enable_myaccount_registration' ),  
  313. 'registration_generate_username' => get_option( 'woocommerce_registration_generate_username' ),  
  314. 'registration_generate_password' => get_option( 'woocommerce_registration_generate_password' ),  
  315. ); 
  316.  
  317. /** 
  318. * Look for any template override and return filenames. 
  319. * @return array 
  320. */ 
  321. private static function get_all_template_overrides() { 
  322. $override_data = array(); 
  323. $template_paths = apply_filters( 'woocommerce_template_overrides_scan_paths', array( 'WooCommerce' => WC()->plugin_path() . '/templates/' ) ); 
  324. $scanned_files = array(); 
  325.  
  326. require_once( WC()->plugin_path() . '/includes/admin/class-wc-admin-status.php' ); 
  327.  
  328. foreach ( $template_paths as $plugin_name => $template_path ) { 
  329. $scanned_files[ $plugin_name ] = WC_Admin_Status::scan_template_files( $template_path ); 
  330.  
  331. foreach ( $scanned_files as $plugin_name => $files ) { 
  332. foreach ( $files as $file ) { 
  333. if ( file_exists( get_stylesheet_directory() . '/' . $file ) ) { 
  334. $theme_file = get_stylesheet_directory() . '/' . $file; 
  335. } elseif ( file_exists( get_stylesheet_directory() . '/woocommerce/' . $file ) ) { 
  336. $theme_file = get_stylesheet_directory() . '/woocommerce/' . $file; 
  337. } elseif ( file_exists( get_template_directory() . '/' . $file ) ) { 
  338. $theme_file = get_template_directory() . '/' . $file; 
  339. } elseif ( file_exists( get_template_directory() . '/woocommerce/' . $file ) ) { 
  340. $theme_file = get_template_directory() . '/woocommerce/' . $file; 
  341. } else { 
  342. $theme_file = false; 
  343.  
  344. if ( false !== $theme_file ) { 
  345. $override_data[] = basename( $theme_file ); 
  346. return $override_data; 
  347.  
  348. /** 
  349. * When an admin user logs in, there user agent is tracked in user meta and collected here. 
  350. * @return array 
  351. */ 
  352. private static function get_admin_user_agents() { 
  353. return array_filter( (array) get_option( 'woocommerce_tracker_ua', array() ) ); 
  354.  
  355. WC_Tracker::init(); 
.