PluginProbe
Search Atlas SEO – OTTO AI SEO Automation for WordPress / 2.7.2
Search Atlas SEO – OTTO AI SEO Automation for WordPress v2.7.2
2.7.1 2.7.2 2.7.0 2.6.26 2.6.25 2.6.24 2.6.23 2.6.22 2.6.21 2.6.20 2.6.19 2.6.18 2.6.17 2.6.16 2.6.15 2.6.14 2.6.13 2.6.12 2.6.11 2.6.10 2.6.9 2.6.8 2.6.7 2.6.6 2.6.5 All 141 releases
← All changes | telemetry/sentry-wordpress-integration.php +94 -37 2.6.22 → 2.7.2 View file →
@@ -3,8 +3,10 @@
3 3 if (!defined('ABSPATH')) {
4 4 exit;
5 5 }
6 6
7 +require_once __DIR__ . '/privacy.php';
8 +
7 9 /**
8 10 * WordPress-Native Sentry Integration
9 11 *
10 12 * Uses WordPress HTTP API to send data directly to Sentry
@@ -41,14 +43,14 @@
41 43 $this->host = null; // Proxy handles this
42 44 $this->scheme = 'proxy';
43 45 } else {
44 46 // Legacy DSN format for backward compatibility
45 - $parsed = parse_url($this->dsn);
46 - $this->public_key = isset($parsed['user']) ? $parsed['user'] : null;
47 - $this->secret_key = isset($parsed['pass']) ? $parsed['pass'] : null;
48 - $this->project_id = trim($parsed['path'], '/');
49 - $this->host = isset($parsed['host']) ? $parsed['host'] : null;
50 - $this->scheme = isset($parsed['scheme']) ? $parsed['scheme'] : 'https';
47 + $parsed = wp_parse_url($this->dsn);
48 + $this->public_key = is_array($parsed) && isset($parsed['user']) ? $parsed['user'] : null;
49 + $this->secret_key = is_array($parsed) && isset($parsed['pass']) ? $parsed['pass'] : null;
50 + $this->project_id = is_array($parsed) && isset($parsed['path']) ? trim($parsed['path'], '/') : null;
51 + $this->host = is_array($parsed) && isset($parsed['host']) ? $parsed['host'] : null;
52 + $this->scheme = is_array($parsed) && isset($parsed['scheme']) ? $parsed['scheme'] : 'https';
51 53 }
52 54 }
53 55
54 56 /**
@@ -95,8 +97,12 @@
95 97 * @param array $extra Additional context.
96 98 * @return bool True if a request was dispatched, false if it could not be.
97 99 */
98 100 public function captureMessageNonBlocking($message, $level = 'info', $extra = []) {
101 + if (metasync_telemetry_is_disabled()) {
102 + return false;
103 + }
104 +
99 105 # Mirrors sendToSentry()'s preconditions.
100 106 if ($this->isLocalhost()) {
101 107 return false;
102 108 }
@@ -237,8 +243,12 @@
237 243 } else {
238 244 $event_data['tags'] = ['category' => 'user-feedback'];
239 245 }
240 246
247 + // Attach white-label metadata to the issue-report event (not only the
248 + // user-feedback item) so support can identify the reporting site.
249 + $event_data = self::apply_white_label_context($event_data, $feedback);
250 +
241 251 // Send the event first with attachment
242 252 $event_result = $this->sendToSentry($event_data, 'event', $attachment);
243 253
244 254 // Extract event_id from response
@@ -263,10 +273,47 @@
263 273 $feedback_result = $this->sendToSentry($data, 'user_report');
264 274
265 275 return is_array($feedback_result) ? $feedback_result['success'] : $feedback_result;
266 276 }
267 -
277 +
268 278 /**
279 + * Attach white-label metadata to an issue-report event payload.
280 + *
281 + * Support needs to tell from the Sentry event alone whether the reporting
282 + * site is white-labeled, so the values go on the event itself (tags plus a
283 + * white_label context), not only on the associated user-feedback item.
284 + *
285 + * Static and public so the unit suite can exercise the mapping directly;
286 + * captureFeedback() runs the result through a private curl sender that has
287 + * no test seam.
288 + *
289 + * @param array $event_data Event payload built by formatMessage().
290 + * @param array $feedback Feedback data supplied by the report handler.
291 + * @return array The event payload with white-label tags and context added.
292 + */
293 + public static function apply_white_label_context(array $event_data, array $feedback)
294 + {
295 + $is_whitelabel = !empty($feedback['is_whitelabel']);
296 + $brand_name = isset($feedback['whitelabel_brand_name'])
297 + ? sanitize_text_field($feedback['whitelabel_brand_name']) : '';
298 + $support_email = isset($feedback['whitelabel_support_email'])
299 + ? sanitize_email($feedback['whitelabel_support_email']) : '';
300 + $site_url = isset($feedback['site_url']) ? esc_url_raw($feedback['site_url']) : '';
301 + $event_data['tags']['is_whitelabel'] = $is_whitelabel ? 'true' : 'false';
302 + $event_data['tags']['whitelabel_brand_name'] = $brand_name;
303 + $event_data['tags']['whitelabel_support_email'] = $support_email;
304 + $event_data['tags']['site_url'] = $site_url;
305 + $event_data['contexts']['white_label'] = array(
306 + 'is_whitelabel' => $is_whitelabel,
307 + 'whitelabel_brand_name' => $brand_name,
308 + 'whitelabel_support_email' => $support_email,
309 + 'site_url' => $site_url,
310 + );
311 +
312 + return $event_data;
313 + }
314 +
315 + /**
269 316 * Format exception data for Sentry API
270 317 */
271 318 private function formatException($exception, $extra = []) {
272 319 $trace = [];
@@ -387,9 +434,9 @@
387 434 /**
388 435 * Check if the current environment is localhost/development
389 436 */
390 437 private function isLocalhost() {
391 - $host = parse_url(home_url(), PHP_URL_HOST);
438 + $host = wp_parse_url(home_url(), PHP_URL_HOST);
392 439
393 440 // Check for common localhost patterns
394 441 $localhost_patterns = [
395 442 'localhost',
@@ -402,9 +449,9 @@
402 449 '.localhost'
403 450 ];
404 451
405 452 foreach ($localhost_patterns as $pattern) {
406 - if (strpos($host, $pattern) !== false) {
453 + if ($host !== false && $host !== null && strpos($host, $pattern) !== false) {
407 454 return true;
408 455 }
409 456 }
410 457
@@ -432,8 +479,12 @@
432 479 * @param array|null $attachment Optional attachment data
433 480 * @return bool|array Success status, or array with success and event_id
434 481 */
435 482 private function sendToSentry($data, $item_type = 'event', $attachment = null) {
483 + if (metasync_telemetry_is_disabled()) {
484 + return false;
485 + }
486 +
436 487 // Skip sending to Sentry if running on localhost/development environment
437 488 if ($this->isLocalhost()) {
438 489 return false;
439 490 }
@@ -469,32 +520,23 @@
469 520 'X-Plugin-Version' => $plugin_version,
470 521 'User-Agent' => 'WordPress MetaSync Plugin/' . $plugin_version
471 522 ];
472 523
473 - // Use cURL directly to ensure proper envelope format
474 - $ch = curl_init();
475 - curl_setopt($ch, CURLOPT_URL, $url);
476 - curl_setopt($ch, CURLOPT_POST, true);
477 - curl_setopt($ch, CURLOPT_POSTFIELDS, $envelope);
478 - curl_setopt($ch, CURLOPT_HTTPHEADER, array_map(function($key, $value) {
479 - return $key . ': ' . $value;
480 - }, array_keys($headers), $headers));
481 - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
482 - curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
483 - curl_setopt($ch, CURLOPT_TIMEOUT, 5); // 5 second timeout as requested
484 - curl_setopt($ch, CURLOPT_USERAGENT, 'WordPress MetaSync Plugin/' . $plugin_version);
485 - curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5); // 5 second connection timeout
486 -
487 - $response = curl_exec($ch);
488 - $response_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
489 - $error = curl_error($ch);
524 + $response_data = wp_remote_post($url, [
525 + 'body' => $envelope,
526 + 'headers' => $headers,
527 + 'timeout' => 5, // 5 second timeout as requested
528 + 'sslverify' => true,
529 + 'user-agent' => 'WordPress MetaSync Plugin/' . $plugin_version,
530 + ]);
531 + $error = is_wp_error($response_data) ? $response_data->get_error_message() : '';
532 + $response_code = is_wp_error($response_data) ? 0 : (int) wp_remote_retrieve_response_code($response_data);
533 + $response = is_wp_error($response_data) ? '' : wp_remote_retrieve_body($response_data);
490 534
491 - #curl_close($ch);
492 -
493 535 // Log errors in debug mode for troubleshooting
494 536 if (defined('WP_DEBUG') && WP_DEBUG && WP_DEBUG_LOG) {
495 537 if ($error) {
496 - error_log(sprintf(
538 + error_log(sprintf( // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- debug-gated, no secrets
497 539 'MetaSync Sentry Error (%s): %s | Response Code: %s | Item Type: %s',
498 540 $item_type,
499 541 $error,
500 542 $response_code,
@@ -500,13 +542,12 @@
500 542 $response_code,
501 543 $item_type
502 544 ));
503 545 } elseif ($response_code < 200 || $response_code >= 300) {
504 - error_log(sprintf(
505 - 'MetaSync Sentry HTTP Error (%s): Response Code: %s | Response: %s | Item Type: %s',
546 + error_log(sprintf( // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- debug-gated, no secrets
547 + 'MetaSync Sentry HTTP Error (%s): Response Code: %s | Item Type: %s',
506 548 $item_type,
507 549 $response_code,
508 - substr($response, 0, 200),
509 550 $item_type
510 551 ));
511 552 }
512 553 }
@@ -710,9 +751,9 @@
710 751 if ($cached_context !== false) {
711 752 // Add dynamic data that changes per request
712 753 $cached_context['memory_usage'] = memory_get_usage(true);
713 754 $cached_context['memory_peak'] = memory_get_peak_usage(true);
714 - $cached_context['request_uri'] = $_SERVER['REQUEST_URI'] ?? 'unknown';
755 + $cached_context['request_uri'] = metasync_telemetry_request_path();
715 756 return $cached_context;
716 757 }
717 758
718 759 // Collect static system context (expensive operations)
@@ -729,14 +770,14 @@
729 770 'max_execution_time' => ini_get('max_execution_time'),
730 771 'active_plugins' => count(get_option('active_plugins', [])),
731 772 'active_theme' => get_template(),
732 773 'multisite' => is_multisite(),
733 - 'mysql_version' => method_exists($wpdb, 'get_var') ? $wpdb->get_var('SELECT VERSION()') : 'unknown',
774 + 'mysql_version' => method_exists($wpdb, 'get_var') ? $wpdb->get_var('SELECT VERSION()') : 'unknown', // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- diagnostic metadata — SELECT VERSION() has no cached WordPress API
734 775 'server_software' => $_SERVER['SERVER_SOFTWARE'] ?? 'unknown',
735 776 // Dynamic data added per request
736 777 'memory_usage' => memory_get_usage(true),
737 778 'memory_peak' => memory_get_peak_usage(true),
738 - 'request_uri' => $_SERVER['REQUEST_URI'] ?? 'unknown'
779 + 'request_uri' => metasync_telemetry_request_path()
739 780 ];
740 781
741 782 // Cache static context for 1 hour
742 783 wp_cache_set($cache_key, $context, 'metasync', HOUR_IN_SECONDS);
@@ -812,10 +853,10 @@
812 853 if ($this->isLocalhost()) {
813 854 return 'development';
814 855 }
815 856
816 - $host = parse_url(home_url(), PHP_URL_HOST);
817 - if (strpos($host, 'staging') !== false || strpos($host, 'dev') !== false) {
857 + $host = wp_parse_url(home_url(), PHP_URL_HOST);
858 + if ($host !== false && $host !== null && (strpos($host, 'staging') !== false || strpos($host, 'dev') !== false)) {
818 859 return 'staging';
819 860 }
820 861
821 862 return 'production';
@@ -874,8 +915,12 @@
874 915 * Initialize Sentry with DSN configuration
875 916 */
876 917 function init_metasync_sentry_wordpress() {
877 918 global $metasync_sentry_wordpress;
919 +
920 + if (metasync_telemetry_is_disabled()) {
921 + return null;
922 + }
878 923
879 924 $dsn = '';
880 925
881 926 // Use constants defined in metasync.php for configuration
@@ -905,8 +950,11 @@
905 950 * Helper function to capture exceptions
906 951 */
907 952 function metasync_sentry_capture_exception($exception, $extra = []) {
908 953 global $metasync_sentry_wordpress;
954 + if (metasync_telemetry_is_disabled()) {
955 + return false;
956 + }
909 957 if (!$metasync_sentry_wordpress) {
910 958 $metasync_sentry_wordpress = init_metasync_sentry_wordpress();
911 959 }
912 960
@@ -920,8 +968,11 @@
920 968 * Helper function to capture messages
921 969 */
922 970 function metasync_sentry_capture_message($message, $level = 'info', $extra = [], $attachment = null) {
923 971 global $metasync_sentry_wordpress;
972 + if (metasync_telemetry_is_disabled()) {
973 + return false;
974 + }
924 975 if (!$metasync_sentry_wordpress) {
925 976 $metasync_sentry_wordpress = init_metasync_sentry_wordpress();
926 977 }
927 978
@@ -940,8 +991,11 @@
940 991 * MetaSync_Sentry_WordPress::captureMessageNonBlocking() for the trade-off.
941 992 */
942 993 function metasync_sentry_capture_message_nonblocking($message, $level = 'info', $extra = []) {
943 994 global $metasync_sentry_wordpress;
995 + if (metasync_telemetry_is_disabled()) {
996 + return false;
997 + }
944 998 if (!$metasync_sentry_wordpress) {
945 999 $metasync_sentry_wordpress = init_metasync_sentry_wordpress();
946 1000 }
947 1001
@@ -958,8 +1012,11 @@
958 1012 * @return bool Success status
959 1013 */
960 1014 function metasync_sentry_capture_feedback($feedback, $attachment = null) {
961 1015 global $metasync_sentry_wordpress;
1016 + if (metasync_telemetry_is_disabled()) {
1017 + return false;
1018 + }
962 1019 if (!$metasync_sentry_wordpress) {
963 1020 $metasync_sentry_wordpress = init_metasync_sentry_wordpress();
964 1021 }
965 1022