PluginProbe ʕ •ᴥ•ʔ
MailPoet – Newsletters, Email Marketing, and Automation / 5.34.2
MailPoet – Newsletters, Email Marketing, and Automation v5.34.2
5.34.2 5.34.1 5.34.0 5.33.1 5.33.0 5.32.0 5.31.0 5.30.0 5.29.0 5.28.1 5.28.0 5.27.0 5.26.0 5.26.1 5.25.0 5.24.0 4.43.0 4.43.1 4.44.0 4.44.1 4.45.0 4.46.0 4.47.0 4.48.0 4.48.1 4.48.2 4.49.0 4.49.1 4.5.0 4.5.1 4.5.2 4.50.0 4.50.1 4.51.0 4.51.1 4.51.2 4.52.0 4.53.0 4.54.0 4.55.0 4.56.0 4.57.0 4.58.0 4.58.1 4.58.2 4.6.0 4.6.1 4.6.2 4.7.0 4.7.1 4.8.0 4.8.1 4.9.0 5.0.0 5.0.1 5.0.2 5.1.0 5.1.1 5.10.0 5.10.1 5.11.0 5.12.0 5.12.1 5.12.10 5.12.11 5.12.12 5.12.13 5.12.2 5.12.3 5.12.4 5.12.5 5.12.6 5.12.7 5.12.8 5.12.9 5.13.0 5.13.1 5.13.2 5.14.0 5.14.1 5.14.2 5.14.3 5.15.0 5.15.1 5.16.0 5.16.1 5.16.2 5.16.3 5.16.4 5.17.0 5.17.1 5.17.2 5.17.3 5.17.4 5.17.5 5.17.6 5.18.0 5.19.0 5.2.0 5.2.1 5.2.2 5.2.3 5.20.0 5.21.0 5.21.1 5.21.2 5.21.3 5.22.0 5.22.1 5.22.2 5.22.3 5.22.4 5.23.0 5.23.1 5.23.2 5.3.0 5.3.1 5.3.2 5.3.3 5.3.4 5.3.5 5.3.6 5.3.7 5.4.0 5.4.1 5.4.2 5.5.0 5.5.1 5.5.2 5.6.0 5.6.1 5.6.2 5.6.3 5.6.4 5.7.0 5.7.1 5.8.0 5.8.1 5.9.0 3.0.0-beta.15 3.7.1 3.0.0-beta.16 3.7.2 3.0.0-beta.17 3.7.3 3.0.0-beta.18 3.7.4 3.0.0-beta.19 3.7.5 3.0.0-beta.2 3.7.6 3.0.0-beta.20 3.7.8 3.0.0-beta.21 3.70.0 3.0.0-beta.22 3.71.0 3.0.0-beta.23 3.71.1 3.0.0-beta.23.1 3.71.2 3.0.0-beta.23.2 3.71.3 3.0.0-beta.24 3.72.0 3.0.0-beta.25 3.73.0 3.0.0-beta.26 3.73.1 3.0.0-beta.27 3.73.2 3.0.0-beta.28 3.74.0 3.0.0-beta.29 3.74.1 3.0.0-beta.3 3.74.2 3.0.0-beta.30 3.74.3 3.0.0-beta.31 3.75.0 3.0.0-beta.32 3.75.1 3.0.0-beta.33 3.76.0 3.0.0-beta.33.1 3.77.0 3.0.0-beta.34.0.0 3.77.1 3.0.0-beta.36.0.0 3.78.0 3.0.0-beta.36.0.1 3.79.0 3.0.0-beta.36.2.0 3.8 3.0.0-beta.36.3.0 3.8.1 3.0.0-beta.36.3.1 3.8.2 3.0.0-beta.37.0.0 3.8.3 3.0.0-beta.4 3.8.4 3.0.0-beta.5 3.8.5 3.0.0-beta.6 3.8.6 3.0.0-beta.7 3.80.0 3.0.0-beta.7.1 3.81.0 3.0.0-beta.8 3.82.0 3.0.0-beta.9 3.83.0 3.0.0-rc.1.0.0 3.84.0 3.0.0-rc.1.0.1 3.84.1 3.0.0-rc.1.0.2 3.85.0 3.0.0-rc.1.0.3 3.85.1 3.0.0-rc.1.0.4 3.86.0 3.0.0-rc.2.0.0 3.87.0 3.0.0-rc.2.0.1 3.87.1 3.0.0-rc.2.0.2 3.87.2 3.0.0-rc.2.0.3 3.88.0 3.0.1 3.88.1 3.0.2 3.88.2 3.0.3 3.89.0 3.0.4 3.89.1 3.0.5 3.89.2 3.0.6 3.89.3 3.0.7 3.89.4 3.0.8 3.9.0 3.0.9 3.9.1 3.1.0 3.90.0 3.10 3.90.1 3.10.1 3.90.2 3.100.0 3.91.0 3.100.1 3.91.1 3.100.2 3.92.0 3.101.0 3.92.1 3.101.1 3.93.0 3.102.0 3.93.1 3.102.1 3.94.0 3.103.0 3.95.0 3.103.1 3.95.1 3.11.0 3.96.0 3.11.1 3.96.1 3.11.2 3.97.0 3.11.3 3.98.0 3.11.4 3.98.1 3.11.5 3.99.0 3.12.0 3.99.1 3.12.1 4.0.0 3.13.0 4.0.1 3.14.0 4.1.0 3.14.1 4.1.1 3.15.0 4.10.0 3.16.0 4.11.0 3.16.1 4.11.1 3.16.2 4.12.0 3.16.3 4.12.1 3.17.0 4.12.2 3.17.1 4.13.0 3.17.2 4.14.0 3.18.0 4.15.0 3.18.1 4.16.0 3.18.2 4.17.0 3.19.0 4.17.1 3.19.1 4.18.0 3.19.2 4.18.1 3.19.3 4.19.0 3.2.0 4.2.0 3.2.1 4.20.0 3.2.2 4.20.1 3.2.3 4.20.2 3.2.4 4.21.0 3.2.5 4.22.0 3.20.0 4.22.1 3.21.0 4.22.2 3.21.1 4.23.0 3.22.0 4.24.0 3.23.0 4.25.0 3.23.1 4.26.0 3.23.2 4.26.1 3.24.0 4.27.0 3.25.0 4.28.0 3.25.1 4.29.0 3.26.0 4.3.0 3.26.1 4.3.1 3.27.0 4.30.0 3.28.0 4.31.0 3.29.0 4.31.1 3.3.0 4.32.0 3.3.1 4.33.0 3.3.2 4.34.0 3.3.3 4.35.0 3.3.4 4.35.1 3.3.5 4.36.0 3.3.6 4.37.0 3.30.0 4.38.0 3.31.0 4.39.0 3.31.1 4.4.0 3.32.0 4.40.0 3.32.1 4.41.0 3.32.2 4.41.1 3.33.0 4.41.2 3.34.0 4.41.3 3.34.1 4.42.0 3.34.2 4.42.1 3.34.3 3.34.4 3.35.0 3.35.1 3.35.3 3.35.4 3.36.0 3.37.0 3.37.1 3.37.2 3.37.3 3.38.0 3.38.1 3.39.0 3.39.1 3.39.2 3.4.0 3.4.1 3.4.2 3.4.3 3.4.4 3.40.0 3.40.1 3.41.0 3.41.1 3.41.2 3.42.0 3.42.1 3.42.2 3.42.3 3.43.0 3.43.1 3.44.0 3.45.0 3.45.1 3.46.0 3.46.1 3.46.10 3.46.11 3.46.12 3.46.13 3.46.14 3.46.2 3.46.3 3.46.4 3.46.5 3.46.6 3.46.7 3.46.8 3.46.9 3.47.0 3.47.1 3.47.10 3.47.11 3.47.2 3.47.3 3.47.5 3.47.6 3.47.7 3.47.9 3.48.0 3.48.1 3.49.0 3.49.1 3.5.0 3.5.1 3.50.0 3.51.0 3.51.1 3.51.2 3.52.0 3.53.0 3.54.0 3.54.1 3.54.2 3.54.3 3.55.0 3.55.1 3.56.0 3.56.1 3.56.2 3.57.0 3.57.1 3.58.0 3.59.0 3.59.1 3.59.2 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.6.5 3.6.6 3.6.7 3.60.0 3.60.1 3.60.10 3.60.11 3.60.12 3.60.2 3.60.3 3.60.4 3.60.6 3.60.7 3.60.8 3.60.9 3.61.0 3.62.0 3.62.1 3.63.0 3.64.0 3.64.1 3.64.2 3.64.3 3.65.0 trunk 3.65.1 3.0.0 3.66.0 3.0.0-beta.1 3.67.0 3.0.0-beta.10 3.67.1 3.0.0-beta.11 3.68.0 3.0.0-beta.12 3.69.0 3.0.0-beta.13 3.69.1 3.0.0-beta.14 3.7.0
mailpoet / lib / AutomaticEmails / WooCommerce / Events / FirstPurchase.php
mailpoet / lib / AutomaticEmails / WooCommerce / Events Last commit date
AbandonedCart.php 1 year ago FirstPurchase.php 2 months ago PurchasedInCategory.php 2 months ago PurchasedProduct.php 2 months ago index.php 3 years ago
FirstPurchase.php
256 lines
1 <?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing
2
3 namespace MailPoet\AutomaticEmails\WooCommerce\Events;
4
5 if (!defined('ABSPATH')) exit;
6
7
8 use MailPoet\AutomaticEmails\WooCommerce\WooCommerce;
9 use MailPoet\DI\ContainerWrapper;
10 use MailPoet\Entities\NewsletterEntity;
11 use MailPoet\Entities\SendingQueueEntity;
12 use MailPoet\Entities\SubscriberEntity;
13 use MailPoet\Logging\LoggerFactory;
14 use MailPoet\Newsletter\AutomaticEmailsRepository;
15 use MailPoet\Newsletter\Scheduler\AutomaticEmailScheduler;
16 use MailPoet\Subscribers\SubscribersRepository;
17 use MailPoet\WooCommerce\Helper as WCHelper;
18 use MailPoet\WP\Functions as WPFunctions;
19
20 class FirstPurchase {
21 const SLUG = 'woocommerce_first_purchase';
22 const ORDER_TOTAL_SHORTCODE = '[woocommerce:order_total]';
23 const ORDER_DATE_SHORTCODE = '[woocommerce:order_date]';
24 /**
25 * @var \MailPoet\WooCommerce\Helper
26 */
27 private $helper;
28
29 /** @var AutomaticEmailScheduler */
30 private $scheduler;
31
32 /** @var LoggerFactory */
33 private $loggerFactory;
34
35 /** @var AutomaticEmailsRepository */
36 private $automaticEmailsRepository;
37
38 /** @var SubscribersRepository */
39 private $subscribersRepository;
40
41 public function __construct(
42 ?WCHelper $helper = null
43 ) {
44 if ($helper === null) {
45 $helper = ContainerWrapper::getInstance()->get(WCHelper::class);
46 }
47 $this->helper = $helper;
48 $this->scheduler = ContainerWrapper::getInstance()->get(AutomaticEmailScheduler::class);
49 $this->loggerFactory = LoggerFactory::getInstance();
50 $this->automaticEmailsRepository = ContainerWrapper::getInstance()->get(AutomaticEmailsRepository::class);
51 $this->subscribersRepository = ContainerWrapper::getInstance()->get(SubscribersRepository::class);
52 }
53
54 public function init() {
55 WPFunctions::get()->addFilter('mailpoet_newsletter_shortcode', [
56 $this,
57 'handleOrderTotalShortcode',
58 ], 10, 4);
59 WPFunctions::get()->addFilter('mailpoet_newsletter_shortcode', [
60 $this,
61 'handleOrderDateShortcode',
62 ], 10, 4);
63
64 // We have to use a set of states because an order state after checkout differs for different payment methods
65 $acceptedOrderStates = WPFunctions::get()->applyFilters('mailpoet_first_purchase_order_states', ['completed', 'processing']);
66 if (!is_array($acceptedOrderStates)) {
67 $acceptedOrderStates = ['completed', 'processing'];
68 }
69
70 foreach ($acceptedOrderStates as $state) {
71 if (!is_string($state)) {
72 continue;
73 }
74 WPFunctions::get()->addAction('woocommerce_order_status_' . $state, [
75 $this,
76 'scheduleEmailWhenOrderIsPlaced',
77 ], 10, 1);
78 }
79 }
80
81 public function getEventDetails() {
82 return [
83 'slug' => self::SLUG,
84 'title' => __('First Purchase', 'mailpoet'),
85 'description' => __('Let MailPoet send an email to customers who make their first purchase.', 'mailpoet'),
86 'listingScheduleDisplayText' => __('Email sent when a customer makes their first purchase.', 'mailpoet'),
87 'afterDelayText' => __('after the first purchase', 'mailpoet'),
88 'badge' => [
89 'text' => __('Must-have', 'mailpoet'),
90 'style' => 'red',
91 ],
92 'timeDelayValues' => [
93 'immediate' => [
94 'text' => __('immediately', 'mailpoet'),
95 'displayAfterTimeNumberField' => false,
96 ],
97 'minutes' => [
98 'text' => __('minute(s)', 'mailpoet'),
99 'displayAfterTimeNumberField' => true,
100 ],
101 'hours' => [
102 'text' => __('hour(s)', 'mailpoet'),
103 'displayAfterTimeNumberField' => true,
104 ],
105 'days' => [
106 'text' => __('day(s)', 'mailpoet'),
107 'displayAfterTimeNumberField' => true,
108 ],
109 'weeks' => [
110 'text' => __('week(s)', 'mailpoet'),
111 'displayAfterTimeNumberField' => true,
112 ],
113 ],
114 'shortcodes' => [
115 [
116 'text' => __('Order amount', 'mailpoet'),
117 'shortcode' => self::ORDER_TOTAL_SHORTCODE,
118 ],
119 [
120 'text' => __('Order date', 'mailpoet'),
121 'shortcode' => self::ORDER_DATE_SHORTCODE,
122 ],
123 ],
124 ];
125 }
126
127 public function handleOrderDateShortcode($shortcode, $newsletter, $subscriber, $queue) {
128 $result = $shortcode;
129 if ($shortcode === self::ORDER_DATE_SHORTCODE) {
130 $defaultValue = WPFunctions::get()->dateI18n(get_option('date_format'));
131 if (!$queue) {
132 $result = $defaultValue;
133 } else {
134 $meta = $queue->getMeta();
135 $result = (!empty($meta['order_date'])) ? WPFunctions::get()->dateI18n(get_option('date_format'), $meta['order_date']) : $defaultValue;
136 }
137
138 $this->loggerFactory->getLogger(self::SLUG)->info(
139 'handleOrderDateShortcode called',
140 [
141 'newsletter_id' => ($newsletter instanceof NewsletterEntity) ? $newsletter->getId() : null,
142 'subscriber_id' => ($subscriber instanceof SubscriberEntity) ? $subscriber->getId() : null,
143 'task_id' => ($queue instanceof SendingQueueEntity) ? (($task = $queue->getTask()) ? $task->getId() : null) : null,
144 'shortcode' => $shortcode,
145 'result' => $result,
146 ]
147 );
148 }
149 return $result;
150 }
151
152 public function handleOrderTotalShortcode($shortcode, $newsletter, $subscriber, $queue) {
153 $result = $shortcode;
154 if ($shortcode === self::ORDER_TOTAL_SHORTCODE) {
155 $defaultValue = $this->helper->wcPrice(0);
156 if (!$queue) {
157 $result = $defaultValue;
158 } else {
159 $meta = $queue->getMeta();
160 $result = (!empty($meta['order_amount'])) ? $this->helper->wcPrice($meta['order_amount']) : $defaultValue;
161 }
162
163 $this->loggerFactory->getLogger(self::SLUG)->info(
164 'handleOrderTotalShortcode called',
165 [
166 'newsletter_id' => ($newsletter instanceof NewsletterEntity) ? $newsletter->getId() : null,
167 'subscriber_id' => ($subscriber instanceof SubscriberEntity) ? $subscriber->getId() : null,
168 'task_id' => ($queue instanceof SendingQueueEntity) ? (($task = $queue->getTask()) ? $task->getId() : null) : null,
169 'shortcode' => $shortcode,
170 'result' => $result,
171 ]
172 );
173 }
174 return $result;
175 }
176
177 public function scheduleEmailWhenOrderIsPlaced($orderId) {
178 $orderDetails = $this->helper->wcGetOrder($orderId);
179 if (!$orderDetails || !$orderDetails->get_billing_email()) {
180 $this->loggerFactory->getLogger(self::SLUG)->info(
181 'Email not scheduled because the order customer was not found',
182 ['order_id' => $orderId]
183 );
184 return;
185 }
186
187 $customerEmail = $orderDetails->get_billing_email();
188 $customerOrderCount = $this->getCustomerOrderCount($customerEmail);
189 if ($customerOrderCount > 1) {
190 $this->loggerFactory->getLogger(self::SLUG)->info(
191 'Email not scheduled because this is not the first order of the customer',
192 [
193 'order_id' => $orderId,
194 'customer_email' => $customerEmail,
195 'order_count' => $customerOrderCount,
196 ]
197 );
198 return;
199 }
200
201 $meta = [
202 'order_amount' => $orderDetails->get_total(),
203 'order_date' => $orderDetails->get_date_created()->getTimestamp(),
204 'order_id' => $orderDetails->get_id(),
205 ];
206
207 $subscriber = $this->subscribersRepository->getWooCommerceSegmentSubscriber($customerEmail);
208
209 if (!$subscriber instanceof SubscriberEntity) {
210 $this->loggerFactory->getLogger(self::SLUG)->info(
211 'Email not scheduled because the customer was not found as WooCommerce list subscriber',
212 ['order_id' => $orderId, 'customer_email' => $customerEmail]
213 );
214 return;
215 }
216
217 $checkEmailWasNotScheduled = function (NewsletterEntity $newsletter) use ($subscriber) {
218 return !$this->automaticEmailsRepository->wasScheduledForSubscriber((int)$newsletter->getId(), (int)$subscriber->getId());
219 };
220
221 $this->loggerFactory->getLogger(self::SLUG)->info(
222 'Email scheduled',
223 [
224 'order_id' => $orderId,
225 'customer_email' => $customerEmail,
226 'subscriber_id' => $subscriber->getId(),
227 ]
228 );
229 $this->scheduler->scheduleAutomaticEmail(WooCommerce::SLUG, self::SLUG, $checkEmailWasNotScheduled, $subscriber, $meta);
230 }
231
232 public function getCustomerOrderCount($customerEmail) {
233 // registered user
234 $user = WPFunctions::get()->getUserBy('email', $customerEmail);
235 if ($user) {
236 return $this->helper->wcGetCustomerOrderCount($user->ID);
237 }
238 // guest user
239 return $this->getGuestCustomerOrderCountByEmail($customerEmail);
240 }
241
242 private function getGuestCustomerOrderCountByEmail(string $customerEmail): int {
243 $ordersCount = $this->helper->wcGetOrders(
244 [
245 'status' => 'all',
246 'type' => 'shop_order',
247 'billing_email' => $customerEmail,
248 'limit' => 1,
249 'return' => 'ids',
250 'paginate' => true,
251 ]
252 )->total;
253 return intval($ordersCount);
254 }
255 }
256