PluginProbe
Elementor Website Builder – more than just a page builder / 3.3.1
Elementor Website Builder – more than just a page builder v3.3.1
4.3.0-beta2 4.3.0-beta1 4.2.4 4.2.3 4.2.2 4.2.1 4.2.0 4.1.5 4.2.0-beta2 4.2.0-dev2 4.2.0-beta1 4.1.4 4.1.3 4.1.2 4.1.1 4.1.0 4.1.0-beta3 4.1.0-dev3 4.0.9 4.1.0-beta2 4.1.0-dev2 4.0.8 4.1.0-beta1 4.1.0-dev1 4.0.7 All 451 releases
← All changes | includes/tracker.php +13 -288 4.1.0-dev13.3.1 View file →
@@ -1,9 +1,7 @@
1 1 <?php
2 2 namespace Elementor;
3 3
4 -use Elementor\Core\Common\Modules\EventTracker\DB as Events_DB_Manager;
5 -use Elementor\Core\Experiments\Experiments_Reporter;
6 4 use Elementor\Modules\System_Info\Module as System_Info_Module;
7 5
8 6 if ( ! defined( 'ABSPATH' ) ) {
9 7 exit; // Exit if accessed directly.
@@ -28,14 +26,12 @@
28 26 * @access private
29 27 *
30 28 * @var string API URL.
31 29 */
32 - private static $api_url = 'https://my.elementor.com/api/v1/tracker/';
30 + private static $_api_url = 'https://my.elementor.com/api/v1/tracker/';
33 31
34 32 private static $notice_shown = false;
35 33
36 - const LAST_TERMS_UPDATED = '2025-07-07';
37 -
38 34 /**
39 35 * Init.
40 36 *
41 37 * Initialize Elementor tracker.
@@ -46,10 +42,8 @@
46 42 */
47 43 public static function init() {
48 44 add_action( 'elementor/tracker/send_event', [ __CLASS__, 'send_tracking_data' ] );
49 45 add_action( 'admin_init', [ __CLASS__, 'handle_tracker_actions' ] );
50 -
51 - add_action( 'update_option_elementor_allow_tracking', [ __CLASS__, 'set_last_update_time' ] );
52 46 }
53 47
54 48 /**
55 49 * Check for settings opt-in.
@@ -66,20 +60,14 @@
66 60 */
67 61 public static function check_for_settings_optin( $new_value ) {
68 62 $old_value = get_option( 'elementor_allow_tracking', 'no' );
69 63 if ( $old_value !== $new_value && 'yes' === $new_value ) {
70 - Plugin::$instance->custom_tasks->add_tasks_requested_to_run( [
71 - 'opt_in_recalculate_usage',
72 - 'opt_in_send_tracking_data',
73 - ] );
64 + self::send_tracking_data( true );
74 65 }
75 66
76 - self::set_last_update_time();
77 -
78 67 if ( empty( $new_value ) ) {
79 68 $new_value = 'no';
80 69 }
81 -
82 70 return $new_value;
83 71 }
84 72
85 73 /**
@@ -133,10 +121,13 @@
133 121 // Send a maximum of once per week by default.
134 122 if ( $last_send && $last_send > $last_send_interval ) {
135 123 return;
136 124 }
137 - } elseif ( $last_send && $last_send > strtotime( '-1 hours' ) ) {
138 - return;
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 + }
139 130 }
140 131
141 132 // Update time first before sending to ensure it is set.
142 133 update_option( 'elementor_tracker_last_send', time() );
@@ -142,27 +133,21 @@
142 133 update_option( 'elementor_tracker_last_send', time() );
143 134
144 135 $params = self::get_tracking_data( empty( $last_send ) );
145 136
146 - // Tracking data is used for System Info reports, and events should not be included in System Info reports,
147 - // so it is added here.
148 - $params['analytics_events'] = self::get_events();
149 -
150 137 add_filter( 'https_ssl_verify', '__return_false' );
151 138
152 139 wp_safe_remote_post(
153 - self::$api_url,
140 + self::$_api_url,
154 141 [
155 142 'timeout' => 25,
156 143 'blocking' => false,
144 + // 'sslverify' => false,
157 145 'body' => [
158 146 'data' => wp_json_encode( $params ),
159 147 ],
160 148 ]
161 149 );
162 -
163 - // After sending the event tracking data, we reset the events table.
164 - Events_DB_Manager::reset_table();
165 150 }
166 151
167 152 /**
168 153 * Is allow track.
@@ -176,31 +161,8 @@
176 161 public static function is_allow_track() {
177 162 return 'yes' === get_option( 'elementor_allow_tracking', 'no' );
178 163 }
179 164
180 - public static function get_last_update_time() {
181 - return get_option( 'elementor_allow_tracking_last_update', false );
182 - }
183 -
184 - public static function set_last_update_time(): void {
185 - update_option( 'elementor_allow_tracking_last_update', gmdate( 'U' ) );
186 - }
187 -
188 - public static function has_terms_changed( $terms_updated = self::LAST_TERMS_UPDATED ): bool {
189 - if ( ! self::is_allow_track() ) {
190 - return false;
191 - }
192 -
193 - $last_update_time = self::get_last_update_time();
194 - if ( $last_update_time ) {
195 - $terms_updated_timestamp = strtotime( $terms_updated . ' UTC' );
196 -
197 - return $last_update_time < $terms_updated_timestamp;
198 - }
199 -
200 - return true;
201 - }
202 -
203 165 /**
204 166 * Handle tracker actions.
205 167 *
206 168 * Check if the user opted-in or opted-out and update the database.
@@ -227,9 +189,9 @@
227 189
228 190 self::set_opt_in( false );
229 191 }
230 192
231 - wp_safe_redirect( remove_query_arg( 'elementor_tracker' ) );
193 + wp_redirect( remove_query_arg( 'elementor_tracker' ) );
232 194 exit;
233 195 }
234 196
235 197 /**
@@ -243,10 +205,8 @@
243 205
244 206 public static function set_opt_in( $value ) {
245 207 if ( $value ) {
246 208 update_option( 'elementor_allow_tracking', 'yes' );
247 - self::set_last_update_time();
248 -
249 209 self::send_tracking_data( true );
250 210 } else {
251 211 update_option( 'elementor_allow_tracking', 'no' );
252 212 update_option( 'elementor_tracker_notice', '1' );
@@ -266,17 +226,12 @@
266 226 */
267 227 private static function get_system_reports_data() {
268 228 $reports = Plugin::$instance->system_info->load_reports( System_Info_Module::get_allowed_reports() );
269 229
270 - // The log report should not be sent with the usage data - it is not used and causes bloat.
271 - if ( isset( $reports['log'] ) ) {
272 - unset( $reports['log'] );
273 - }
274 -
275 230 $system_reports = [];
276 231 foreach ( $reports as $report_key => $report_details ) {
277 232 $system_reports[ $report_key ] = [];
278 - foreach ( $report_details['report']->get_report() as $sub_report_key => $sub_report_details ) {
233 + foreach ( $report_details['report'] as $sub_report_key => $sub_report_details ) {
279 234 $system_reports[ $report_key ][ $sub_report_key ] = $sub_report_details['value'];
280 235 }
281 236 }
282 237 return $system_reports;
@@ -324,9 +279,8 @@
324 279 global $wpdb;
325 280
326 281 $usage = [];
327 282
328 - // phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.DirectQuery
329 283 $results = $wpdb->get_results(
330 284 "SELECT `post_type`, `post_status`, COUNT(`ID`) `hits`
331 285 FROM {$wpdb->posts} `p`
332 286 LEFT JOIN {$wpdb->postmeta} `pm` ON(`p`.`ID` = `pm`.`post_id` AND `meta_key` = '_elementor_edit_mode' )
@@ -359,9 +313,8 @@
359 313 global $wpdb;
360 314
361 315 $usage = [];
362 316
363 - // phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.DirectQuery
364 317 $results = $wpdb->get_results(
365 318 "SELECT `post_type`, `post_status`, COUNT(`ID`) `hits`
366 319 FROM {$wpdb->posts} `p`
367 320 LEFT JOIN {$wpdb->postmeta} `pm` ON(`p`.`ID` = `pm`.`post_id`)
@@ -371,9 +324,9 @@
371 324 );
372 325
373 326 if ( $results ) {
374 327 foreach ( $results as $result ) {
375 - $usage[ $result->post_type ][ $result->post_status ] = (int) $result->hits;
328 + $usage[ $result->post_type ][ $result->post_status ] = $result->hits;
376 329 }
377 330 }
378 331
379 332 return $usage;
@@ -395,9 +348,8 @@
395 348 global $wpdb;
396 349
397 350 $usage = [];
398 351
399 - // phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.DirectQuery
400 352 $results = $wpdb->get_results(
401 353 "SELECT `meta_value`, COUNT(`ID`) `hits`
402 354 FROM {$wpdb->posts} `p`
403 355 LEFT JOIN {$wpdb->postmeta} `pm` ON(`p`.`ID` = `pm`.`post_id`)
@@ -412,149 +364,12 @@
412 364 }
413 365 }
414 366
415 367 return $usage;
416 - }
417 368
418 - /**
419 - * Get usage of general settings.
420 - * 'Elementor->Settings->General'.
421 - *
422 - * @return array
423 - */
424 - public static function get_settings_general_usage() {
425 - return self::get_tracking_data_from_settings( 'general' );
426 369 }
427 370
428 371 /**
429 - * Get usage of advanced settings.
430 - * 'Elementor->Settings->Advanced'.
431 - *
432 - * @return array
433 - */
434 - public static function get_settings_advanced_usage() {
435 - return self::get_tracking_data_from_settings( 'advanced' );
436 - }
437 -
438 - /**
439 - * Get usage of performance settings.
440 - * 'Elementor->Settings->Performance'.
441 - *
442 - * @return array
443 - */
444 - public static function get_settings_performance_usage() {
445 - return self::get_tracking_data_from_settings( 'performance' );
446 - }
447 -
448 - /**
449 - * Get usage of experiments settings.
450 - *
451 - * 'Elementor->Settings->Experiments'.
452 - *
453 - * @return array
454 - */
455 - public static function get_settings_experiments_usage() {
456 - $system_info = Plugin::$instance->system_info;
457 -
458 - /**
459 - * @var $experiments_report Experiments_Reporter
460 - */
461 - $experiments_report = $system_info->create_reporter( [
462 - 'class_name' => Experiments_Reporter::class,
463 - ] );
464 -
465 - return $experiments_report->get_experiments()['value'];
466 - }
467 -
468 - /**
469 - * Get usage of general tools.
470 - * 'Elementor->Tools->General'.
471 - *
472 - * @return array
473 - */
474 - public static function get_tools_general_usage() {
475 - return self::get_tracking_data_from_tools( 'general' );
476 - }
477 -
478 - /**
479 - * Get usage of 'version control' tools.
480 - * 'Elementor->Tools->Version Control'.
481 - *
482 - * @return array
483 - */
484 - public static function get_tools_version_control_usage() {
485 - return self::get_tracking_data_from_tools( 'versions' );
486 - }
487 -
488 - /**
489 - * Get usage of 'maintenance' tools.
490 - * 'Elementor->Tools->Maintenance'.
491 - *
492 - * @return array
493 - */
494 - public static function get_tools_maintenance_usage() {
495 - return self::get_tracking_data_from_tools( 'maintenance_mode' );
496 - }
497 -
498 - /**
499 - * Get library usage extend.
500 - *
501 - * Retrieve the number of Elementor library items saved.
502 - *
503 - * @return array The number of Elementor library items grouped by post types, post status
504 - * and meta value.
505 - */
506 - public static function get_library_usage_extend() {
507 - global $wpdb;
508 -
509 - $usage = [];
510 -
511 - // phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.DirectQuery
512 - $results = $wpdb->get_results(
513 - "SELECT `meta_value`, COUNT(`ID`) `hits`, `post_status`
514 - FROM {$wpdb->posts} `p`
515 - LEFT JOIN {$wpdb->postmeta} `pm` ON(`p`.`ID` = `pm`.`post_id`)
516 - WHERE `post_type` = 'elementor_library'
517 - AND `meta_key` = '_elementor_template_type'
518 - GROUP BY `post_type`, `meta_value`, `post_status`;"
519 - );
520 -
521 - if ( $results ) {
522 - foreach ( $results as $result ) {
523 - if ( empty( $usage[ $result->meta_value ] ) ) {
524 - $usage[ $result->meta_value ] = [];
525 - }
526 -
527 - if ( empty( $usage[ $result->meta_value ][ $result->post_status ] ) ) {
528 - $usage[ $result->meta_value ][ $result->post_status ] = 0;
529 - }
530 -
531 - $usage[ $result->meta_value ][ $result->post_status ] += $result->hits;
532 - }
533 - }
534 -
535 - return $usage;
536 - }
537 -
538 - public static function get_events() {
539 - global $wpdb;
540 - $table_name = $wpdb->prefix . Events_DB_Manager::TABLE_NAME;
541 -
542 - // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.DirectQuery
543 - $results = $wpdb->get_results( "SELECT event_data FROM {$table_name}" );
544 -
545 - $events_data = [];
546 -
547 - foreach ( $results as $event ) {
548 - // Results are stored in the database as a JSON string. Since all tracking data is encoded right before
549 - // being sent, it is now decoded.
550 - $events_data[] = json_decode( $event->event_data, true );
551 - }
552 -
553 - return $events_data;
554 - }
555 -
556 - /**
557 372 * Get the tracking data
558 373 *
559 374 * Retrieve tracking data and apply filter
560 375 *
@@ -573,34 +388,12 @@
573 388 'usages' => [
574 389 'posts' => self::get_posts_usage(),
575 390 'non-elementor-posts' => self::get_non_elementor_posts_usage(),
576 391 'library' => self::get_library_usage(),
577 - 'settings' => [
578 - 'general' => self::get_settings_general_usage(),
579 - 'advanced' => self::get_settings_advanced_usage(),
580 - 'experiments' => self::get_settings_experiments_usage(),
581 - ],
582 - 'tools' => [
583 - 'general' => self::get_tools_general_usage(),
584 - 'version' => self::get_tools_version_control_usage(),
585 - 'maintenance' => self::get_tools_maintenance_usage(),
586 - ],
587 - 'library-details' => self::get_library_usage_extend(),
588 392 ],
589 393 'is_first_time' => $is_first_time,
590 - 'install_time' => Plugin::instance()->get_install_time(),
591 394 ];
592 395
593 - $site_key = Api::get_site_key();
594 - if ( ! empty( $site_key ) ) {
595 - $params['site_key'] = $site_key;
596 - }
597 -
598 - $allowed_usage_time = self::get_last_update_time();
599 - if ( ! empty( $allowed_usage_time ) ) {
600 - $params['allowed_usage_time'] = $allowed_usage_time;
601 - }
602 -
603 396 /**
604 397 * Tracker send tracking data params.
605 398 *
606 399 * Filters the data parameters when sending tracking request.
@@ -607,79 +400,11 @@
607 400 *
608 401 * @param array $params Variable to encode as JSON.
609 402 *
610 403 * @since 1.0.0
404 + *
611 405 */
612 406 $params = apply_filters( 'elementor/tracker/send_tracking_data_params', $params );
613 407
614 408 return $params;
615 - }
616 -
617 - /**
618 - * @param string $tab_name
619 - * @return array
620 - */
621 - private static function get_tracking_data_from_settings( $tab_name ) {
622 - return self::get_tracking_data_from_settings_page(
623 - Plugin::$instance->settings->get_tabs(),
624 - $tab_name
625 - );
626 - }
627 -
628 - /**
629 - * @param string $tab_name
630 - * @return array
631 - */
632 - private static function get_tracking_data_from_tools( $tab_name ) {
633 - return self::get_tracking_data_from_settings_page(
634 - Plugin::$instance->tools->get_tabs(),
635 - $tab_name
636 - );
637 - }
638 -
639 - private static function get_tracking_data_from_settings_page( $tabs, $tab_name ) {
640 - $result = [];
641 -
642 - if ( empty( $tabs[ $tab_name ] ) ) {
643 - return $result;
644 - }
645 -
646 - $tab = $tabs[ $tab_name ];
647 -
648 - foreach ( $tab['sections'] as $section_name => $section ) {
649 - foreach ( $section['fields'] as $field_name => $field ) {
650 - // Skips fields with '_' prefix.
651 - if ( '_' === $field_name[0] ) {
652 - continue;
653 - }
654 -
655 - $default_value = null;
656 - $args = $field['field_args'];
657 - switch ( $args['type'] ) {
658 - case 'checkbox':
659 - $default_value = $args['value'];
660 - break;
661 -
662 - case 'select':
663 - case 'checkbox_list_cpt':
664 - $default_value = $args['std'];
665 - break;
666 -
667 - case 'checkbox_list_roles':
668 - $default_value = null;
669 - break;
670 -
671 - // 'raw_html' is used as action and not as data.
672 - case 'raw_html':
673 - continue 2; // Skip fields loop.
674 -
675 - default:
676 - trigger_error( 'Invalid type: \'' . $args['type'] . '\'' ); // phpcs:ignore
677 - }
678 -
679 - $result[ $field_name ] = get_option( 'elementor_' . $field_name, $default_value );
680 - }
681 - }
682 -
683 - return $result;
684 409 }
685 410 }