Automations
1 year ago
KeyCheck
1 year ago
SendingQueue
5 days ago
StatsNotifications
2 months ago
AuthorizedSendingEmailsCheck.php
3 years ago
BackfillEngagementData.php
1 year ago
Bounce.php
5 days ago
BounceTaskSubscribersCleanup.php
1 month ago
BulkConfirmationEmailResend.php
2 months ago
ExportFilesCleanup.php
2 months ago
InactiveSubscribersMaintenance.php
2 weeks ago
LogCleanup.php
10 months ago
Mixpanel.php
9 months ago
NewsletterTemplateThumbnails.php
1 year ago
ReEngagementEmailsScheduler.php
1 year ago
Scheduler.php
2 months ago
SendingQueueBodyCleanup.php
2 months ago
SendingTaskSubscribersCleanup.php
2 months ago
SimpleWorker.php
1 year ago
StatisticsExport.php
2 months ago
SubscriberLimitNotificationWorker.php
2 months ago
SubscriberLinkTokens.php
1 year ago
SubscribersCountCacheRecalculation.php
2 weeks ago
SubscribersEngagementScore.php
3 days ago
SubscribersLastEngagement.php
2 months ago
SubscribersSegmentsCountSync.php
2 weeks ago
SubscribersStatsReport.php
1 year ago
Tracks.php
9 months ago
UnconfirmedSubscribersCleanup.php
2 months ago
UnsubscribeTokens.php
1 month ago
WooCommercePastOrders.php
1 year ago
WooCommerceSync.php
3 years ago
WorkersFactory.php
2 weeks ago
index.php
3 years ago
Tracks.php
134 lines
| 1 | <?php declare(strict_types = 1); |
| 2 | |
| 3 | namespace MailPoet\Cron\Workers; |
| 4 | |
| 5 | if (!defined('ABSPATH')) exit; |
| 6 | |
| 7 | |
| 8 | use MailPoet\Analytics\Analytics; |
| 9 | use MailPoet\Entities\ScheduledTaskEntity; |
| 10 | |
| 11 | class Tracks extends SimpleWorker { |
| 12 | |
| 13 | /** @var Analytics */ |
| 14 | private $analytics; |
| 15 | |
| 16 | const TASK_TYPE = 'tracks'; |
| 17 | |
| 18 | public function __construct( |
| 19 | Analytics $analytics |
| 20 | ) { |
| 21 | parent::__construct(); |
| 22 | $this->analytics = $analytics; |
| 23 | } |
| 24 | |
| 25 | public function processTaskStrategy(ScheduledTaskEntity $task, $timer) { |
| 26 | return $this->maybeReportAnalyticsToTracks(); |
| 27 | } |
| 28 | |
| 29 | public function maybeReportAnalyticsToTracks(): bool { |
| 30 | if (!$this->analytics->shouldSendToTracks()) { |
| 31 | return true; |
| 32 | } |
| 33 | return $this->reportAnalyticsToTracks(); |
| 34 | } |
| 35 | |
| 36 | public function reportAnalyticsToTracks(): bool { |
| 37 | $publicId = $this->analytics->getPublicId(); |
| 38 | |
| 39 | if (strlen($publicId) < 1) { |
| 40 | return true; |
| 41 | } |
| 42 | |
| 43 | $data = $this->analytics->getAnalyticsData(); |
| 44 | |
| 45 | $success = $this->sendToTracksAPI($publicId, $data); |
| 46 | |
| 47 | if ($success) { |
| 48 | $this->analytics->recordTracksDataSent(); |
| 49 | } |
| 50 | |
| 51 | return $success; |
| 52 | } |
| 53 | |
| 54 | private function convertKeysToSnakeCase(array $data): array { |
| 55 | $converted = []; |
| 56 | |
| 57 | foreach ($data as $key => $value) { |
| 58 | $snakeKey = $this->normalizeKeyToSnakeCase($key); |
| 59 | $converted[$snakeKey] = $value; |
| 60 | } |
| 61 | |
| 62 | return $converted; |
| 63 | } |
| 64 | |
| 65 | private function normalizeKeyToSnakeCase(string $key): string { |
| 66 | // Step 1: Convert to lowercase |
| 67 | $key = strtolower($key); |
| 68 | |
| 69 | // Step 2: Remove quotes and apostrophes |
| 70 | $key = str_replace(['\'', '"', '`'], '', $key); |
| 71 | |
| 72 | // Step 3: Replace dashes directly with underscores |
| 73 | $key = str_replace(['-', '–', '.'], '_', $key); |
| 74 | |
| 75 | // Step 4: Replace other separators with spaces |
| 76 | $key = preg_replace('/[_:>()<>\[\]{}|\\\\\/]+/', ' ', $key); |
| 77 | |
| 78 | // Step 5: Remove redundant spaces |
| 79 | $key = preg_replace('/\s+/', ' ', trim((string)$key)); |
| 80 | |
| 81 | // Step 6: Replace spaces with underscores |
| 82 | $key = str_replace(' ', '_', (string)$key); |
| 83 | |
| 84 | return $key; |
| 85 | } |
| 86 | |
| 87 | private function sendToTracksAPI(string $publicId, array $data): bool { |
| 88 | $url = 'https://public-api.wordpress.com/rest/v1.1/tracks/record'; |
| 89 | |
| 90 | // Convert Analytics data keys to snake_case for consistency |
| 91 | $convertedData = $this->convertKeysToSnakeCase($data); |
| 92 | |
| 93 | $payload = [ |
| 94 | 'commonProps' => array_merge([ |
| 95 | 'public_id' => $publicId, |
| 96 | ], $convertedData), |
| 97 | 'events' => [[ |
| 98 | '_ut' => 'anon', |
| 99 | '_ui' => $publicId, |
| 100 | '_en' => 'mailpoet_user_profile', |
| 101 | ]], |
| 102 | ]; |
| 103 | |
| 104 | $jsonPayload = json_encode($payload); |
| 105 | if ($jsonPayload === false) { |
| 106 | return false; |
| 107 | } |
| 108 | |
| 109 | $args = [ |
| 110 | 'method' => 'POST', |
| 111 | 'headers' => [ |
| 112 | 'Content-Type' => 'application/json', |
| 113 | 'Accept' => 'application/json', |
| 114 | 'User-Agent' => 'MailPoet Plugin', |
| 115 | ], |
| 116 | 'body' => $jsonPayload, |
| 117 | 'timeout' => 30, |
| 118 | ]; |
| 119 | |
| 120 | $response = wp_remote_request($url, $args); |
| 121 | |
| 122 | if (is_wp_error($response)) { |
| 123 | return false; |
| 124 | } |
| 125 | |
| 126 | $statusCode = wp_remote_retrieve_response_code($response); |
| 127 | return $statusCode >= 200 && $statusCode < 300; |
| 128 | } |
| 129 | |
| 130 | public function getNextRunDate() { |
| 131 | return $this->analytics->getNextSendDateForTracks()->addMinutes(rand(0, 59)); |
| 132 | } |
| 133 | } |
| 134 |