HomepageDataController.php
213 lines
| 1 | <?php declare(strict_types = 1); |
| 2 | |
| 3 | namespace MailPoet\Homepage; |
| 4 | |
| 5 | if (!defined('ABSPATH')) exit; |
| 6 | |
| 7 | |
| 8 | use MailPoet\AutomaticEmails\WooCommerce\Events\AbandonedCart; |
| 9 | use MailPoet\Automation\Engine\Storage\AutomationStorage; |
| 10 | use MailPoet\Automation\Integrations\MailPoet\Actions\SendEmailAction; |
| 11 | use MailPoet\Automation\Integrations\MailPoet\Triggers\SomeoneSubscribesTrigger; |
| 12 | use MailPoet\Automation\Integrations\MailPoet\Triggers\UserRegistrationTrigger; |
| 13 | use MailPoet\Entities\NewsletterEntity; |
| 14 | use MailPoet\Form\FormsRepository; |
| 15 | use MailPoet\Newsletter\NewslettersRepository; |
| 16 | use MailPoet\Services\AuthorizedSenderDomainController; |
| 17 | use MailPoet\Services\Bridge; |
| 18 | use MailPoet\Settings\SettingsController; |
| 19 | use MailPoet\Subscribers\SubscribersCountsController; |
| 20 | use MailPoet\Util\License\Features\Subscribers as SubscribersFeature; |
| 21 | use MailPoet\Util\Notices\SenderDomainAuthenticationNotices; |
| 22 | use MailPoet\WooCommerce\Helper as WooCommerceHelper; |
| 23 | |
| 24 | class HomepageDataController { |
| 25 | public const UPSELL_SUBSCRIBERS_COUNT_REQUIRED = 600; |
| 26 | |
| 27 | /** @var SettingsController */ |
| 28 | private $settingsController; |
| 29 | |
| 30 | /** @var FormsRepository */ |
| 31 | private $formsRepository; |
| 32 | |
| 33 | /** @var WooCommerceHelper */ |
| 34 | private $wooCommerceHelper; |
| 35 | |
| 36 | /** @var NewslettersRepository */ |
| 37 | private $newslettersRepository; |
| 38 | |
| 39 | /** @var AutomationStorage */ |
| 40 | private $automationStorage; |
| 41 | |
| 42 | /** @var SubscribersFeature */ |
| 43 | private $subscribersFeature; |
| 44 | |
| 45 | /** @var SubscribersCountsController */ |
| 46 | private $subscribersCountsController; |
| 47 | |
| 48 | /** @var AuthorizedSenderDomainController */ |
| 49 | private $senderDomainController; |
| 50 | |
| 51 | /** @var SenderDomainAuthenticationNotices */ |
| 52 | private $senderDomainAuthenticationNotices; |
| 53 | |
| 54 | public function __construct( |
| 55 | SettingsController $settingsController, |
| 56 | FormsRepository $formsRepository, |
| 57 | NewslettersRepository $newslettersRepository, |
| 58 | AutomationStorage $automationStorage, |
| 59 | SubscribersFeature $subscribersFeature, |
| 60 | SubscribersCountsController $subscribersCountsController, |
| 61 | AuthorizedSenderDomainController $senderDomainController, |
| 62 | SenderDomainAuthenticationNotices $senderDomainAuthenticationNotices, |
| 63 | WooCommerceHelper $wooCommerceHelper |
| 64 | ) { |
| 65 | $this->settingsController = $settingsController; |
| 66 | $this->formsRepository = $formsRepository; |
| 67 | $this->newslettersRepository = $newslettersRepository; |
| 68 | $this->automationStorage = $automationStorage; |
| 69 | $this->wooCommerceHelper = $wooCommerceHelper; |
| 70 | $this->subscribersFeature = $subscribersFeature; |
| 71 | $this->subscribersCountsController = $subscribersCountsController; |
| 72 | $this->senderDomainController = $senderDomainController; |
| 73 | $this->senderDomainAuthenticationNotices = $senderDomainAuthenticationNotices; |
| 74 | } |
| 75 | |
| 76 | public function getPageData(): array { |
| 77 | $subscribersCount = $this->subscribersFeature->getSubscribersCount(); |
| 78 | $formsCount = $this->formsRepository->count(); |
| 79 | $showTaskList = !$this->settingsController->get('homepage.task_list_dismissed', false); |
| 80 | $showProductDiscovery = !$this->settingsController->get('homepage.product_discovery_dismissed', false); |
| 81 | $showUpsell = !$this->settingsController->get('homepage.upsell_dismissed', false); |
| 82 | $fullyVerifiedSenderDomains = $this->senderDomainController->getFullyVerifiedSenderDomains(true); |
| 83 | $senderDomainsCount = count($fullyVerifiedSenderDomains); |
| 84 | return [ |
| 85 | 'taskListDismissed' => !$showTaskList, |
| 86 | 'productDiscoveryDismissed' => !$showProductDiscovery, |
| 87 | 'upsellDismissed' => !$showUpsell, |
| 88 | 'taskListStatus' => $showTaskList ? $this->getTaskListStatus($subscribersCount, $formsCount, $senderDomainsCount) : null, |
| 89 | 'productDiscoveryStatus' => $showProductDiscovery ? $this->getProductDiscoveryStatus($formsCount) : null, |
| 90 | 'upsellStatus' => $showUpsell ? $this->getUpsellStatus($subscribersCount) : null, |
| 91 | 'wooCustomersCount' => $this->wooCommerceHelper->getCustomersCount(), |
| 92 | 'subscribersCount' => $subscribersCount, |
| 93 | 'formsCount' => $formsCount, |
| 94 | 'subscribersStats' => $this->getSubscribersStats(), |
| 95 | 'isNewUserForSenderDomainAuth' => $this->senderDomainController->isNewUser(), |
| 96 | 'isFreeMailUser' => $this->senderDomainAuthenticationNotices->isFreeMailUser(), |
| 97 | ]; |
| 98 | } |
| 99 | |
| 100 | /** |
| 101 | * @return array{senderSet:bool, mssConnected:bool, wooSubscribersImported:bool, subscribersAdded:bool, senderDomainAuthenticated:bool} |
| 102 | */ |
| 103 | private function getTaskListStatus(int $subscribersCount, int $formsCount, int $senderDomainsCount): array { |
| 104 | return [ |
| 105 | 'senderSet' => $this->settingsController->get('sender.address', false) && $this->settingsController->get('sender.name', false), |
| 106 | 'mssConnected' => Bridge::isMSSKeySpecified(), |
| 107 | 'wooSubscribersImported' => (bool)$this->settingsController->get('woocommerce_import_screen_displayed', false), |
| 108 | 'subscribersAdded' => $formsCount || ($subscribersCount > 10), |
| 109 | 'senderDomainAuthenticated' => $senderDomainsCount > 0, |
| 110 | ]; |
| 111 | } |
| 112 | |
| 113 | /** |
| 114 | * @return array{setUpWelcomeCampaign:bool, addSubscriptionForm:bool, sendFirstNewsletter:bool, setUpAbandonedCartEmail:bool, brandWooEmails:bool} |
| 115 | */ |
| 116 | private function getProductDiscoveryStatus(int $formsCount): array { |
| 117 | $sentStandard = $this->newslettersRepository->getCountForStatusAndTypes( |
| 118 | NewsletterEntity::STATUS_SENT, |
| 119 | [NewsletterEntity::TYPE_STANDARD] |
| 120 | ); |
| 121 | $scheduledStandard = $this->newslettersRepository->getCountForStatusAndTypes( |
| 122 | NewsletterEntity::STATUS_SCHEDULED, |
| 123 | [NewsletterEntity::TYPE_STANDARD] |
| 124 | ); |
| 125 | $activePostNotificationsAndAutomaticEmails = $this->newslettersRepository->getCountForStatusAndTypes( |
| 126 | NewsletterEntity::STATUS_ACTIVE, |
| 127 | [NewsletterEntity::TYPE_NOTIFICATION, NewsletterEntity::TYPE_AUTOMATIC] |
| 128 | ); |
| 129 | $abandonedCartEmailsCount = $this->newslettersRepository->getCountOfActiveAutomaticEmailsForEvent(AbandonedCart::SLUG); |
| 130 | $welcomeEmailsCount = $this->newslettersRepository->getCountForStatusAndTypes(NewsletterEntity::STATUS_ACTIVE, [NewsletterEntity::TYPE_WELCOME]); |
| 131 | $welcomeEmailLikeAutomationsCount = $this->automationStorage->getCountOfActiveByTriggerKeysAndAction( |
| 132 | [UserRegistrationTrigger::KEY, SomeoneSubscribesTrigger::KEY], |
| 133 | SendEmailAction::KEY |
| 134 | ); |
| 135 | return [ |
| 136 | 'setUpWelcomeCampaign' => ($welcomeEmailsCount + $welcomeEmailLikeAutomationsCount) > 0, |
| 137 | 'addSubscriptionForm' => $formsCount > 0, |
| 138 | 'sendFirstNewsletter' => ($sentStandard + $scheduledStandard + $activePostNotificationsAndAutomaticEmails) > 0, |
| 139 | 'setUpAbandonedCartEmail' => $abandonedCartEmailsCount > 0, |
| 140 | 'brandWooEmails' => (bool)$this->settingsController->get('woocommerce.use_mailpoet_editor', false), |
| 141 | ]; |
| 142 | } |
| 143 | |
| 144 | /** |
| 145 | * @return array{canDisplay:bool} |
| 146 | */ |
| 147 | private function getUpsellStatus(int $subscribersCount): array { |
| 148 | $hasValidMssKey = $this->subscribersFeature->hasValidMssKey(); |
| 149 | |
| 150 | return [ |
| 151 | 'canDisplay' => !$hasValidMssKey && $subscribersCount > self::UPSELL_SUBSCRIBERS_COUNT_REQUIRED, |
| 152 | ]; |
| 153 | } |
| 154 | |
| 155 | /** |
| 156 | * This method returns data for subscribers stats statistics section. |
| 157 | * |
| 158 | * global: |
| 159 | * - subscribed: int number of subscribers who were added in last 30 days by checking lastSubscribedAt column and ignoring current global status |
| 160 | * - unsubscribed: int number of subscribers who have a record in statistics_unsubscribes table in last 30 days |
| 161 | * - changePercent: float ($subscribedSubscribersCount - $subscribedSubscribers30DaysAgo) / $subscribedSubscribers30DaysAgo) * 100 |
| 162 | * |
| 163 | * lists: |
| 164 | * - id: int id of the list |
| 165 | * - name: string name of the list |
| 166 | * - subscribed: int number of subscribers who were added to a list in last 30 days and have both list statuse "subscribed" |
| 167 | * - unsubscribed: int number of subscribers who were removed from a list in last 30 (list status is unsubscribed and updated_at is in last 30 days) |
| 168 | * - averageEngagementScore: float engagement score of the list |
| 169 | * |
| 170 | * @return array{global:array{subscribed:int, unsubscribed:int, changePercent:float|int}, lists:array<int, array>} |
| 171 | */ |
| 172 | private function getSubscribersStats(): array { |
| 173 | $listData = []; |
| 174 | $counts = $this->subscribersCountsController->getHomepageStatistics(); |
| 175 | $listsDataSubscribed = $counts['listsDataSubscribed'] ?? []; |
| 176 | foreach ($listsDataSubscribed as $list) { |
| 177 | $listData[$list['id']] = array_intersect_key($list, array_flip(['name', 'id', 'type', 'averageEngagementScore'])); |
| 178 | $listData[$list['id']]['subscribed'] = $list['count']; |
| 179 | $listData[$list['id']]['unsubscribed'] = 0; |
| 180 | } |
| 181 | $listsDataUnsubscribed = $counts['listsDataUnsubscribed'] ?? []; |
| 182 | foreach ($listsDataUnsubscribed as $list) { |
| 183 | if (!isset($listData[$list['id']])) { |
| 184 | $listData[$list['id']] = array_intersect_key($list, array_flip(['name', 'id', 'type', 'averageEngagementScore'])); |
| 185 | $listData[$list['id']]['subscribed'] = 0; |
| 186 | } |
| 187 | $listData[$list['id']]['unsubscribed'] = $list['count']; |
| 188 | } |
| 189 | |
| 190 | $subscribedCount = intval($counts['subscribedCount'] ?? 0); |
| 191 | $unsubscribedCount = intval($counts['unsubscribedCount'] ?? 0); |
| 192 | $subscribedSubscribersCount = intval($counts['subscribedSubscribersCount'] ?? 0); |
| 193 | $subscribedSubscribers30DaysAgo = $subscribedSubscribersCount - $subscribedCount + $unsubscribedCount; |
| 194 | if ($subscribedSubscribers30DaysAgo > 0) { |
| 195 | $globalChangePercent = (($subscribedSubscribersCount - $subscribedSubscribers30DaysAgo) / $subscribedSubscribers30DaysAgo) * 100; |
| 196 | if (floor($globalChangePercent) !== (float)$globalChangePercent) { |
| 197 | $globalChangePercent = round($globalChangePercent, 1); |
| 198 | } |
| 199 | } else { |
| 200 | $globalChangePercent = $subscribedSubscribersCount * 100; |
| 201 | } |
| 202 | |
| 203 | return [ |
| 204 | 'global' => [ |
| 205 | 'subscribed' => $subscribedCount, |
| 206 | 'unsubscribed' => $unsubscribedCount, |
| 207 | 'changePercent' => $globalChangePercent, |
| 208 | ], |
| 209 | 'lists' => array_values($listData), |
| 210 | ]; |
| 211 | } |
| 212 | } |
| 213 |