PluginProbe
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress / 11.1.0
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress v11.1.0
11.1.1 11.1.0 11.0.5 11.0.4 11.0.3 11.0.2 11.0.1 11.0.0 10.11.1 10.11.0 10.10.2 10.10.1 10.10.0 10.9.1 trunk 10.0.0 10.0.1 10.1.0 10.1.1 10.1.2 10.1.3 10.1.4 10.2.0 10.2.1 10.2.2 All 62 releases
← All changes | back/Controllers/Stats/GlobalStats.php +74 -32 11.0.4 → 11.1.0 View file →
@@ -241,9 +241,9 @@
241 241 $startDate = $clickDate;
242 242 }
243 243 }
244 244
245 - $lastOpen = end($campaignOpens);
245 + $lastOpen = empty($campaignOpens) ? null : end($campaignOpens);
246 246 $endDate = $lastOpen->open_date ?? null;
247 247 if (!empty($campaignClicks)) {
248 248 $lastClick = end($campaignClicks);
249 249 $clickDate = $lastClick->date_click ?? null;
@@ -288,20 +288,22 @@
288 288 }
289 289
290 290 public function prepareLineChart(object &$statsCampaignSelected, array $mailIdsOfCampaign, string $newStart = '', string $newEnd = ''): void
291 291 {
292 - $campaignClass = new CampaignClass();
293 292 $statsCampaignSelected->hasStats = true;
293 + $anonymousStats = !empty($this->config->get('anonymous_stats', 0));
294 294
295 295 //We get the opening by month, day, hour
296 - $campaignOpenByMonth = $campaignClass->getOpenByMonth($mailIdsOfCampaign, $newStart, $newEnd);
297 - $campaignOpenByDay = $campaignClass->getOpenByDay($mailIdsOfCampaign, $newStart, $newEnd);
298 - $campaignOpenByHour = $campaignClass->getOpenByHour($mailIdsOfCampaign, $newStart, $newEnd);
299 -
300 - if (empty($campaignOpenByMonth) || empty($campaignOpenByDay) || empty($campaignOpenByHour)) {
301 - $statsCampaignSelected->hasStats = false;
302 -
303 - return;
296 + if ($anonymousStats) {
297 + $mailStatClass = new MailStatClass();
298 + $campaignOpenByMonth = $mailStatClass->getAnonOpensByFormat($mailIdsOfCampaign, '%Y-%m', $newStart, $newEnd);
299 + $campaignOpenByDay = $mailStatClass->getAnonOpensByFormat($mailIdsOfCampaign, '%Y-%m-%d', $newStart, $newEnd);
300 + $campaignOpenByHour = $mailStatClass->getAnonOpensByFormat($mailIdsOfCampaign, '%Y-%m-%d %H:00:00', $newStart, $newEnd);
301 + } else {
302 + $campaignClass = new CampaignClass();
303 + $campaignOpenByMonth = $campaignClass->getOpenByMonth($mailIdsOfCampaign, $newStart, $newEnd);
304 + $campaignOpenByDay = $campaignClass->getOpenByDay($mailIdsOfCampaign, $newStart, $newEnd);
305 + $campaignOpenByHour = $campaignClass->getOpenByHour($mailIdsOfCampaign, $newStart, $newEnd);
304 306 }
305 307
306 308 $urlClickClass = new UrlClickClass();
307 309 $campaignClickByMonth = $urlClickClass->getAllClickByMailMonth($mailIdsOfCampaign, $newStart, $newEnd);
@@ -307,8 +309,17 @@
307 309 $campaignClickByMonth = $urlClickClass->getAllClickByMailMonth($mailIdsOfCampaign, $newStart, $newEnd);
308 310 $campaignClickByDay = $urlClickClass->getAllClickByMailDay($mailIdsOfCampaign, $newStart, $newEnd);
309 311 $campaignClickByHour = $urlClickClass->getAllClickByMailHour($mailIdsOfCampaign, $newStart, $newEnd);
310 312
313 + // In anonymous mode a click doesn't register an open, and in any mode a link can be clicked without the open pixel firing: gating on opens alone wrongly hid the whole chart.
314 + $hasOpens = !empty($campaignOpenByMonth) && !empty($campaignOpenByDay) && !empty($campaignOpenByHour);
315 + $hasClicks = !empty($campaignClickByMonth) && !empty($campaignClickByDay) && !empty($campaignClickByHour);
316 + if (!$hasOpens && !$hasClicks) {
317 + $statsCampaignSelected->hasStats = false;
318 +
319 + return;
320 + }
321 +
311 322 $statsCampaignSelected->month = $this->getValues('day', 'P1M', $campaignOpenByMonth, $campaignClickByMonth, 'Y-m');
312 323 $statsCampaignSelected->day = $this->getValues('hour', 'P1D', $campaignOpenByDay, $campaignClickByDay, 'Y-m-d');
313 324 $statsCampaignSelected->hour = $this->getValues('min', 'PT1H', $campaignOpenByHour, $campaignClickByHour, 'Y-m-d H:i', true);
314 325
@@ -342,9 +353,14 @@
342 353
343 354 public function prepareOpenTimeChart(array &$data): void
344 355 {
345 356 $userStatClass = new UserStatClass();
346 - $statsDB = $userStatClass->getOpenTimeStats($this->selectedMailIds);
357 + if (!empty($this->config->get('anonymous_stats', 0))) {
358 + $mailStatClass = new MailStatClass();
359 + $statsDB = $mailStatClass->getAnonOpenTimeStats($this->selectedMailIds);
360 + } else {
361 + $statsDB = $userStatClass->getOpenTimeStats($this->selectedMailIds);
362 + }
347 363
348 364 if (empty($statsDB['total_open'])) {
349 365 $data['openTime'] = $userStatClass->getDefaultStat();
350 366 $data['empty_open'] = true;
@@ -529,10 +545,15 @@
529 545 }
530 546
531 547 private function prepareDevicesStats(array &$data): void
532 548 {
533 - $campaignClass = new CampaignClass();
534 - $devicesCampaign = $campaignClass->getDevicesWithCountByMailId($this->selectedMailIds);
549 + if (!empty($this->config->get('anonymous_stats', 0))) {
550 + $mailStatClass = new MailStatClass();
551 + $devicesCampaign = $mailStatClass->getAnonDevices($this->selectedMailIds);
552 + } else {
553 + $campaignClass = new CampaignClass();
554 + $devicesCampaign = $campaignClass->getDevicesWithCountByMailId($this->selectedMailIds);
555 + }
535 556
536 557 $defaultDataDevices = [
537 558 'ACYM_MOBILE' => 0,
538 559 'ACYM_DESKTOP' => 0,
@@ -565,10 +586,15 @@
565 586 }
566 587
567 588 private function prepareOpenSourcesStats(array &$data): void
568 589 {
569 - $userStatClass = new UserStatClass();
570 - $openedFromStats = $userStatClass->getOpenSourcesStats($this->selectedMailIds);
590 + if (!empty($this->config->get('anonymous_stats', 0))) {
591 + $mailStatClass = new MailStatClass();
592 + $openedFromStats = $mailStatClass->getAnonOpenSources($this->selectedMailIds);
593 + } else {
594 + $userStatClass = new UserStatClass();
595 + $openedFromStats = $userStatClass->getOpenSourcesStats($this->selectedMailIds);
596 + }
571 597
572 598 $data['openedWith'] = [];
573 599 foreach ($openedFromStats as $oneSource) {
574 600 if (empty($oneSource->number)) {
@@ -607,29 +633,45 @@
607 633 $data['mail']->sent,
608 634 $data['mail']->totalMail
609 635 );
610 636
637 + // Anonymized mode has no per-subscriber data: show total opens/clicks instead of unique counts
638 + $anonymousStats = !empty($this->config->get('anonymous_stats', 0));
639 + $data['anonymousStats'] = $anonymousStats;
640 +
641 + if ($anonymousStats) {
642 + $cumulatedTotals = $mailStatClass->getCumulatedStatsByMailIds($this->selectedMailIds);
643 + $openCount = (int)($cumulatedTotals->open ?? 0);
644 + $clickCount = (int)($cumulatedTotals->click_unique ?? 0);
645 + $openSent = (int)$data['mail']->sent;
646 + } else {
647 + $openRateCampaign = empty($this->selectedMailIds) ? $campaignClass->getOpenRateAllCampaign() : $campaignClass->getOpenRateCampaigns($this->selectedMailIds);
648 + $openCount = (int)$openRateCampaign->open_unique;
649 + $openSent = (int)$openRateCampaign->sent;
650 + $clickCount = $urlClickClass->getNumberUsersClicked($this->selectedMailIds);
651 + }
652 +
611 653 //open rate
612 - $openRateCampaign = empty($this->selectedMailIds) ? $campaignClass->getOpenRateAllCampaign() : $campaignClass->getOpenRateCampaigns($this->selectedMailIds);
613 - $data['mail']->percentageOpen = empty($openRateCampaign->sent) ? 0 : number_format(($openRateCampaign->open_unique * 100) / $openRateCampaign->sent, 2);
614 - $data['mail']->allOpen = empty($openRateCampaign->sent)
615 - ? acym_translationSprintf('ACYM_X_MAIL_OPENED_OF_X', 0, 0)
616 - : acym_translationSprintf(
617 - 'ACYM_X_MAIL_OPENED_OF_X',
618 - $openRateCampaign->open_unique,
619 - $openRateCampaign->sent
620 - );
654 + // In anonymous mode $openCount is a total number of opens (not a unique-user count), so use a wording that reflects the total number of times mails were opened
655 + $openLabelKey = $anonymousStats ? 'ACYM_X_MAIL_OPENED_TIMES_OF_X' : 'ACYM_X_MAIL_OPENED_OF_X';
656 + $data['mail']->openCount = $openCount;
657 + // In anonymous mode the count is a total (not a unique), so the rate can exceed 100%: cap it to keep a meaningful percentage
658 + $openRate = empty($openSent) ? 0 : ($openCount * 100) / $openSent;
659 + $data['mail']->percentageOpen = number_format($anonymousStats ? min($openRate, 100) : $openRate, 2);
660 + $data['mail']->allOpen = empty($openSent)
661 + ? acym_translationSprintf($openLabelKey, 0, 0)
662 + : acym_translationSprintf($openLabelKey, $openCount, $openSent);
621 663
622 664 //click rate
623 - $clickRateCampaign = $urlClickClass->getNumberUsersClicked($this->selectedMailIds);
624 - $data['mail']->percentageClick = empty($data['mail']->sent) ? 0 : number_format(($clickRateCampaign * 100) / $data['mail']->sent, 2);
665 + // In anonymous mode $clickCount is a total (aggregated with user_id = 0), not a unique-user count, so use a wording that reflects total clicks
666 + $clickLabelKey = $anonymousStats ? 'ACYM_X_CLICKS_REGISTERED_OF_X' : 'ACYM_X_MAIL_CLICKED_OF_X';
667 + $data['mail']->clickCount = $clickCount;
668 + // In anonymous mode the count is a total (not a unique), so the rate can exceed 100%: cap it to keep a meaningful percentage
669 + $clickRate = empty($data['mail']->sent) ? 0 : ($clickCount * 100) / $data['mail']->sent;
670 + $data['mail']->percentageClick = number_format($anonymousStats ? min($clickRate, 100) : $clickRate, 2);
625 671 $data['mail']->allClick = empty($data['mail']->sent)
626 - ? acym_translationSprintf('ACYM_X_MAIL_CLICKED_OF_X', 0, 0)
627 - : acym_translationSprintf(
628 - 'ACYM_X_MAIL_CLICKED_OF_X',
629 - $clickRateCampaign,
630 - $data['mail']->sent
631 - );
672 + ? acym_translationSprintf($clickLabelKey, 0, 0)
673 + : acym_translationSprintf($clickLabelKey, $clickCount, $data['mail']->sent);
632 674
633 675 //bounce rate
634 676 $bounceRateCampaign = empty($this->selectedMailIds) ? $campaignClass->getBounceRateAllCampaign() : $campaignClass->getBounceRateCampaigns($this->selectedMailIds);
635 677 $data['mail']->percentageBounce = empty($data['mail']->sent) ? 0 : number_format(($bounceRateCampaign->bounce_unique * 100) / $data['mail']->sent, 2);