urlHelper = $urlHelper; $this->fieldNameObfuscator = $fieldNameObfuscator; $this->unsubscribesTracker = $unsubscribesTracker; $this->linkTokens = $linkTokens; $this->newSubscriberNotificationMailer = $newSubscriberNotificationMailer; $this->welcomeScheduler = $welcomeScheduler; $this->segmentsRepository = $segmentsRepository; $this->subscribersRepository = $subscribersRepository; $this->subscriberSegmentRepository = $subscriberSegmentRepository; $this->customFieldsRepository = $customFieldsRepository; $this->subscriberSaveController = $subscriberSaveController; } public function onSave() { $action = (isset($_POST['action']) && is_string($_POST['action']) ? sanitize_text_field(wp_unslash($_POST['action'])) : ''); $token = (isset($_POST['token']) && is_string($_POST['token']) ? sanitize_text_field(wp_unslash($_POST['token'])) : ''); if ($action !== 'mailpoet_subscription_update' || empty($_POST['data'])) { $this->urlHelper->redirectBack(); } $sanitize = function ($value) { if (is_array($value)) { foreach ($value as $k => $v) { $value[sanitize_text_field((string)$k)] = sanitize_text_field(is_scalar($v) ? (string)$v : ''); } return $value; }; return sanitize_text_field(is_scalar($value) ? (string)$value : ''); }; // custom sanitization via $sanitize //phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized $subscriberData = array_map($sanitize, wp_unslash((array)$_POST['data'])); $subscriberData = $this->fieldNameObfuscator->deobfuscateFormPayload($subscriberData); $result = []; if (!empty($subscriberData['email'])) { $subscriber = $this->subscribersRepository->findOneBy(['email' => $subscriberData['email']]); if ($subscriber && $this->linkTokens->verifyToken($subscriber, $token)) { if ($subscriberData['email'] !== Pages::DEMO_EMAIL) { $shouldTrackUnsubscribe = ( ($subscriberData['status'] ?? '') === SubscriberEntity::STATUS_UNSUBSCRIBED && $subscriber instanceof SubscriberEntity && $subscriber->getStatus() === SubscriberEntity::STATUS_SUBSCRIBED ); $subscriber = $this->subscriberSaveController->createOrUpdate($subscriberData, $subscriber); if ($shouldTrackUnsubscribe) { $this->unsubscribesTracker->track( (int)$subscriber->getId(), StatisticsUnsubscribeEntity::SOURCE_MANAGE ); } $this->subscriberSaveController->updateCustomFields($this->filterOutEmptyMandatoryFields($subscriberData), $subscriber); $this->updateSubscriptions($subscriber, $subscriberData); } } $result = ['success' => true]; } $this->urlHelper->redirectBack($result); } private function updateSubscriptions(SubscriberEntity $subscriber, array $subscriberData): void { /** @var string[] $segmentsIds */ $segmentsIds = []; if (isset($subscriberData['segments']) && is_array($subscriberData['segments'])) { $segmentsIds = array_map('strval', array_filter($subscriberData['segments'], 'is_scalar')); } // Unsubscribe from all other segments already subscribed to // but don't change disallowed segments foreach ($subscriber->getSubscriberSegments() as $subscriberSegment) { $segment = $subscriberSegment->getSegment(); if (!$segment) { continue; } if (empty($segment->getDisplayInManageSubscriptionPage())) { continue; } if (!in_array($segment->getId(), $segmentsIds)) { $this->subscriberSegmentRepository->createOrUpdate( $subscriber, $segment, SubscriberEntity::STATUS_UNSUBSCRIBED ); } } // Store new segments for notifications $subscriberSegments = $this->subscriberSegmentRepository->findBy([ 'status' => SubscriberEntity::STATUS_SUBSCRIBED, 'subscriber' => $subscriber, ]); $currentSegmentIds = array_filter(array_map(function (SubscriberSegmentEntity $subscriberSegment): ?string { $segment = $subscriberSegment->getSegment(); return $segment ? (string)$segment->getId() : null; }, $subscriberSegments)); $newSegmentIds = array_diff($segmentsIds, $currentSegmentIds); foreach ($segmentsIds as $segmentId) { $segment = $this->segmentsRepository->findOneById($segmentId); if (!$segment) { continue; } // Allow subscribing only to allowed segments if (empty($segment->getDisplayInManageSubscriptionPage())) { continue; } $this->subscriberSegmentRepository->createOrUpdate( $subscriber, $segment, SubscriberEntity::STATUS_SUBSCRIBED ); } if ($subscriber->getStatus() === SubscriberEntity::STATUS_SUBSCRIBED && $newSegmentIds) { $newSegments = $this->segmentsRepository->findByIds($newSegmentIds); $this->newSubscriberNotificationMailer->send($subscriber, $newSegments); $this->welcomeScheduler->scheduleSubscriberWelcomeNotification( $subscriber->getId(), $newSegmentIds ); } } private function filterOutEmptyMandatoryFields(array $subscriberData): array { $mandatory = $this->getMandatory(); foreach ($mandatory as $name) { if (!isset($subscriberData[$name])) { continue; } if (is_array($subscriberData[$name]) && count(array_filter($subscriberData[$name])) === 0) { unset($subscriberData[$name]); } if (is_string($subscriberData[$name]) && strlen(trim($subscriberData[$name])) === 0) { unset($subscriberData[$name]); } } return $subscriberData; } /** * @return string[] */ private function getMandatory(): array { $mandatory = []; $requiredCustomFields = $this->customFieldsRepository->findAllActive(); foreach ($requiredCustomFields as $customField) { $params = $customField->getParams(); if ( is_array($params) && isset($params['required']) && $params['required'] ) { $mandatory[] = 'cf_' . $customField->getId(); } } return $mandatory; } }