Sin descripción

Clicks.php 6.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. <?php
  2. namespace MailPoet\Statistics\Track;
  3. if (!defined('ABSPATH')) exit;
  4. use MailPoet\Entities\NewsletterEntity;
  5. use MailPoet\Entities\NewsletterLinkEntity;
  6. use MailPoet\Entities\SendingQueueEntity;
  7. use MailPoet\Entities\StatisticsClickEntity;
  8. use MailPoet\Entities\SubscriberEntity;
  9. use MailPoet\Entities\UserAgentEntity;
  10. use MailPoet\Newsletter\Shortcodes\Categories\Link as LinkShortcodeCategory;
  11. use MailPoet\Newsletter\Shortcodes\Shortcodes;
  12. use MailPoet\Settings\SettingsController;
  13. use MailPoet\Statistics\StatisticsClicksRepository;
  14. use MailPoet\Statistics\UserAgentsRepository;
  15. use MailPoet\Subscribers\SubscribersRepository;
  16. use MailPoet\Util\Cookies;
  17. use MailPoet\WP\Functions as WPFunctions;
  18. class Clicks {
  19. const REVENUE_TRACKING_COOKIE_NAME = 'mailpoet_revenue_tracking';
  20. const REVENUE_TRACKING_COOKIE_EXPIRY = 60 * 60 * 24 * 14;
  21. const ABANDONED_CART_COOKIE_NAME = 'mailpoet_abandoned_cart_tracking';
  22. const ABANDONED_CART_COOKIE_EXPIRY = 10 * 365 * 24 * 60 * 60; // 10 years (~ no expiry)
  23. /** @var SettingsController */
  24. private $settingsController;
  25. /** @var Cookies */
  26. private $cookies;
  27. /** @var Shortcodes */
  28. private $shortcodes;
  29. /** @var LinkShortcodeCategory */
  30. private $linkShortcodeCategory;
  31. /** @var Opens */
  32. private $opens;
  33. /** @var StatisticsClicksRepository */
  34. private $statisticsClicksRepository;
  35. /** @var UserAgentsRepository */
  36. private $userAgentsRepository;
  37. /** @var SubscribersRepository */
  38. private $subscribersRepository;
  39. public function __construct(
  40. SettingsController $settingsController,
  41. Cookies $cookies,
  42. Shortcodes $shortcodes,
  43. Opens $opens,
  44. StatisticsClicksRepository $statisticsClicksRepository,
  45. UserAgentsRepository $userAgentsRepository,
  46. LinkShortcodeCategory $linkShortcodeCategory,
  47. SubscribersRepository $subscribersRepository
  48. ) {
  49. $this->settingsController = $settingsController;
  50. $this->cookies = $cookies;
  51. $this->shortcodes = $shortcodes;
  52. $this->linkShortcodeCategory = $linkShortcodeCategory;
  53. $this->opens = $opens;
  54. $this->statisticsClicksRepository = $statisticsClicksRepository;
  55. $this->userAgentsRepository = $userAgentsRepository;
  56. $this->subscribersRepository = $subscribersRepository;
  57. }
  58. /**
  59. * @param \stdClass|null $data
  60. */
  61. public function track($data) {
  62. if (!$data || empty($data->link)) {
  63. return $this->abort();
  64. }
  65. /** @var SubscriberEntity $subscriber */
  66. $subscriber = $data->subscriber;
  67. /** @var SendingQueueEntity $queue */
  68. $queue = $data->queue;
  69. /** @var NewsletterEntity $newsletter */
  70. $newsletter = $data->newsletter;
  71. /** @var NewsletterLinkEntity $link */
  72. $link = $data->link;
  73. $wpUserPreview = ($data->preview && ($subscriber->isWPUser()));
  74. // log statistics only if the action did not come from
  75. // a WP user previewing the newsletter
  76. if (!$wpUserPreview) {
  77. $userAgent = !empty($data->userAgent) ? $this->userAgentsRepository->findOrCreate($data->userAgent) : null;
  78. $statisticsClicks = $this->statisticsClicksRepository->createOrUpdateClickCount(
  79. $link,
  80. $subscriber,
  81. $newsletter,
  82. $queue,
  83. $userAgent
  84. );
  85. if ($userAgent instanceof UserAgentEntity &&
  86. ($userAgent->getUserAgentType() === UserAgentEntity::USER_AGENT_TYPE_HUMAN
  87. || $statisticsClicks->getUserAgentType() === UserAgentEntity::USER_AGENT_TYPE_MACHINE)
  88. ) {
  89. $statisticsClicks->setUserAgent($userAgent);
  90. $statisticsClicks->setUserAgentType($userAgent->getUserAgentType());
  91. }
  92. $this->statisticsClicksRepository->flush();
  93. $this->sendRevenueCookie($statisticsClicks);
  94. $this->sendAbandonedCartCookie($subscriber);
  95. // track open event
  96. $this->opens->track($data, $displayImage = false);
  97. // Update engagement date
  98. $this->subscribersRepository->maybeUpdateLastEngagement($subscriber, $userAgent ?? null);
  99. }
  100. $url = $this->processUrl($link->getUrl(), $newsletter, $subscriber, $queue, $wpUserPreview);
  101. $this->redirectToUrl($url);
  102. }
  103. private function sendRevenueCookie(StatisticsClickEntity $clicks) {
  104. if ($this->settingsController->get('woocommerce.accept_cookie_revenue_tracking.enabled')) {
  105. $this->cookies->set(
  106. self::REVENUE_TRACKING_COOKIE_NAME,
  107. [
  108. 'statistics_clicks' => $clicks->getId(),
  109. 'created_at' => time(),
  110. ],
  111. [
  112. 'expires' => time() + self::REVENUE_TRACKING_COOKIE_EXPIRY,
  113. 'path' => '/',
  114. ]
  115. );
  116. }
  117. }
  118. private function sendAbandonedCartCookie($subscriber) {
  119. if ($this->settingsController->get('woocommerce.accept_cookie_revenue_tracking.enabled')) {
  120. $this->cookies->set(
  121. self::ABANDONED_CART_COOKIE_NAME,
  122. [
  123. 'subscriber_id' => $subscriber->getId(),
  124. ],
  125. [
  126. 'expires' => time() + self::ABANDONED_CART_COOKIE_EXPIRY,
  127. 'path' => '/',
  128. ]
  129. );
  130. }
  131. }
  132. public function processUrl(
  133. string $url,
  134. NewsletterEntity $newsletter,
  135. SubscriberEntity $subscriber,
  136. SendingQueueEntity $queue,
  137. bool $wpUserPreview
  138. ) {
  139. if (preg_match('/\[link:(?P<action>.*?)\]/', $url, $shortcode)) {
  140. if (!$shortcode['action']) $this->abort();
  141. $url = $this->linkShortcodeCategory->processShortcodeAction(
  142. $shortcode['action'],
  143. $newsletter,
  144. $subscriber,
  145. $queue,
  146. $wpUserPreview
  147. );
  148. } else {
  149. $this->shortcodes->setQueue($queue);
  150. $this->shortcodes->setNewsletter($newsletter);
  151. $this->shortcodes->setSubscriber($subscriber);
  152. $this->shortcodes->setWpUserPreview($wpUserPreview);
  153. $url = $this->shortcodes->replace($url);
  154. }
  155. return $url;
  156. }
  157. public function abort() {
  158. global $wp_query;// phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
  159. WPFunctions::get()->statusHeader(404);
  160. $wp_query->set_404();// phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
  161. WPFunctions::get()->getTemplatePart((string)404);
  162. exit;
  163. }
  164. public function redirectToUrl($url) {
  165. header('Location: ' . $url, true, 302);
  166. exit;
  167. }
  168. }