ly accept fields defined in the form $formFieldIds = array_filter(array_map(function (array $formField): ?string { if (!isset($formField['id'])) { return null; } return is_numeric($formField['id']) ? "cf_{$formField['id']}" : $formField['id']; }, $form->getBlocksByTypes(FormEntity::FORM_FIELD_TYPES))); $data = array_intersect_key($data, array_flip($formFieldIds)); // make sure we don't allow too many subscriptions with the same ip address $timeout = $this->throttling->throttle(); if ($timeout > 0) { $timeToWait = $this->throttling->secondsToTimeString($timeout); $meta['refresh_captcha'] = true; // translators: %s is the amount of time the user has to wait. $meta['error'] = sprintf(__('You need to wait %s before subscribing again.', 'mailpoet'), $timeToWait); return $meta; } /** * Fires before a subscription gets created. * To interrupt the subscription process, you can throw an MailPoet\Exception. * The error message will then be displayed to the user. * * @param array $data The subscription data. * @param array $segmentIds The segment IDs the user gets subscribed to. * @param FormEntity $form The form the user used to subscribe. */ $this->wp->doAction('mailpoet_subscription_before_subscribe', $data, $segmentIds, $form); [$subscriber, $subscriptionMeta] = $this->subscriberActions->subscribe($data, $segmentIds); if (!empty($captchaSettings['type']) && $captchaSettings['type'] === CaptchaConstants::TYPE_BUILTIN && isset($data['captcha_session_id'])) { // Captcha has been verified, invalidate the session vars $this->captchaSession->reset($data['captcha_session_id']); } // record form statistics $this->statisticsFormsRepository->record($form, $subscriber); $formSettings = $form->getSettings(); // add tags to subscriber if they are filled $this->addTagsToSubscriber($formSettings['tags'] ?? [], $subscriber); // Confirmation email failed. We want to show the error message if ($subscriptionMeta['confirmationEmailResult'] instanceof \Exception) { $meta['error'] = $subscriptionMeta['confirmationEmailResult']->getMessage(); return $meta; } if (!empty($formSettings['on_success'])) { if ($formSettings['on_success'] === 'page') { // redirect to a page on a success, pass the page url in the meta $meta['redirect_url'] = $this->wp->getPermalink($formSettings['success_page']); } else if ($formSettings['on_success'] === 'url') { $meta['redirect_url'] = $formSettings['success_url']; } } return $meta; } /** * Checks if the subscriber is subscribed to any segments in the form * * @param FormEntity $form The form entity * @param SubscriberEntity $subscriber The subscriber entity * @return bool True if the subscriber is subscribed to any of the segments in the form */ public function isSubscribedToAnyFormSegments(FormEntity $form, SubscriberEntity $subscriber): bool { $formSegments = array_merge($form->getSegmentBlocksSegmentIds(), $form->getSettingsSegmentIds()); $subscribersFound = $this->subscribersFinder->findSubscribersInSegments([$subscriber->getId()], $formSegments); if (!empty($subscribersFound)) return true; return false; } private function deobfuscateFormPayload($data): array { return $this->fieldNameObfuscator->deobfuscateFormPayload($data); } private function initCaptcha(?array $captchaSettings, FormEntity $form, array $data): array { if ( !$captchaSettings || !isset($captchaSettings['type']) || $captchaSettings['type'] !== CaptchaConstants::TYPE_BUILTIN ) { return $data; } // When serving the built-in CAPTCHA for the first time, generate a new session ID. if (!isset($data['captcha_session_id'])) { $data['captcha_session_id'] = $this->captchaSession->generateSessionId(); } $sessionId = $data['captcha_session_id']; if (!isset($data['captcha'])) { // Save form data to session $this->captchaSession->setFormData($sessionId, array_merge($data, ['form_id' => $form->getId()])); } elseif ($this->captchaSession->getFormData($sessionId)) { // Restore form data from session $data = array_merge($this->captchaSession->getFormData($sessionId), ['captcha' => $data['captcha']]); } return $data; } private function validateCaptcha($captchaSettings, $data): array { if (empty($captchaSettings['type'])) { return []; } try { if ($captchaSettings['type'] === CaptchaConstants::TYPE_BUILTIN) { $this->builtInCaptchaValidator->validate($data); } if (CaptchaConstants::isReCaptcha($captchaSettings['type'])) { $this->recaptchaValidator->validate($data); } } catch (ValidationError $error) { return $error->getMeta(); } return []; } private function getSegmentIds(FormEntity $form, array $segmentIds): array { // If form contains segment selection blocks allow only segments ids configured in those blocks $segmentBlocksSegmentIds = $form->getSegmentBlocksSegmentIds(); if (!empty($segmentBlocksSegmentIds)) { $segmentIds = array_intersect($segmentIds, $segmentBlocksSegmentIds); } else { $segmentIds = $form->getSettingsSegmentIds(); } if (empty($segmentIds)) { throw new UnexpectedValueException(__('Please select a list.', 'mailpoet')); } return $segmentIds; } private function getForm(array $data): FormEntity { $formId = (isset($data['form_id']) ? (int)$data['form_id'] : false); $form = $this->formsRepository->findOneById($formId); if (!$form) { throw new NotFoundException(__('Please specify a valid form ID.', 'mailpoet')); } return $form; } /** * @param string[] $tagNames */ private function addTagsToSubscriber(array $tagNames, SubscriberEntity $subscriber): void { foreach ($tagNames as $tagName) { $tag = $this->tagRepository->createOrUpdate(['name' => $tagName]); $subscriberTag = $subscriber->getSubscriberTag($tag); if (!$subscriberTag) { $subscriberTag = new SubscriberTagEntity($tag, $subscriber); $subscriber->getSubscriberTags()->add($subscriberTag); $this->subscriberTagRepository->persist($subscriberTag); $this->subscriberTagRepository->flush(); $this->wp->doAction('mailpoet_subscriber_tag_added', $subscriberTag); } } } }