balmet.com

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

tracker.php (13569B)


      1 <?php
      2 namespace Elementor;
      3 
      4 use Elementor\Modules\System_Info\Module as System_Info_Module;
      5 
      6 if ( ! defined( 'ABSPATH' ) ) {
      7 	exit; // Exit if accessed directly.
      8 }
      9 
     10 /**
     11  * Elementor tracker.
     12  *
     13  * Elementor tracker handler class is responsible for sending non-sensitive plugin
     14  * data to Elementor servers for users that actively allowed data tracking.
     15  *
     16  * @since 1.0.0
     17  */
     18 class Tracker {
     19 
     20 	/**
     21 	 * API URL.
     22 	 *
     23 	 * Holds the URL of the Tracker API.
     24 	 *
     25 	 * @since 1.0.0
     26 	 * @access private
     27 	 *
     28 	 * @var string API URL.
     29 	 */
     30 	private static $_api_url = 'https://my.elementor.com/api/v1/tracker/';
     31 
     32 	private static $notice_shown = false;
     33 
     34 	/**
     35 	 * Init.
     36 	 *
     37 	 * Initialize Elementor tracker.
     38 	 *
     39 	 * @since 1.0.0
     40 	 * @access public
     41 	 * @static
     42 	 */
     43 	public static function init() {
     44 		add_action( 'elementor/tracker/send_event', [ __CLASS__, 'send_tracking_data' ] );
     45 		add_action( 'admin_init', [ __CLASS__, 'handle_tracker_actions' ] );
     46 	}
     47 
     48 	/**
     49 	 * Check for settings opt-in.
     50 	 *
     51 	 * Checks whether the site admin has opted-in for data tracking, or not.
     52 	 *
     53 	 * @since 1.0.0
     54 	 * @access public
     55 	 * @static
     56 	 *
     57 	 * @param string $new_value Allowed tracking value.
     58 	 *
     59 	 * @return string Return `yes` if tracking allowed, `no` otherwise.
     60 	 */
     61 	public static function check_for_settings_optin( $new_value ) {
     62 		$old_value = get_option( 'elementor_allow_tracking', 'no' );
     63 		if ( $old_value !== $new_value && 'yes' === $new_value ) {
     64 			self::send_tracking_data( true );
     65 		}
     66 
     67 		if ( empty( $new_value ) ) {
     68 			$new_value = 'no';
     69 		}
     70 		return $new_value;
     71 	}
     72 
     73 	/**
     74 	 * Send tracking data.
     75 	 *
     76 	 * Decide whether to send tracking data, or not.
     77 	 *
     78 	 * @since 1.0.0
     79 	 * @access public
     80 	 * @static
     81 	 *
     82 	 * @param bool $override
     83 	 */
     84 	public static function send_tracking_data( $override = false ) {
     85 		// Don't trigger this on AJAX Requests.
     86 		if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
     87 			return;
     88 		}
     89 
     90 		if ( ! self::is_allow_track() ) {
     91 			return;
     92 		}
     93 
     94 		$last_send = self::get_last_send_time();
     95 
     96 		/**
     97 		 * Tracker override send.
     98 		 *
     99 		 * Filters whether to override sending tracking data or not.
    100 		 *
    101 		 * @since 1.0.0
    102 		 *
    103 		 * @param bool $override Whether to override default setting or not.
    104 		 */
    105 		$override = apply_filters( 'elementor/tracker/send_override', $override );
    106 
    107 		if ( ! $override ) {
    108 			$last_send_interval = strtotime( '-1 week' );
    109 
    110 			/**
    111 			 * Tracker last send interval.
    112 			 *
    113 			 * Filters the interval of between two tracking requests.
    114 			 *
    115 			 * @since 1.0.0
    116 			 *
    117 			 * @param int $last_send_interval A date/time string. Default is `strtotime( '-1 week' )`.
    118 			 */
    119 			$last_send_interval = apply_filters( 'elementor/tracker/last_send_interval', $last_send_interval );
    120 
    121 			// Send a maximum of once per week by default.
    122 			if ( $last_send && $last_send > $last_send_interval ) {
    123 				return;
    124 			}
    125 		} else {
    126 			// Make sure there is at least a 1 hour delay between override sends, we dont want duplicate calls due to double clicking links.
    127 			if ( $last_send && $last_send > strtotime( '-1 hours' ) ) {
    128 				return;
    129 			}
    130 		}
    131 
    132 		// Update time first before sending to ensure it is set.
    133 		update_option( 'elementor_tracker_last_send', time() );
    134 
    135 		$params = self::get_tracking_data( empty( $last_send ) );
    136 
    137 		add_filter( 'https_ssl_verify', '__return_false' );
    138 
    139 		wp_safe_remote_post(
    140 			self::$_api_url,
    141 			[
    142 				'timeout' => 25,
    143 				'blocking' => false,
    144 				// 'sslverify' => false,
    145 				'body' => [
    146 					'data' => wp_json_encode( $params ),
    147 				],
    148 			]
    149 		);
    150 	}
    151 
    152 	/**
    153 	 * Is allow track.
    154 	 *
    155 	 * Checks whether the site admin has opted-in for data tracking, or not.
    156 	 *
    157 	 * @since 1.0.0
    158 	 * @access public
    159 	 * @static
    160 	 */
    161 	public static function is_allow_track() {
    162 		return 'yes' === get_option( 'elementor_allow_tracking', 'no' );
    163 	}
    164 
    165 	/**
    166 	 * Handle tracker actions.
    167 	 *
    168 	 * Check if the user opted-in or opted-out and update the database.
    169 	 *
    170 	 * Fired by `admin_init` action.
    171 	 *
    172 	 * @since 1.0.0
    173 	 * @access public
    174 	 * @static
    175 	 */
    176 	public static function handle_tracker_actions() {
    177 		if ( ! isset( $_GET['elementor_tracker'] ) ) {
    178 			return;
    179 		}
    180 
    181 		if ( 'opt_into' === $_GET['elementor_tracker'] ) {
    182 			check_admin_referer( 'opt_into' );
    183 
    184 			self::set_opt_in( true );
    185 		}
    186 
    187 		if ( 'opt_out' === $_GET['elementor_tracker'] ) {
    188 			check_admin_referer( 'opt_out' );
    189 
    190 			self::set_opt_in( false );
    191 		}
    192 
    193 		wp_redirect( remove_query_arg( 'elementor_tracker' ) );
    194 		exit;
    195 	}
    196 
    197 	/**
    198 	 * @since 2.2.0
    199 	 * @access public
    200 	 * @static
    201 	 */
    202 	public static function is_notice_shown() {
    203 		return self::$notice_shown;
    204 	}
    205 
    206 	public static function set_opt_in( $value ) {
    207 		if ( $value ) {
    208 			update_option( 'elementor_allow_tracking', 'yes' );
    209 			self::send_tracking_data( true );
    210 		} else {
    211 			update_option( 'elementor_allow_tracking', 'no' );
    212 			update_option( 'elementor_tracker_notice', '1' );
    213 		}
    214 	}
    215 
    216 	/**
    217 	 * Get system reports data.
    218 	 *
    219 	 * Retrieve the data from system reports.
    220 	 *
    221 	 * @since 2.0.0
    222 	 * @access private
    223 	 * @static
    224 	 *
    225 	 * @return array The data from system reports.
    226 	 */
    227 	private static function get_system_reports_data() {
    228 		$reports = Plugin::$instance->system_info->load_reports( System_Info_Module::get_allowed_reports() );
    229 
    230 		$system_reports = [];
    231 		foreach ( $reports as $report_key => $report_details ) {
    232 			$system_reports[ $report_key ] = [];
    233 			foreach ( $report_details['report'] as $sub_report_key => $sub_report_details ) {
    234 				$system_reports[ $report_key ][ $sub_report_key ] = $sub_report_details['value'];
    235 			}
    236 		}
    237 		return $system_reports;
    238 	}
    239 
    240 	/**
    241 	 * Get last send time.
    242 	 *
    243 	 * Retrieve the last time tracking data was sent.
    244 	 *
    245 	 * @since 2.0.0
    246 	 * @access private
    247 	 * @static
    248 	 *
    249 	 * @return int|false The last time tracking data was sent, or false if
    250 	 *                   tracking data never sent.
    251 	 */
    252 	private static function get_last_send_time() {
    253 		$last_send_time = get_option( 'elementor_tracker_last_send', false );
    254 
    255 		/**
    256 		 * Tracker last send time.
    257 		 *
    258 		 * Filters the last time tracking data was sent.
    259 		 *
    260 		 * @since 1.0.0
    261 		 *
    262 		 * @param int|false $last_send_time The last time tracking data was sent,
    263 		 *                                  or false if tracking data never sent.
    264 		 */
    265 		$last_send_time = apply_filters( 'elementor/tracker/last_send_time', $last_send_time );
    266 
    267 		return $last_send_time;
    268 	}
    269 
    270 	/**
    271 	 * Get non elementor post usages.
    272 	 *
    273 	 * Retrieve the number of posts that not using elementor.
    274 
    275 	 * @return array The number of posts using not used by Elementor grouped by post types
    276 	 *               and post status.
    277 	 */
    278 	public static function get_non_elementor_posts_usage() {
    279 		global $wpdb;
    280 
    281 		$usage = [];
    282 
    283 		$results = $wpdb->get_results(
    284 			"SELECT `post_type`, `post_status`, COUNT(`ID`) `hits`
    285 				FROM {$wpdb->posts} `p`
    286 				LEFT JOIN {$wpdb->postmeta} `pm` ON(`p`.`ID` = `pm`.`post_id` AND  `meta_key` = '_elementor_edit_mode' )
    287 				WHERE `post_type` != 'elementor_library' AND `meta_value` IS NULL
    288 				GROUP BY `post_type`, `post_status`;"
    289 		);
    290 
    291 		if ( $results ) {
    292 			foreach ( $results as $result ) {
    293 				$usage[ $result->post_type ][ $result->post_status ] = $result->hits;
    294 			}
    295 		}
    296 
    297 		return $usage;
    298 	}
    299 
    300 	/**
    301 	 * Get posts usage.
    302 	 *
    303 	 * Retrieve the number of posts using Elementor.
    304 	 *
    305 	 * @since 2.0.0
    306 	 * @access public
    307 	 * @static
    308 	 *
    309 	 * @return array The number of posts using Elementor grouped by post types
    310 	 *               and post status.
    311 	 */
    312 	public static function get_posts_usage() {
    313 		global $wpdb;
    314 
    315 		$usage = [];
    316 
    317 		$results = $wpdb->get_results(
    318 			"SELECT `post_type`, `post_status`, COUNT(`ID`) `hits`
    319 				FROM {$wpdb->posts} `p`
    320 				LEFT JOIN {$wpdb->postmeta} `pm` ON(`p`.`ID` = `pm`.`post_id`)
    321 				WHERE `post_type` != 'elementor_library'
    322 					AND `meta_key` = '_elementor_edit_mode' AND `meta_value` = 'builder'
    323 				GROUP BY `post_type`, `post_status`;"
    324 		);
    325 
    326 		if ( $results ) {
    327 			foreach ( $results as $result ) {
    328 				$usage[ $result->post_type ][ $result->post_status ] = $result->hits;
    329 			}
    330 		}
    331 
    332 		return $usage;
    333 	}
    334 
    335 	/**
    336 	 * Get library usage.
    337 	 *
    338 	 * Retrieve the number of Elementor library items saved.
    339 	 *
    340 	 * @since 2.0.0
    341 	 * @access public
    342 	 * @static
    343 	 *
    344 	 * @return array The number of Elementor library items grouped by post types
    345 	 *               and meta value.
    346 	 */
    347 	public static function get_library_usage() {
    348 		global $wpdb;
    349 
    350 		$usage = [];
    351 
    352 		$results = $wpdb->get_results(
    353 			"SELECT `meta_value`, COUNT(`ID`) `hits`
    354 				FROM {$wpdb->posts} `p`
    355 				LEFT JOIN {$wpdb->postmeta} `pm` ON(`p`.`ID` = `pm`.`post_id`)
    356 				WHERE `post_type` = 'elementor_library'
    357 					AND `meta_key` = '_elementor_template_type'
    358 				GROUP BY `post_type`, `meta_value`;"
    359 		);
    360 
    361 		if ( $results ) {
    362 			foreach ( $results as $result ) {
    363 				$usage[ $result->meta_value ] = $result->hits;
    364 			}
    365 		}
    366 
    367 		return $usage;
    368 
    369 	}
    370 
    371 	/**
    372 	 * Get usage of general settings.
    373 	 * 'Elementor->Settings->General'.
    374 	 *
    375 	 * @return array
    376 	 */
    377 	public static function get_settings_general_usage() {
    378 		return self::get_tracking_data_from_settings( 'general' );
    379 	}
    380 
    381 	/**
    382 	 * Get usage of advanced settings.
    383 	 * 'Elementor->Settings->Advanced'.
    384 	 *
    385 	 * @return array
    386 	 */
    387 	public static function get_settings_advanced_usage() {
    388 		return self::get_tracking_data_from_settings( 'advanced' );
    389 	}
    390 
    391 	/**
    392 	 * Get usage of experiments settings.
    393 	 *
    394 	 * 'Elementor->Settings->Experiments'.
    395 	 *
    396 	 * @return array
    397 	 */
    398 	public static function get_settings_experiments_usage() {
    399 		$result = [];
    400 
    401 		$experiments_manager = Plugin::$instance->experiments;
    402 
    403 		// TODO: Those keys should be at `$experiments_manager`.
    404 		$tracking_keys = [
    405 			'default',
    406 			'state',
    407 		];
    408 
    409 		foreach ( $experiments_manager->get_features() as $feature_name => $feature_data ) {
    410 			$data_to_collect = [];
    411 
    412 			// Extract only tracking keys.
    413 			foreach ( $tracking_keys as $tracking_key ) {
    414 				$data_to_collect[ $tracking_key ] = $feature_data[ $tracking_key ];
    415 			}
    416 
    417 			$result[ $feature_name ] = $data_to_collect;
    418 		}
    419 
    420 		return $result;
    421 	}
    422 
    423 	/**
    424 	 * Get usage of general tools.
    425 	 * 'Elementor->Tools->General'.
    426 	 *
    427 	 * @return array
    428 	 */
    429 	public static function get_tools_general_usage() {
    430 		return self::get_tracking_data_from_tools( 'general' );
    431 	}
    432 
    433 	/**
    434 	 * Get usage of 'version control' tools.
    435 	 * 'Elementor->Tools->Version Control'.
    436 	 *
    437 	 * @return array
    438 	 */
    439 	public static function get_tools_version_control_usage() {
    440 		return self::get_tracking_data_from_tools( 'versions' );
    441 	}
    442 
    443 	/**
    444 	 * Get usage of 'maintenance' tools.
    445 	 * 'Elementor->Tools->Maintenance'.
    446 	 *
    447 	 * @return array
    448 	 */
    449 	public static function get_tools_maintenance_usage() {
    450 		return self::get_tracking_data_from_tools( 'maintenance_mode' );
    451 	}
    452 
    453 	/**
    454 	 * Get the tracking data
    455 	 *
    456 	 * Retrieve tracking data and apply filter
    457 	 *
    458 	 * @access public
    459 	 * @static
    460 	 *
    461 	 * @param bool $is_first_time
    462 	 *
    463 	 * @return array
    464 	 */
    465 	public static function get_tracking_data( $is_first_time = false ) {
    466 		$params = [
    467 			'system' => self::get_system_reports_data(),
    468 			'site_lang' => get_bloginfo( 'language' ),
    469 			'email' => get_option( 'admin_email' ),
    470 			'usages' => [
    471 				'posts' => self::get_posts_usage(),
    472 				'non-elementor-posts' => self::get_non_elementor_posts_usage(),
    473 				'library' => self::get_library_usage(),
    474 				'settings' => [
    475 					'general' => self::get_settings_general_usage(),
    476 					'advanced' => self::get_settings_advanced_usage(),
    477 					'experiments' => self::get_settings_experiments_usage(),
    478 				],
    479 				'tools' => [
    480 					'general' => self::get_tools_general_usage(),
    481 					'version' => self::get_tools_version_control_usage(),
    482 					'maintenance' => self::get_tools_maintenance_usage(),
    483 				],
    484 			],
    485 			'is_first_time' => $is_first_time,
    486 			'install_time' => Plugin::instance()->get_install_time(),
    487 		];
    488 
    489 		/**
    490 		 * Tracker send tracking data params.
    491 		 *
    492 		 * Filters the data parameters when sending tracking request.
    493 		 *
    494 		 * @param array $params Variable to encode as JSON.
    495 		 *
    496 		 * @since 1.0.0
    497 		 *
    498 		 */
    499 		$params = apply_filters( 'elementor/tracker/send_tracking_data_params', $params );
    500 
    501 		return $params;
    502 	}
    503 
    504 	/**
    505 	 * @param string $tab_name
    506 	 * @return array
    507 	 */
    508 	private static function get_tracking_data_from_settings( $tab_name ) {
    509 		return self::get_tracking_data_from_settings_page(
    510 			Plugin::$instance->settings->get_tabs(),
    511 			$tab_name
    512 		);
    513 	}
    514 
    515 	/**
    516 	 * @param string $tab_name
    517 	 * @return array
    518 	 */
    519 	private static function get_tracking_data_from_tools( $tab_name ) {
    520 		return self::get_tracking_data_from_settings_page(
    521 			Plugin::$instance->tools->get_tabs(),
    522 			$tab_name
    523 		);
    524 	}
    525 
    526 	private static function get_tracking_data_from_settings_page( $tabs, $tab_name ) {
    527 		$result = [];
    528 
    529 		if ( empty( $tabs[ $tab_name ] ) ) {
    530 			return $result;
    531 		}
    532 
    533 		$tab = $tabs[ $tab_name ];
    534 
    535 		foreach ( $tab['sections'] as $section_name => $section ) {
    536 			foreach ( $section['fields'] as $field_name => $field ) {
    537 				// Skips fields with '_' prefix.
    538 				if ( '_' === $field_name[0] ) {
    539 					continue;
    540 				}
    541 
    542 				$default_value = null;
    543 				$args = $field['field_args'];
    544 				switch ( $args['type'] ) {
    545 					case 'checkbox':
    546 						$default_value = $args['value'];
    547 						break;
    548 
    549 					case 'select':
    550 					case 'checkbox_list_cpt':
    551 						$default_value = $args['std'];
    552 						break;
    553 
    554 					case 'checkbox_list_roles':
    555 						$default_value = null;
    556 						break;
    557 
    558 					// 'raw_html' is used as action and not as data.
    559 					case 'raw_html':
    560 						continue 2; // Skip fields loop.
    561 
    562 					default:
    563 						trigger_error( 'Invalid type: \'' . $args['type'] . '\'' ); // phpcs:ignore
    564 				}
    565 
    566 				$result[ $field_name ] = get_option( 'elementor_' . $field_name, $default_value );
    567 			}
    568 		}
    569 
    570 		return $result;
    571 	}
    572 }