暫無描述

FirstPurchase.php 7.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. <?php
  2. namespace MailPoet\AutomaticEmails\WooCommerce\Events;
  3. if (!defined('ABSPATH')) exit;
  4. use MailPoet\AutomaticEmails\WooCommerce\WooCommerce;
  5. use MailPoet\DI\ContainerWrapper;
  6. use MailPoet\Logging\LoggerFactory;
  7. use MailPoet\Models\Newsletter;
  8. use MailPoet\Models\SendingQueue;
  9. use MailPoet\Models\Subscriber;
  10. use MailPoet\Newsletter\AutomaticEmailsRepository;
  11. use MailPoet\Newsletter\Scheduler\AutomaticEmailScheduler;
  12. use MailPoet\WooCommerce\Helper as WCHelper;
  13. use MailPoet\WP\Functions as WPFunctions;
  14. class FirstPurchase {
  15. const SLUG = 'woocommerce_first_purchase';
  16. const ORDER_TOTAL_SHORTCODE = '[woocommerce:order_total]';
  17. const ORDER_DATE_SHORTCODE = '[woocommerce:order_date]';
  18. /**
  19. * @var \MailPoet\WooCommerce\Helper
  20. */
  21. private $helper;
  22. /** @var AutomaticEmailScheduler */
  23. private $scheduler;
  24. /** @var LoggerFactory */
  25. private $loggerFactory;
  26. /** @var AutomaticEmailsRepository */
  27. private $repository;
  28. public function __construct(
  29. WCHelper $helper = null
  30. ) {
  31. if ($helper === null) {
  32. $helper = new WCHelper();
  33. }
  34. $this->helper = $helper;
  35. $this->scheduler = new AutomaticEmailScheduler();
  36. $this->loggerFactory = LoggerFactory::getInstance();
  37. $this->repository = ContainerWrapper::getInstance()->get(AutomaticEmailsRepository::class);
  38. }
  39. public function init() {
  40. WPFunctions::get()->addFilter('mailpoet_newsletter_shortcode', [
  41. $this,
  42. 'handleOrderTotalShortcode',
  43. ], 10, 4);
  44. WPFunctions::get()->addFilter('mailpoet_newsletter_shortcode', [
  45. $this,
  46. 'handleOrderDateShortcode',
  47. ], 10, 4);
  48. // We have to use a set of states because an order state after checkout differs for different payment methods
  49. $acceptedOrderStates = WPFunctions::get()->applyFilters('mailpoet_first_purchase_order_states', ['completed', 'processing']);
  50. foreach ($acceptedOrderStates as $state) {
  51. WPFunctions::get()->addAction('woocommerce_order_status_' . $state, [
  52. $this,
  53. 'scheduleEmailWhenOrderIsPlaced',
  54. ], 10, 1);
  55. }
  56. }
  57. public function getEventDetails() {
  58. return [
  59. 'slug' => self::SLUG,
  60. 'title' => WPFunctions::get()->__('First Purchase', 'mailpoet'),
  61. 'description' => WPFunctions::get()->__('Let MailPoet send an email to customers who make their first purchase.', 'mailpoet'),
  62. 'listingScheduleDisplayText' => WPFunctions::get()->__('Email sent when a customer makes their first purchase.', 'mailpoet'),
  63. 'badge' => [
  64. 'text' => WPFunctions::get()->__('Must-have', 'mailpoet'),
  65. 'style' => 'red',
  66. ],
  67. 'shortcodes' => [
  68. [
  69. 'text' => WPFunctions::get()->__('Order amount', 'mailpoet'),
  70. 'shortcode' => self::ORDER_TOTAL_SHORTCODE,
  71. ],
  72. [
  73. 'text' => WPFunctions::get()->__('Order date', 'mailpoet'),
  74. 'shortcode' => self::ORDER_DATE_SHORTCODE,
  75. ],
  76. ],
  77. ];
  78. }
  79. public function handleOrderDateShortcode($shortcode, $newsletter, $subscriber, $queue) {
  80. $result = $shortcode;
  81. if ($shortcode === self::ORDER_DATE_SHORTCODE) {
  82. $defaultValue = WPFunctions::get()->dateI18n(get_option('date_format'));
  83. if (!$queue) {
  84. $result = $defaultValue;
  85. } else {
  86. $meta = $queue->getMeta();
  87. $result = (!empty($meta['order_date'])) ? WPFunctions::get()->dateI18n(get_option('date_format'), $meta['order_date']) : $defaultValue;
  88. }
  89. }
  90. $this->loggerFactory->getLogger(self::SLUG)->addInfo(
  91. 'handleOrderDateShortcode called', [
  92. 'newsletter_id' => ($newsletter instanceof Newsletter) ? $newsletter->id : null,
  93. 'subscriber_id' => ($subscriber instanceof Subscriber) ? $subscriber->id : null,
  94. 'task_id' => ($queue instanceof SendingQueue) ? $queue->taskId : null,
  95. 'shortcode' => $shortcode,
  96. 'result' => $result,
  97. ]
  98. );
  99. return $result;
  100. }
  101. public function handleOrderTotalShortcode($shortcode, $newsletter, $subscriber, $queue) {
  102. $result = $shortcode;
  103. if ($shortcode === self::ORDER_TOTAL_SHORTCODE) {
  104. $defaultValue = $this->helper->wcPrice(0);
  105. if (!$queue) {
  106. $result = $defaultValue;
  107. } else {
  108. $meta = $queue->getMeta();
  109. $result = (!empty($meta['order_amount'])) ? $this->helper->wcPrice($meta['order_amount']) : $defaultValue;
  110. }
  111. }
  112. $this->loggerFactory->getLogger(self::SLUG)->addInfo(
  113. 'handleOrderTotalShortcode called', [
  114. 'newsletter_id' => ($newsletter instanceof Newsletter) ? $newsletter->id : null,
  115. 'subscriber_id' => ($subscriber instanceof Subscriber) ? $subscriber->id : null,
  116. 'task_id' => ($queue instanceof SendingQueue) ? $queue->taskId : null,
  117. 'shortcode' => $shortcode,
  118. 'result' => $result,
  119. ]
  120. );
  121. return $result;
  122. }
  123. public function scheduleEmailWhenOrderIsPlaced($orderId) {
  124. $orderDetails = $this->helper->wcGetOrder($orderId);
  125. if (!$orderDetails || !$orderDetails->get_billing_email()) {
  126. $this->loggerFactory->getLogger(self::SLUG)->addInfo(
  127. 'Email not scheduled because the order customer was not found',
  128. ['order_id' => $orderId]
  129. );
  130. return;
  131. }
  132. $customerEmail = $orderDetails->get_billing_email();
  133. $customerOrderCount = $this->getCustomerOrderCount($customerEmail);
  134. if ($customerOrderCount > 1) {
  135. $this->loggerFactory->getLogger(self::SLUG)->addInfo(
  136. 'Email not scheduled because this is not the first order of the customer', [
  137. 'order_id' => $orderId,
  138. 'customer_email' => $customerEmail,
  139. 'order_count' => $customerOrderCount,
  140. ]
  141. );
  142. return;
  143. }
  144. $meta = [
  145. 'order_amount' => $orderDetails->get_total(),
  146. 'order_date' => $orderDetails->get_date_created()->getTimestamp(),
  147. 'order_id' => $orderDetails->get_id(),
  148. ];
  149. $subscriber = Subscriber::getWooCommerceSegmentSubscriber($customerEmail);
  150. if (!$subscriber instanceof Subscriber) {
  151. $this->loggerFactory->getLogger(self::SLUG)->addInfo(
  152. 'Email not scheduled because the customer was not found as WooCommerce list subscriber',
  153. ['order_id' => $orderId, 'customer_email' => $customerEmail]
  154. );
  155. return;
  156. }
  157. $checkEmailWasNotScheduled = function (Newsletter $newsletter) use ($subscriber) {
  158. return !$this->repository->wasScheduledForSubscriber($newsletter->id, $subscriber->id);
  159. };
  160. $this->loggerFactory->getLogger(self::SLUG)->addInfo(
  161. 'Email scheduled', [
  162. 'order_id' => $orderId,
  163. 'customer_email' => $customerEmail,
  164. 'subscriber_id' => $subscriber->id,
  165. ]
  166. );
  167. $this->scheduler->scheduleAutomaticEmail(WooCommerce::SLUG, self::SLUG, $checkEmailWasNotScheduled, $subscriber->id, $meta);
  168. }
  169. public function getCustomerOrderCount($customerEmail) {
  170. // registered user
  171. $user = WPFunctions::get()->getUserBy('email', $customerEmail);
  172. if ($user) {
  173. return $this->helper->wcGetCustomerOrderCount($user->ID);
  174. }
  175. // guest user
  176. return $this->getGuestCustomerOrderCountByEmail($customerEmail);
  177. }
  178. private function getGuestCustomerOrderCountByEmail($customerEmail) {
  179. global $wpdb;
  180. $count = $wpdb->get_var( "SELECT COUNT(*)
  181. FROM $wpdb->posts as posts
  182. LEFT JOIN {$wpdb->postmeta} AS meta ON posts.ID = meta.post_id
  183. WHERE meta.meta_key = '_billing_email'
  184. AND posts.post_type = 'shop_order'
  185. AND meta_value = '" . WPFunctions::get()->escSql($customerEmail) . "'
  186. " );
  187. return (int)$count;
  188. }
  189. }