| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352 |
- <?php
- namespace MailPoet\API\MP\v1;
- if (!defined('ABSPATH')) exit;
- use MailPoet\Models\Segment;
- use MailPoet\Models\Subscriber;
- use MailPoet\Models\SubscriberSegment;
- use MailPoet\Newsletter\Scheduler\WelcomeScheduler;
- use MailPoet\Settings\SettingsController;
- use MailPoet\Subscribers\ConfirmationEmailMailer;
- use MailPoet\Subscribers\NewSubscriberNotificationMailer;
- use MailPoet\Subscribers\RequiredCustomFieldValidator;
- use MailPoet\Subscribers\Source;
- use MailPoet\Tasks\Sending;
- use MailPoet\Util\Helpers;
- use MailPoet\WP\Functions as WPFunctions;
- class API {
- /** @var NewSubscriberNotificationMailer */
- private $newSubscriberNotificationMailer;
- /** @var ConfirmationEmailMailer */
- private $confirmationEmailMailer;
- /** @var RequiredCustomFieldValidator */
- private $requiredCustomFieldValidator;
- /** @var WelcomeScheduler */
- private $welcomeScheduler;
- /** @var SettingsController */
- private $settings;
- /** @var CustomFields */
- private $customFields;
- public function __construct(
- NewSubscriberNotificationMailer $newSubscriberNotificationMailer,
- ConfirmationEmailMailer $confirmationEmailMailer,
- RequiredCustomFieldValidator $requiredCustomFieldValidator,
- WelcomeScheduler $welcomeScheduler,
- CustomFields $customFields,
- SettingsController $settings
- ) {
- $this->newSubscriberNotificationMailer = $newSubscriberNotificationMailer;
- $this->confirmationEmailMailer = $confirmationEmailMailer;
- $this->requiredCustomFieldValidator = $requiredCustomFieldValidator;
- $this->welcomeScheduler = $welcomeScheduler;
- $this->settings = $settings;
- $this->customFields = $customFields;
- }
- public function getSubscriberFields() {
- return $this->customFields->getSubscriberFields();
- }
- public function addSubscriberField(array $data = []) {
- try {
- return $this->customFields->addSubscriberField($data);
- } catch (\InvalidArgumentException $e) {
- throw new APIException($e->getMessage(), $e->getCode(), $e);
- }
- }
- public function subscribeToList($subscriberId, $listId, $options = []) {
- return $this->subscribeToLists($subscriberId, [$listId], $options);
- }
- public function subscribeToLists($subscriberId, array $listIds, $options = []) {
- $scheduleWelcomeEmail = (isset($options['schedule_welcome_email']) && $options['schedule_welcome_email'] === false) ? false : true;
- $sendConfirmationEmail = (isset($options['send_confirmation_email']) && $options['send_confirmation_email'] === false) ? false : true;
- $skipSubscriberNotification = (isset($options['skip_subscriber_notification']) && $options['skip_subscriber_notification'] === true) ? true : false;
- $signupConfirmationEnabled = (bool)$this->settings->get('signup_confirmation.enabled');
- if (empty($listIds)) {
- throw new APIException(__('At least one segment ID is required.', 'mailpoet'), APIException::SEGMENT_REQUIRED);
- }
- // throw exception when subscriber does not exist
- $subscriber = Subscriber::findOne($subscriberId);
- if (!$subscriber) {
- throw new APIException(__('This subscriber does not exist.', 'mailpoet'), APIException::SUBSCRIBER_NOT_EXISTS);
- }
- // throw exception when none of the segments exist
- $foundSegments = Segment::whereIn('id', $listIds)->findMany();
- if (!$foundSegments) {
- $exception = WPFunctions::get()->_n('This list does not exist.', 'These lists do not exist.', count($listIds), 'mailpoet');
- throw new APIException($exception, APIException::LIST_NOT_EXISTS);
- }
- // throw exception when trying to subscribe to WP Users or WooCommerce Customers segments
- $foundSegmentsIds = [];
- foreach ($foundSegments as $foundSegment) {
- if ($foundSegment->type === Segment::TYPE_WP_USERS) {
- throw new APIException(__(sprintf("Can't subscribe to a WordPress Users list with ID %d.", $foundSegment->id), 'mailpoet'), APIException::SUBSCRIBING_TO_WP_LIST_NOT_ALLOWED);
- }
- if ($foundSegment->type === Segment::TYPE_WC_USERS) {
- throw new APIException(__(sprintf("Can't subscribe to a WooCommerce Customers list with ID %d.", $foundSegment->id), 'mailpoet'), APIException::SUBSCRIBING_TO_WC_LIST_NOT_ALLOWED);
- }
- if ($foundSegment->type !== Segment::TYPE_DEFAULT) {
- throw new APIException(__(sprintf("Can't subscribe to a list with ID %d.", $foundSegment->id), 'mailpoet'), APIException::SUBSCRIBING_TO_LIST_NOT_ALLOWED);
- }
- $foundSegmentsIds[] = $foundSegment->id;
- }
- // throw an exception when one or more segments do not exist
- if (count($foundSegmentsIds) !== count($listIds)) {
- $missingIds = array_values(array_diff($listIds, $foundSegmentsIds));
- $exception = sprintf(
- WPFunctions::get()->_n('List with ID %s does not exist.', 'Lists with IDs %s do not exist.', count($missingIds), 'mailpoet'),
- implode(', ', $missingIds)
- );
- throw new APIException(sprintf($exception, implode(', ', $missingIds)), APIException::LIST_NOT_EXISTS);
- }
- SubscriberSegment::subscribeToSegments($subscriber, $foundSegmentsIds);
- // set status depending on signup confirmation setting
- if ($subscriber->status !== Subscriber::STATUS_SUBSCRIBED) {
- if ($signupConfirmationEnabled === true) {
- $subscriber->set('status', Subscriber::STATUS_UNCONFIRMED);
- } else {
- $subscriber->set('status', Subscriber::STATUS_SUBSCRIBED);
- }
- $subscriber->save();
- if ($subscriber->getErrors() !== false) {
- throw new APIException(
- __(sprintf('Failed to save a status of a subscriber : %s', strtolower(implode(', ', $subscriber->getErrors()))), 'mailpoet'),
- APIException::FAILED_TO_SAVE_SUBSCRIBER
- );
- }
- }
- // schedule welcome email
- if ($scheduleWelcomeEmail && $subscriber->status === Subscriber::STATUS_SUBSCRIBED) {
- $this->_scheduleWelcomeNotification($subscriber, $foundSegmentsIds);
- }
- // send confirmation email
- if ($sendConfirmationEmail) {
- $result = $this->_sendConfirmationEmail($subscriber);
- if (!$result && $subscriber->getErrors()) {
- throw new APIException(
- __(sprintf('Subscriber added to lists, but confirmation email failed to send: %s', strtolower(implode(', ', $subscriber->getErrors()))), 'mailpoet'),
- APIException::CONFIRMATION_FAILED_TO_SEND);
- }
- }
- if (!$skipSubscriberNotification && ($subscriber->status === Subscriber::STATUS_SUBSCRIBED)) {
- $this->sendSubscriberNotification($subscriber, $foundSegmentsIds);
- }
- return $subscriber->withCustomFields()->withSubscriptions()->asArray();
- }
- public function unsubscribeFromList($subscriberId, $listId) {
- return $this->unsubscribeFromLists($subscriberId, [$listId]);
- }
- public function unsubscribeFromLists($subscriberId, array $listIds) {
- if (empty($listIds)) {
- throw new APIException(__('At least one segment ID is required.', 'mailpoet'), APIException::SEGMENT_REQUIRED);
- }
- // throw exception when subscriber does not exist
- $subscriber = Subscriber::findOne($subscriberId);
- if (!$subscriber) {
- throw new APIException(__('This subscriber does not exist.', 'mailpoet'), APIException::SUBSCRIBER_NOT_EXISTS);
- }
- // throw exception when none of the segments exist
- $foundSegments = Segment::whereIn('id', $listIds)->findMany();
- if (!$foundSegments) {
- $exception = WPFunctions::get()->_n('This list does not exist.', 'These lists do not exist.', count($listIds), 'mailpoet');
- throw new APIException($exception, APIException::LIST_NOT_EXISTS);
- }
- // throw exception when trying to subscribe to WP Users or WooCommerce Customers segments
- $foundSegmentsIds = [];
- foreach ($foundSegments as $segment) {
- if ($segment->type === Segment::TYPE_WP_USERS) {
- throw new APIException(__(sprintf("Can't unsubscribe from a WordPress Users list with ID %d.", $segment->id), 'mailpoet'), APIException::SUBSCRIBING_TO_WP_LIST_NOT_ALLOWED);
- }
- if ($segment->type === Segment::TYPE_WC_USERS) {
- throw new APIException(__(sprintf("Can't unsubscribe from a WooCommerce Customers list with ID %d.", $segment->id), 'mailpoet'), APIException::SUBSCRIBING_TO_WC_LIST_NOT_ALLOWED);
- }
- $foundSegmentsIds[] = $segment->id;
- }
- // throw an exception when one or more segments do not exist
- if (count($foundSegmentsIds) !== count($listIds)) {
- $missingIds = array_values(array_diff($listIds, $foundSegmentsIds));
- $exception = sprintf(
- WPFunctions::get()->_n('List with ID %s does not exist.', 'Lists with IDs %s do not exist.', count($missingIds), 'mailpoet'),
- implode(', ', $missingIds)
- );
- throw new APIException($exception, APIException::LIST_NOT_EXISTS);
- }
- SubscriberSegment::unsubscribeFromSegments($subscriber, $foundSegmentsIds);
- return $subscriber->withCustomFields()->withSubscriptions()->asArray();
- }
- public function getLists() {
- return Segment::where('type', Segment::TYPE_DEFAULT)
- ->findArray();
- }
- public function addSubscriber(array $subscriber, $listIds = [], $options = []) {
- $sendConfirmationEmail = (isset($options['send_confirmation_email']) && $options['send_confirmation_email'] === false) ? false : true;
- $scheduleWelcomeEmail = (isset($options['schedule_welcome_email']) && $options['schedule_welcome_email'] === false) ? false : true;
- $skipSubscriberNotification = (isset($options['skip_subscriber_notification']) && $options['skip_subscriber_notification'] === true) ? true : false;
- // throw exception when subscriber email is missing
- if (empty($subscriber['email'])) {
- throw new APIException(
- __('Subscriber email address is required.', 'mailpoet'),
- APIException::EMAIL_ADDRESS_REQUIRED
- );
- }
- // throw exception when subscriber already exists
- if (Subscriber::findOne($subscriber['email'])) {
- throw new APIException(
- __('This subscriber already exists.', 'mailpoet'),
- APIException::SUBSCRIBER_EXISTS
- );
- }
- if (empty($subscriber['subscribed_ip'])) {
- $subscriber['subscribed_ip'] = Helpers::getIP();
- }
- // separate data into default and custom fields
- [$defaultFields, $customFields] = Subscriber::extractCustomFieldsFromFromObject($subscriber);
- // filter out all incoming data that we don't want to change, like status ...
- $defaultFields = array_intersect_key($defaultFields, array_flip(['email', 'first_name', 'last_name', 'subscribed_ip']));
- // if some required default fields are missing, set their values
- $defaultFields = Subscriber::setRequiredFieldsDefaultValues($defaultFields);
- $this->requiredCustomFieldValidator->validate($customFields);
- // add subscriber
- $newSubscriber = Subscriber::create();
- $newSubscriber->hydrate($defaultFields);
- $newSubscriber = Source::setSource($newSubscriber, Source::API);
- $newSubscriber->save();
- if ($newSubscriber->getErrors() !== false) {
- throw new APIException(
- __(sprintf('Failed to add subscriber: %s', strtolower(implode(', ', $newSubscriber->getErrors()))), 'mailpoet'),
- APIException::FAILED_TO_SAVE_SUBSCRIBER
- );
- }
- if (!empty($customFields)) {
- $newSubscriber->saveCustomFields($customFields);
- }
- // reload subscriber to get the saved status/created|updated|delete dates/other fields
- $newSubscriber = Subscriber::findOne($newSubscriber->id);
- // subscribe to segments and optionally: 1) send confirmation email, 2) schedule welcome email(s)
- if (!empty($listIds)) {
- $this->subscribeToLists($newSubscriber->id, $listIds, [
- 'send_confirmation_email' => $sendConfirmationEmail,
- 'schedule_welcome_email' => $scheduleWelcomeEmail,
- 'skip_subscriber_notification' => $skipSubscriberNotification,
- ]);
- }
- return $newSubscriber->withCustomFields()->withSubscriptions()->asArray();
- }
- public function addList(array $list) {
- // throw exception when list name is missing
- if (empty($list['name'])) {
- throw new APIException(
- __('List name is required.', 'mailpoet'),
- APIException::LIST_NAME_REQUIRED
- );
- }
- // throw exception when list already exists
- if (Segment::where('name', $list['name'])->findOne()) {
- throw new APIException(
- __('This list already exists.', 'mailpoet'),
- APIException::LIST_EXISTS
- );
- }
- // filter out all incoming data that we don't want to change, like type,
- $list = array_intersect_key($list, array_flip(['name', 'description']));
- // add list
- $newList = Segment::create();
- $newList->hydrate($list);
- $newList->save();
- if ($newList->getErrors() !== false) {
- throw new APIException(
- __(sprintf('Failed to add list: %s', strtolower(implode(', ', $newList->getErrors()))), 'mailpoet'),
- APIException::FAILED_TO_SAVE_LIST
- );
- }
- // reload list to get the saved created|updated|delete dates/other fields
- $newList = Segment::findOne($newList->id);
- if (!$newList instanceof Segment) {
- throw new APIException(__('Failed to add list', 'mailpoet'), APIException::FAILED_TO_SAVE_LIST);
- }
- return $newList->asArray();
- }
- public function getSubscriber($subscriberEmail) {
- $subscriber = Subscriber::findOne($subscriberEmail);
- // throw exception when subscriber does not exist
- if (!$subscriber) {
- throw new APIException(__('This subscriber does not exist.', 'mailpoet'), APIException::SUBSCRIBER_NOT_EXISTS);
- }
- return $subscriber->withCustomFields()->withSubscriptions()->asArray();
- }
- protected function _sendConfirmationEmail(Subscriber $subscriber) {
- return $this->confirmationEmailMailer->sendConfirmationEmailOnce($subscriber);
- }
- protected function _scheduleWelcomeNotification(Subscriber $subscriber, array $segments) {
- $result = $this->welcomeScheduler->scheduleSubscriberWelcomeNotification($subscriber->id, $segments);
- if (is_array($result)) {
- foreach ($result as $queue) {
- if ($queue instanceof Sending && $queue->getErrors()) {
- throw new APIException(
- __(sprintf('Subscriber added, but welcome email failed to send: %s', strtolower(implode(', ', $queue->getErrors()))), 'mailpoet'),
- APIException::WELCOME_FAILED_TO_SEND
- );
- }
- }
- }
- return $result;
- }
- private function sendSubscriberNotification(Subscriber $subscriber, array $segmentIds) {
- $this->newSubscriberNotificationMailer->send($subscriber, Segment::whereIn('id', $segmentIds)->findMany());
- }
- }
|