Add hook for segment subscription

This will be used for a "SegmentSubscribed" trigger for automation
that can trigger welcome emails and other actions.

[MAILPOET-4136]
This commit is contained in:
Jan Jakes
2022-03-02 11:00:03 +01:00
committed by Veljko V
parent 716050b7de
commit 86d934ba36
6 changed files with 91 additions and 5 deletions

View File

@@ -5,6 +5,7 @@ namespace MailPoet\API\MP\v1;
use MailPoet\API\JSON\ResponseBuilders\SubscribersResponseBuilder; use MailPoet\API\JSON\ResponseBuilders\SubscribersResponseBuilder;
use MailPoet\Entities\SegmentEntity; use MailPoet\Entities\SegmentEntity;
use MailPoet\Entities\SubscriberEntity; use MailPoet\Entities\SubscriberEntity;
use MailPoet\Features\FeaturesController;
use MailPoet\Models\Segment; use MailPoet\Models\Segment;
use MailPoet\Models\Subscriber; use MailPoet\Models\Subscriber;
use MailPoet\Newsletter\Scheduler\WelcomeScheduler; use MailPoet\Newsletter\Scheduler\WelcomeScheduler;
@@ -42,6 +43,12 @@ class Subscribers {
/** @var NewSubscriberNotificationMailer */ /** @var NewSubscriberNotificationMailer */
private $newSubscriberNotificationMailer; private $newSubscriberNotificationMailer;
/** @var FeaturesController */
private $featuresController;
/** @var WPFunctions */
private $wp;
public function __construct ( public function __construct (
ConfirmationEmailMailer $confirmationEmailMailer, ConfirmationEmailMailer $confirmationEmailMailer,
NewSubscriberNotificationMailer $newSubscriberNotificationMailer, NewSubscriberNotificationMailer $newSubscriberNotificationMailer,
@@ -50,7 +57,9 @@ class Subscribers {
SubscriberSegmentRepository $subscriberSegmentRepository, SubscriberSegmentRepository $subscriberSegmentRepository,
SubscribersRepository $subscribersRepository, SubscribersRepository $subscribersRepository,
SubscribersResponseBuilder $subscribersResponseBuilder, SubscribersResponseBuilder $subscribersResponseBuilder,
WelcomeScheduler $welcomeScheduler WelcomeScheduler $welcomeScheduler,
FeaturesController $featuresController,
WPFunctions $wp
) { ) {
$this->confirmationEmailMailer = $confirmationEmailMailer; $this->confirmationEmailMailer = $confirmationEmailMailer;
$this->newSubscriberNotificationMailer = $newSubscriberNotificationMailer; $this->newSubscriberNotificationMailer = $newSubscriberNotificationMailer;
@@ -60,6 +69,8 @@ class Subscribers {
$this->subscribersRepository = $subscribersRepository; $this->subscribersRepository = $subscribersRepository;
$this->subscribersResponseBuilder = $subscribersResponseBuilder; $this->subscribersResponseBuilder = $subscribersResponseBuilder;
$this->welcomeScheduler = $welcomeScheduler; $this->welcomeScheduler = $welcomeScheduler;
$this->featuresController = $featuresController;
$this->wp = $wp;
} }
/** /**
@@ -144,6 +155,19 @@ class Subscribers {
APIException::FAILED_TO_SAVE_SUBSCRIBER APIException::FAILED_TO_SAVE_SUBSCRIBER
); );
} }
// when global status changes to subscribed, fire subscribed hook for all subscribed segments
if (
$this->featuresController->isSupported(FeaturesController::AUTOMATION)
&& $subscriber->getStatus() === SubscriberEntity::STATUS_SUBSCRIBED
) {
$subscriberSegments = $subscriber->getSubscriberSegments();
foreach ($subscriberSegments as $subscriberSegment) {
if ($subscriberSegment->getStatus() === SubscriberEntity::STATUS_SUBSCRIBED) {
$this->wp->doAction('mailpoet_segment_subscribed', $subscriberSegment);
}
}
}
} }
// schedule welcome email // schedule welcome email

View File

@@ -6,12 +6,31 @@ use MailPoet\Doctrine\Repository;
use MailPoet\Entities\SegmentEntity; use MailPoet\Entities\SegmentEntity;
use MailPoet\Entities\SubscriberEntity; use MailPoet\Entities\SubscriberEntity;
use MailPoet\Entities\SubscriberSegmentEntity; use MailPoet\Entities\SubscriberSegmentEntity;
use MailPoet\Features\FeaturesController;
use MailPoet\WP\Functions as WPFunctions;
use MailPoetVendor\Doctrine\ORM\EntityManager;
use MailPoetVendor\Doctrine\ORM\Query\Expr\Join; use MailPoetVendor\Doctrine\ORM\Query\Expr\Join;
/** /**
* @extends Repository<SubscriberSegmentEntity> * @extends Repository<SubscriberSegmentEntity>
*/ */
class SubscriberSegmentRepository extends Repository { class SubscriberSegmentRepository extends Repository {
/** @var FeaturesController */
private $featuresController;
/** @var WPFunctions */
private $wp;
public function __construct(
EntityManager $entityManager,
FeaturesController $featuresController,
WPFunctions $wp
) {
parent::__construct($entityManager);
$this->featuresController = $featuresController;
$this->wp = $wp;
}
protected function getEntityClassName() { protected function getEntityClassName() {
return SubscriberSegmentEntity::class; return SubscriberSegmentEntity::class;
} }
@@ -83,13 +102,27 @@ class SubscriberSegmentRepository extends Repository {
public function createOrUpdate(SubscriberEntity $subscriber, SegmentEntity $segment, string $status): SubscriberSegmentEntity { public function createOrUpdate(SubscriberEntity $subscriber, SegmentEntity $segment, string $status): SubscriberSegmentEntity {
$subscriberSegment = $this->findOneBy(['segment' => $segment, 'subscriber' => $subscriber]); $subscriberSegment = $this->findOneBy(['segment' => $segment, 'subscriber' => $subscriber]);
$oldStatus = null;
if ($subscriberSegment instanceof SubscriberSegmentEntity) { if ($subscriberSegment instanceof SubscriberSegmentEntity) {
$oldStatus = $subscriberSegment->getStatus();
$subscriberSegment->setStatus($status); $subscriberSegment->setStatus($status);
} else { } else {
$subscriberSegment = new SubscriberSegmentEntity($segment, $subscriber, $status); $subscriberSegment = new SubscriberSegmentEntity($segment, $subscriber, $status);
$subscriber->getSubscriberSegments()->add($subscriberSegment); $subscriber->getSubscriberSegments()->add($subscriberSegment);
$this->entityManager->persist($subscriberSegment); $this->entityManager->persist($subscriberSegment);
} }
// fire subscribed hook for new subscriptions
if (
$this->featuresController->isSupported(FeaturesController::AUTOMATION)
&& $subscriber->getStatus() === SubscriberEntity::STATUS_SUBSCRIBED
&& $subscriberSegment->getStatus() === SubscriberEntity::STATUS_SUBSCRIBED
&& $oldStatus !== SubscriberEntity::STATUS_SUBSCRIBED
) {
$this->wp->doAction('mailpoet_segment_subscribed', $subscriberSegment);
}
$this->entityManager->flush(); $this->entityManager->flush();
return $subscriberSegment; return $subscriberSegment;
} }

View File

@@ -4,6 +4,8 @@ namespace MailPoet\Subscription;
use MailPoet\Config\Renderer as TemplateRenderer; use MailPoet\Config\Renderer as TemplateRenderer;
use MailPoet\Entities\StatisticsUnsubscribeEntity; use MailPoet\Entities\StatisticsUnsubscribeEntity;
use MailPoet\Entities\SubscriberEntity;
use MailPoet\Features\FeaturesController;
use MailPoet\Form\AssetsController; use MailPoet\Form\AssetsController;
use MailPoet\Models\Subscriber; use MailPoet\Models\Subscriber;
use MailPoet\Models\SubscriberSegment; use MailPoet\Models\SubscriberSegment;
@@ -74,6 +76,9 @@ class Pages {
/** @var TrackingConfig */ /** @var TrackingConfig */
private $trackingConfig; private $trackingConfig;
/** @var FeaturesController */
private $featuresController;
public function __construct( public function __construct(
NewSubscriberNotificationMailer $newSubscriberNotificationSender, NewSubscriberNotificationMailer $newSubscriberNotificationSender,
WPFunctions $wp, WPFunctions $wp,
@@ -88,7 +93,8 @@ class Pages {
ManageSubscriptionFormRenderer $manageSubscriptionFormRenderer, ManageSubscriptionFormRenderer $manageSubscriptionFormRenderer,
SubscriberHandler $subscriberHandler, SubscriberHandler $subscriberHandler,
SubscribersRepository $subscribersRepository, SubscribersRepository $subscribersRepository,
TrackingConfig $trackingConfig TrackingConfig $trackingConfig,
FeaturesController $featuresController
) { ) {
$this->wp = $wp; $this->wp = $wp;
$this->newSubscriberNotificationSender = $newSubscriberNotificationSender; $this->newSubscriberNotificationSender = $newSubscriberNotificationSender;
@@ -104,6 +110,7 @@ class Pages {
$this->subscriberHandler = $subscriberHandler; $this->subscriberHandler = $subscriberHandler;
$this->subscribersRepository = $subscribersRepository; $this->subscribersRepository = $subscribersRepository;
$this->trackingConfig = $trackingConfig; $this->trackingConfig = $trackingConfig;
$this->featuresController = $featuresController;
} }
public function init($action = false, $data = [], $initShortcodes = false, $initPageFilters = false) { public function init($action = false, $data = [], $initShortcodes = false, $initPageFilters = false) {
@@ -193,6 +200,17 @@ class Pages {
); );
} }
// when global status changes to subscribed, fire subscribed hook for all subscribed segments
if ($this->featuresController->isSupported(FeaturesController::AUTOMATION)) {
$subscriber = $this->subscribersRepository->findOneById($this->subscriber->id);
$segments = $subscriber ? $subscriber->getSubscriberSegments() : [];
foreach ($segments as $subscriberSegment) {
if ($subscriberSegment->getStatus() === SubscriberEntity::STATUS_SUBSCRIBED) {
$this->wp->doAction('mailpoet_segment_subscribed', $subscriberSegment);
}
}
}
// Send new subscriber notification only when status changes to subscribed or there are unconfirmed data to avoid spamming // Send new subscriber notification only when status changes to subscribed or there are unconfirmed data to avoid spamming
if ($originalStatus !== Subscriber::STATUS_SUBSCRIBED || $subscriberData !== null) { if ($originalStatus !== Subscriber::STATUS_SUBSCRIBED || $subscriberData !== null) {
$this->newSubscriberNotificationSender->send($this->subscriber, $subscriberSegments); $this->newSubscriberNotificationSender->send($this->subscriber, $subscriberSegments);

View File

@@ -13,6 +13,7 @@ use MailPoet\CustomFields\CustomFieldsRepository;
use MailPoet\Entities\CustomFieldEntity; use MailPoet\Entities\CustomFieldEntity;
use MailPoet\Entities\SegmentEntity; use MailPoet\Entities\SegmentEntity;
use MailPoet\Entities\SubscriberEntity; use MailPoet\Entities\SubscriberEntity;
use MailPoet\Features\FeaturesController;
use MailPoet\Models\ScheduledTask; use MailPoet\Models\ScheduledTask;
use MailPoet\Models\SendingQueue; use MailPoet\Models\SendingQueue;
use MailPoet\Newsletter\Scheduler\WelcomeScheduler; use MailPoet\Newsletter\Scheduler\WelcomeScheduler;
@@ -25,6 +26,7 @@ use MailPoet\Subscribers\SubscriberSegmentRepository;
use MailPoet\Subscribers\SubscribersRepository; use MailPoet\Subscribers\SubscribersRepository;
use MailPoet\Tasks\Sending; use MailPoet\Tasks\Sending;
use MailPoet\Test\DataFactories\Subscriber as SubscriberFactory; use MailPoet\Test\DataFactories\Subscriber as SubscriberFactory;
use MailPoet\WP\Functions as WPFunctions;
use MailPoetVendor\Idiorm\ORM; use MailPoetVendor\Idiorm\ORM;
class APITest extends \MailPoetTest { class APITest extends \MailPoetTest {
@@ -57,7 +59,9 @@ class APITest extends \MailPoetTest {
$this->diContainer->get(SubscriberSegmentRepository::class), $this->diContainer->get(SubscriberSegmentRepository::class),
$this->diContainer->get(SubscribersRepository::class), $this->diContainer->get(SubscribersRepository::class),
$this->diContainer->get(SubscribersResponseBuilder::class), $this->diContainer->get(SubscribersResponseBuilder::class),
Stub::makeEmpty(WelcomeScheduler::class) Stub::makeEmpty(WelcomeScheduler::class),
$this->diContainer->get(FeaturesController::class),
$this->diContainer->get(WPFunctions::class)
); );
} }

View File

@@ -11,6 +11,7 @@ use MailPoet\API\MP\v1\Subscribers;
use MailPoet\Config\Changelog; use MailPoet\Config\Changelog;
use MailPoet\Entities\SegmentEntity; use MailPoet\Entities\SegmentEntity;
use MailPoet\Entities\SubscriberEntity; use MailPoet\Entities\SubscriberEntity;
use MailPoet\Features\FeaturesController;
use MailPoet\Newsletter\Scheduler\WelcomeScheduler; use MailPoet\Newsletter\Scheduler\WelcomeScheduler;
use MailPoet\Segments\SegmentsRepository; use MailPoet\Segments\SegmentsRepository;
use MailPoet\Settings\SettingsController; use MailPoet\Settings\SettingsController;
@@ -20,6 +21,7 @@ use MailPoet\Subscribers\RequiredCustomFieldValidator;
use MailPoet\Subscribers\SubscriberSegmentRepository; use MailPoet\Subscribers\SubscriberSegmentRepository;
use MailPoet\Subscribers\SubscribersRepository; use MailPoet\Subscribers\SubscribersRepository;
use MailPoet\Test\DataFactories\Subscriber as SubscriberFactory; use MailPoet\Test\DataFactories\Subscriber as SubscriberFactory;
use MailPoet\WP\Functions as WPFunctions;
class SubscribersTest extends \MailPoetTest { class SubscribersTest extends \MailPoetTest {
@@ -47,7 +49,9 @@ class SubscribersTest extends \MailPoetTest {
$this->diContainer->get(SubscriberSegmentRepository::class), $this->diContainer->get(SubscriberSegmentRepository::class),
$this->diContainer->get(SubscribersRepository::class), $this->diContainer->get(SubscribersRepository::class),
$this->diContainer->get(SubscribersResponseBuilder::class), $this->diContainer->get(SubscribersResponseBuilder::class),
Stub::makeEmpty(WelcomeScheduler::class) Stub::makeEmpty(WelcomeScheduler::class),
$this->diContainer->get(FeaturesController::class),
$this->diContainer->get(WPFunctions::class)
); );
} }
@@ -178,6 +182,7 @@ class SubscribersTest extends \MailPoetTest {
'subscribersSegmentRepository' => $this->diContainer->get(SubscriberSegmentRepository::class), 'subscribersSegmentRepository' => $this->diContainer->get(SubscriberSegmentRepository::class),
'subscribersResponseBuilder' => $this->diContainer->get(SubscribersResponseBuilder::class), 'subscribersResponseBuilder' => $this->diContainer->get(SubscribersResponseBuilder::class),
'settings' => SettingsController::getInstance(), 'settings' => SettingsController::getInstance(),
'featuresController' => $this->diContainer->get(FeaturesController::class),
] ]
); );

View File

@@ -7,6 +7,7 @@ use MailPoet\Config\Renderer;
use MailPoet\DI\ContainerWrapper; use MailPoet\DI\ContainerWrapper;
use MailPoet\Entities\StatisticsUnsubscribeEntity; use MailPoet\Entities\StatisticsUnsubscribeEntity;
use MailPoet\Entities\SubscriberEntity; use MailPoet\Entities\SubscriberEntity;
use MailPoet\Features\FeaturesController;
use MailPoet\Form\AssetsController; use MailPoet\Form\AssetsController;
use MailPoet\Models\Newsletter; use MailPoet\Models\Newsletter;
use MailPoet\Models\NewsletterOption; use MailPoet\Models\NewsletterOption;
@@ -217,7 +218,8 @@ class PagesTest extends \MailPoetTest {
$container->get(ManageSubscriptionFormRenderer::class), $container->get(ManageSubscriptionFormRenderer::class),
$container->get(SubscriberHandler::class), $container->get(SubscriberHandler::class),
$this->subscribersRepository, $this->subscribersRepository,
$container->get(TrackingConfig::class) $container->get(TrackingConfig::class),
$container->get(FeaturesController::class)
); );
} }
} }