Нет описания

Populator.php 30KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906
  1. <?php
  2. namespace MailPoet\Config;
  3. if (!defined('ABSPATH')) exit;
  4. use MailPoet\Cron\CronTrigger;
  5. use MailPoet\Cron\Workers\AuthorizedSendingEmailsCheck;
  6. use MailPoet\Cron\Workers\Beamer;
  7. use MailPoet\Cron\Workers\InactiveSubscribers;
  8. use MailPoet\Cron\Workers\StatsNotifications\Worker;
  9. use MailPoet\Cron\Workers\SubscriberLinkTokens;
  10. use MailPoet\Cron\Workers\SubscribersLastEngagement;
  11. use MailPoet\Cron\Workers\UnsubscribeTokens;
  12. use MailPoet\Entities\FormEntity;
  13. use MailPoet\Entities\NewsletterEntity;
  14. use MailPoet\Entities\ScheduledTaskEntity;
  15. use MailPoet\Entities\SendingQueueEntity;
  16. use MailPoet\Entities\StatisticsFormEntity;
  17. use MailPoet\Entities\UserFlagEntity;
  18. use MailPoet\Form\FormsRepository;
  19. use MailPoet\Mailer\MailerLog;
  20. use MailPoet\Models\Newsletter;
  21. use MailPoet\Models\NewsletterLink;
  22. use MailPoet\Models\ScheduledTask;
  23. use MailPoet\Models\Segment;
  24. use MailPoet\Models\SendingQueue;
  25. use MailPoet\Models\Subscriber;
  26. use MailPoet\Referrals\ReferralDetector;
  27. use MailPoet\Segments\WP;
  28. use MailPoet\Services\Bridge;
  29. use MailPoet\Settings\Pages;
  30. use MailPoet\Settings\SettingsController;
  31. use MailPoet\Settings\UserFlagsRepository;
  32. use MailPoet\Subscribers\NewSubscriberNotificationMailer;
  33. use MailPoet\Subscribers\Source;
  34. use MailPoet\Subscription\Captcha;
  35. use MailPoet\Util\Helpers;
  36. use MailPoet\WP\Functions as WPFunctions;
  37. use MailPoetVendor\Carbon\Carbon;
  38. use MailPoetVendor\Doctrine\ORM\EntityManager;
  39. class Populator {
  40. public $prefix;
  41. public $models;
  42. public $templates;
  43. /** @var SettingsController */
  44. private $settings;
  45. /** @var WPFunctions */
  46. private $wp;
  47. /** @var Captcha */
  48. private $captcha;
  49. /** @var ReferralDetector */
  50. private $referralDetector;
  51. const TEMPLATES_NAMESPACE = '\MailPoet\Config\PopulatorData\Templates\\';
  52. /** @var FormsRepository */
  53. private $formsRepository;
  54. /** @var WP */
  55. private $wpSegment;
  56. /** @var EntityManager */
  57. private $entityManager;
  58. public function __construct(
  59. SettingsController $settings,
  60. WPFunctions $wp,
  61. Captcha $captcha,
  62. ReferralDetector $referralDetector,
  63. FormsRepository $formsRepository,
  64. EntityManager $entityManager,
  65. WP $wpSegment
  66. ) {
  67. $this->settings = $settings;
  68. $this->wp = $wp;
  69. $this->captcha = $captcha;
  70. $this->wpSegment = $wpSegment;
  71. $this->referralDetector = $referralDetector;
  72. $this->prefix = Env::$dbPrefix;
  73. $this->models = [
  74. 'newsletter_option_fields',
  75. 'newsletter_templates',
  76. ];
  77. $this->templates = [
  78. 'WelcomeBlank1Column',
  79. 'WelcomeBlank12Column',
  80. 'GiftWelcome',
  81. 'Minimal',
  82. 'Phone',
  83. 'Sunglasses',
  84. 'RealEstate',
  85. 'AppWelcome',
  86. 'FoodBox',
  87. 'Poet',
  88. 'PostNotificationsBlank1Column',
  89. 'ModularStyleStories',
  90. 'RssSimpleNews',
  91. 'NotSoMedium',
  92. 'WideStoryLayout',
  93. 'IndustryConference',
  94. 'ScienceWeekly',
  95. 'NewspaperTraditional',
  96. 'ClearNews',
  97. 'DogFood',
  98. 'KidsClothing',
  99. 'RockBand',
  100. 'WineCity',
  101. 'Fitness',
  102. 'Motor',
  103. 'Avocado',
  104. 'BookStoreWithCoupon',
  105. 'FlowersWithCoupon',
  106. 'NewsletterBlank1Column',
  107. 'NewsletterBlank12Column',
  108. 'NewsletterBlank121Column',
  109. 'NewsletterBlank13Column',
  110. 'SimpleText',
  111. 'TakeAHike',
  112. 'NewsDay',
  113. 'WorldCup',
  114. 'FestivalEvent',
  115. 'RetroComputingMagazine',
  116. 'Shoes',
  117. 'Music',
  118. 'Hotels',
  119. 'PieceOfCake',
  120. 'BuddhistTemple',
  121. 'Mosque',
  122. 'Synagogue',
  123. 'Faith',
  124. 'College',
  125. 'RenewableEnergy',
  126. 'PrimarySchool',
  127. 'ComputerRepair',
  128. 'YogaStudio',
  129. 'Retro',
  130. 'Charity',
  131. 'CityLocalNews',
  132. 'Coffee',
  133. 'Vlogger',
  134. 'Birds',
  135. 'Engineering',
  136. 'BrandingAgencyNews',
  137. 'WordPressTheme',
  138. 'Drone',
  139. 'FashionBlog',
  140. 'FashionStore',
  141. 'FashionBlogA',
  142. 'Photography',
  143. 'JazzClub',
  144. 'Guitarist',
  145. 'HealthyFoodBlog',
  146. 'Software',
  147. 'LifestyleBlogA',
  148. 'FashionShop',
  149. 'LifestyleBlogB',
  150. 'Painter',
  151. 'FarmersMarket',
  152. ];
  153. $this->formsRepository = $formsRepository;
  154. $this->entityManager = $entityManager;
  155. }
  156. public function up() {
  157. $localizer = new Localizer();
  158. $localizer->forceLoadWebsiteLocaleText();
  159. array_map([$this, 'populate'], $this->models);
  160. $this->createDefaultSegment();
  161. $this->createDefaultSettings();
  162. $this->createDefaultUsersFlags();
  163. $this->createMailPoetPage();
  164. $this->createSourceForSubscribers();
  165. $this->updateMetaFields();
  166. $this->scheduleInitialInactiveSubscribersCheck();
  167. $this->scheduleAuthorizedSendingEmailsCheck();
  168. $this->scheduleBeamer();
  169. $this->updateLastSubscribedAt();
  170. $this->enableStatsNotificationsForAutomatedEmails();
  171. $this->updateSentUnsubscribeLinksToInstantUnsubscribeLinks();
  172. $this->pauseTasksForPausedNewsletters();
  173. $this->scheduleUnsubscribeTokens();
  174. $this->scheduleSubscriberLinkTokens();
  175. $this->detectReferral();
  176. $this->moveGoogleAnalyticsFromPremium();
  177. $this->addPlacementStatusToForms();
  178. $this->migrateFormPlacement();
  179. $this->scheduleSubscriberLastEngagementDetection();
  180. }
  181. private function createMailPoetPage() {
  182. $page = Pages::getDefaultMailPoetPage();
  183. if ($page === null) {
  184. $mailpoetPageId = Pages::createMailPoetPage();
  185. } else {
  186. $mailpoetPageId = (int)$page->ID;
  187. }
  188. $subscription = $this->settings->get('subscription.pages', []);
  189. if (empty($subscription)) {
  190. $this->settings->set('subscription.pages', [
  191. 'unsubscribe' => $mailpoetPageId,
  192. 'manage' => $mailpoetPageId,
  193. 'confirmation' => $mailpoetPageId,
  194. 'captcha' => $mailpoetPageId,
  195. 'confirm_unsubscribe' => $mailpoetPageId,
  196. ]);
  197. } else {
  198. // For existing installations
  199. $captchaPageSetting = (empty($subscription['captcha']) || $subscription['captcha'] !== $mailpoetPageId)
  200. ? $mailpoetPageId : $subscription['captcha'];
  201. $confirmUnsubPageSetting = empty($subscription['confirm_unsubscribe'])
  202. ? $mailpoetPageId : $subscription['confirm_unsubscribe'];
  203. $this->settings->set('subscription.pages', array_merge($subscription, [
  204. 'captcha' => $captchaPageSetting,
  205. 'confirm_unsubscribe' => $confirmUnsubPageSetting,
  206. ]));
  207. }
  208. }
  209. private function createDefaultSettings() {
  210. $currentUser = $this->wp->wpGetCurrentUser();
  211. $settingsDbVersion = $this->settings->fetch('db_version');
  212. // set cron trigger option to default method
  213. if (!$this->settings->fetch(CronTrigger::SETTING_NAME)) {
  214. $this->settings->set(CronTrigger::SETTING_NAME, [
  215. 'method' => CronTrigger::DEFAULT_METHOD,
  216. ]);
  217. }
  218. // set default sender info based on current user
  219. $sender = [
  220. 'name' => $currentUser->display_name, // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
  221. 'address' => $currentUser->user_email, // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
  222. ];
  223. // set default from name & address
  224. if (!$this->settings->fetch('sender')) {
  225. $this->settings->set('sender', $sender);
  226. }
  227. // enable signup confirmation by default
  228. if (!$this->settings->fetch('signup_confirmation')) {
  229. $this->settings->set('signup_confirmation', [
  230. 'enabled' => true,
  231. ]);
  232. }
  233. // set installation date
  234. if (!$this->settings->fetch('installed_at')) {
  235. $this->settings->set('installed_at', date("Y-m-d H:i:s"));
  236. }
  237. // set captcha settings
  238. $captcha = $this->settings->fetch('captcha');
  239. $reCaptcha = $this->settings->fetch('re_captcha');
  240. if (empty($captcha)) {
  241. $captchaType = Captcha::TYPE_DISABLED;
  242. if (!empty($reCaptcha['enabled'])) {
  243. $captchaType = Captcha::TYPE_RECAPTCHA;
  244. } elseif ($this->captcha->isSupported()) {
  245. $captchaType = Captcha::TYPE_BUILTIN;
  246. }
  247. $this->settings->set('captcha', [
  248. 'type' => $captchaType,
  249. 'recaptcha_site_token' => !empty($reCaptcha['site_token']) ? $reCaptcha['site_token'] : '',
  250. 'recaptcha_secret_token' => !empty($reCaptcha['secret_token']) ? $reCaptcha['secret_token'] : '',
  251. ]);
  252. }
  253. $subscriberEmailNotification = $this->settings->fetch(NewSubscriberNotificationMailer::SETTINGS_KEY);
  254. if (empty($subscriberEmailNotification)) {
  255. $sender = $this->settings->fetch('sender', []);
  256. $this->settings->set('subscriber_email_notification', [
  257. 'enabled' => true,
  258. 'automated' => true,
  259. 'address' => isset($sender['address']) ? $sender['address'] : null,
  260. ]);
  261. }
  262. $statsNotifications = $this->settings->fetch(Worker::SETTINGS_KEY);
  263. if (empty($statsNotifications)) {
  264. $sender = $this->settings->fetch('sender', []);
  265. $this->settings->set(Worker::SETTINGS_KEY, [
  266. 'enabled' => true,
  267. 'address' => isset($sender['address']) ? $sender['address'] : null,
  268. ]);
  269. }
  270. $woocommerceOptinOnCheckout = $this->settings->fetch('woocommerce.optin_on_checkout');
  271. $legacyLabelText = $this->wp->_x('Yes, I would like to be added to your mailing list', "default email opt-in message displayed on checkout page for ecommerce websites", 'mailpoet');
  272. $currentLabelText = $this->wp->_x('I would like to receive exclusive emails with discounts and product information', "default email opt-in message displayed on checkout page for ecommerce websites", 'mailpoet');
  273. if (empty($woocommerceOptinOnCheckout)) {
  274. $this->settings->set('woocommerce.optin_on_checkout', [
  275. 'enabled' => empty($settingsDbVersion), // enable on new installs only
  276. 'message' => $currentLabelText,
  277. ]);
  278. } elseif (isset($woocommerceOptinOnCheckout['message']) && $woocommerceOptinOnCheckout['message'] === $legacyLabelText ) {
  279. $this->settings->set('woocommerce.optin_on_checkout.message', $currentLabelText);
  280. }
  281. // reset mailer log
  282. MailerLog::resetMailerLog();
  283. $thirdPartyScriptsEnabled = $this->settings->get('3rd_party_libs');
  284. if (is_null($thirdPartyScriptsEnabled)) {
  285. // keep loading 3rd party libraries for existing users so the functionality is not broken
  286. $this->settings->set('3rd_party_libs.enabled', '1');
  287. }
  288. }
  289. private function createDefaultUsersFlags() {
  290. $lastAnnouncementSeen = $this->settings->fetch('last_announcement_seen');
  291. if (!empty($lastAnnouncementSeen)) {
  292. foreach ($lastAnnouncementSeen as $userId => $value) {
  293. $this->createOrUpdateUserFlag($userId, 'last_announcement_seen', $value);
  294. }
  295. $this->settings->delete('last_announcement_seen');
  296. }
  297. $prefix = 'user_seen_editor_tutorial';
  298. $prefixLength = strlen($prefix);
  299. foreach ($this->settings->getAll() as $name => $value) {
  300. if (substr($name, 0, $prefixLength) === $prefix) {
  301. $userId = substr($name, $prefixLength);
  302. $this->createOrUpdateUserFlag($userId, 'editor_tutorial_seen', $value);
  303. $this->settings->delete($name);
  304. }
  305. }
  306. }
  307. private function createOrUpdateUserFlag($userId, $name, $value) {
  308. $userFlagsRepository = \MailPoet\DI\ContainerWrapper::getInstance(WP_DEBUG)->get(UserFlagsRepository::class);
  309. $flag = $userFlagsRepository->findOneBy([
  310. 'userId' => $userId,
  311. 'name' => $name,
  312. ]);
  313. if (!$flag) {
  314. $flag = new UserFlagEntity();
  315. $flag->setUserId($userId);
  316. $flag->setName($name);
  317. $userFlagsRepository->persist($flag);
  318. }
  319. $flag->setValue($value);
  320. $userFlagsRepository->flush();
  321. }
  322. private function createDefaultSegment() {
  323. // WP Users segment
  324. Segment::getWPSegment();
  325. // WooCommerce customers segment
  326. Segment::getWooCommerceSegment();
  327. // Synchronize WP Users
  328. $this->wpSegment->synchronizeUsers();
  329. // Default segment
  330. $defaultSegment = Segment::where('type', 'default')->orderByAsc('id')->limit(1)->findOne();
  331. if (!$defaultSegment instanceof Segment) {
  332. $defaultSegment = Segment::create();
  333. $newList = [
  334. 'name' => $this->wp->__('Newsletter mailing list', 'mailpoet'),
  335. 'description' =>
  336. $this->wp->__('This list is automatically created when you install MailPoet.', 'mailpoet'),
  337. ];
  338. $defaultSegment->hydrate($newList);
  339. $defaultSegment->save();
  340. }
  341. return $defaultSegment;
  342. }
  343. protected function newsletterOptionFields() {
  344. $optionFields = [
  345. [
  346. 'name' => 'isScheduled',
  347. 'newsletter_type' => 'standard',
  348. ],
  349. [
  350. 'name' => 'scheduledAt',
  351. 'newsletter_type' => 'standard',
  352. ],
  353. [
  354. 'name' => 'event',
  355. 'newsletter_type' => 'welcome',
  356. ],
  357. [
  358. 'name' => 'segment',
  359. 'newsletter_type' => 'welcome',
  360. ],
  361. [
  362. 'name' => 'role',
  363. 'newsletter_type' => 'welcome',
  364. ],
  365. [
  366. 'name' => 'afterTimeNumber',
  367. 'newsletter_type' => 'welcome',
  368. ],
  369. [
  370. 'name' => 'afterTimeType',
  371. 'newsletter_type' => 'welcome',
  372. ],
  373. [
  374. 'name' => 'intervalType',
  375. 'newsletter_type' => 'notification',
  376. ],
  377. [
  378. 'name' => 'timeOfDay',
  379. 'newsletter_type' => 'notification',
  380. ],
  381. [
  382. 'name' => 'weekDay',
  383. 'newsletter_type' => 'notification',
  384. ],
  385. [
  386. 'name' => 'monthDay',
  387. 'newsletter_type' => 'notification',
  388. ],
  389. [
  390. 'name' => 'nthWeekDay',
  391. 'newsletter_type' => 'notification',
  392. ],
  393. [
  394. 'name' => 'schedule',
  395. 'newsletter_type' => 'notification',
  396. ],
  397. [
  398. 'name' => 'group',
  399. 'newsletter_type' => NewsletterEntity::TYPE_AUTOMATIC,
  400. ],
  401. [
  402. 'name' => 'event',
  403. 'newsletter_type' => NewsletterEntity::TYPE_AUTOMATIC,
  404. ],
  405. [
  406. 'name' => 'sendTo',
  407. 'newsletter_type' => NewsletterEntity::TYPE_AUTOMATIC,
  408. ],
  409. [
  410. 'name' => 'segment',
  411. 'newsletter_type' => NewsletterEntity::TYPE_AUTOMATIC,
  412. ],
  413. [
  414. 'name' => 'afterTimeNumber',
  415. 'newsletter_type' => NewsletterEntity::TYPE_AUTOMATIC,
  416. ],
  417. [
  418. 'name' => 'afterTimeType',
  419. 'newsletter_type' => NewsletterEntity::TYPE_AUTOMATIC,
  420. ],
  421. [
  422. 'name' => 'meta',
  423. 'newsletter_type' => NewsletterEntity::TYPE_AUTOMATIC,
  424. ],
  425. [
  426. 'name' => 'afterTimeNumber',
  427. 'newsletter_type' => NewsletterEntity::TYPE_RE_ENGAGEMENT,
  428. ],
  429. [
  430. 'name' => 'afterTimeType',
  431. 'newsletter_type' => NewsletterEntity::TYPE_RE_ENGAGEMENT,
  432. ],
  433. ];
  434. return [
  435. 'rows' => $optionFields,
  436. 'identification_columns' => [
  437. 'name',
  438. 'newsletter_type',
  439. ],
  440. ];
  441. }
  442. protected function newsletterTemplates() {
  443. $templates = [];
  444. foreach ($this->templates as $template) {
  445. $template = self::TEMPLATES_NAMESPACE . $template;
  446. $template = new $template(Env::$assetsUrl);
  447. $templates[] = $template->get();
  448. }
  449. return [
  450. 'rows' => $templates,
  451. 'identification_columns' => [
  452. 'name',
  453. ],
  454. 'remove_duplicates' => true,
  455. ];
  456. }
  457. protected function populate($model) {
  458. $modelMethod = Helpers::underscoreToCamelCase($model);
  459. $table = $this->prefix . $model;
  460. $dataDescriptor = $this->$modelMethod();
  461. $rows = $dataDescriptor['rows'];
  462. $identificationColumns = array_fill_keys(
  463. $dataDescriptor['identification_columns'],
  464. ''
  465. );
  466. $removeDuplicates =
  467. isset($dataDescriptor['remove_duplicates']) && $dataDescriptor['remove_duplicates'];
  468. foreach ($rows as $row) {
  469. $existenceComparisonFields = array_intersect_key(
  470. $row,
  471. $identificationColumns
  472. );
  473. if (!$this->rowExists($table, $existenceComparisonFields)) {
  474. $this->insertRow($table, $row);
  475. } else {
  476. if ($removeDuplicates) {
  477. $this->removeDuplicates($table, $row, $existenceComparisonFields);
  478. }
  479. $this->updateRow($table, $row, $existenceComparisonFields);
  480. }
  481. }
  482. }
  483. private function rowExists($table, $columns) {
  484. global $wpdb;
  485. $conditions = array_map(function($key) {
  486. return $key . '=%s';
  487. }, array_keys($columns));
  488. return $wpdb->get_var($wpdb->prepare(
  489. "SELECT COUNT(*) FROM $table WHERE " . implode(' AND ', $conditions),
  490. array_values($columns)
  491. )) > 0;
  492. }
  493. private function insertRow($table, $row) {
  494. global $wpdb;
  495. return $wpdb->insert(
  496. $table,
  497. $row
  498. );
  499. }
  500. private function updateRow($table, $row, $where) {
  501. global $wpdb;
  502. return $wpdb->update(
  503. $table,
  504. $row,
  505. $where
  506. );
  507. }
  508. private function removeDuplicates($table, $row, $where) {
  509. global $wpdb;
  510. $conditions = ['1=1'];
  511. $values = [];
  512. foreach ($where as $field => $value) {
  513. $conditions[] = "`t1`.`$field` = `t2`.`$field`";
  514. $conditions[] = "`t1`.`$field` = %s";
  515. $values[] = $value;
  516. }
  517. $conditions = implode(' AND ', $conditions);
  518. $sql = "DELETE FROM `$table` WHERE $conditions";
  519. return $wpdb->query(
  520. $wpdb->prepare(
  521. "DELETE t1 FROM $table t1, $table t2 WHERE t1.id < t2.id AND $conditions",
  522. $values
  523. )
  524. );
  525. }
  526. private function createSourceForSubscribers() {
  527. $statisticsFormTable = $this->entityManager->getClassMetadata(StatisticsFormEntity::class)->getTableName();
  528. Subscriber::rawExecute(
  529. ' UPDATE LOW_PRIORITY `' . Subscriber::$_table . '` subscriber ' .
  530. ' JOIN `' . $statisticsFormTable . '` stats ON stats.subscriber_id=subscriber.id ' .
  531. ' SET `source` = "' . Source::FORM . '"' .
  532. ' WHERE `source` = "' . Source::UNKNOWN . '"'
  533. );
  534. Subscriber::rawExecute(
  535. 'UPDATE LOW_PRIORITY `' . Subscriber::$_table . '`' .
  536. ' SET `source` = "' . Source::WORDPRESS_USER . '"' .
  537. ' WHERE `source` = "' . Source::UNKNOWN . '"' .
  538. ' AND `wp_user_id` IS NOT NULL'
  539. );
  540. Subscriber::rawExecute(
  541. 'UPDATE LOW_PRIORITY `' . Subscriber::$_table . '`' .
  542. ' SET `source` = "' . Source::WOOCOMMERCE_USER . '"' .
  543. ' WHERE `source` = "' . Source::UNKNOWN . '"' .
  544. ' AND `is_woocommerce_user` = 1'
  545. );
  546. }
  547. private function updateMetaFields() {
  548. global $wpdb;
  549. // perform once for versions below or equal to 3.26.0
  550. if (version_compare($this->settings->get('db_version', '3.26.1'), '3.26.0', '>')) {
  551. return false;
  552. }
  553. $tables = [ScheduledTask::$_table, SendingQueue::$_table];
  554. foreach ($tables as $table) {
  555. $query = "UPDATE `%s` SET meta = NULL WHERE meta = 'null'";
  556. $wpdb->query(sprintf($query, $table));
  557. }
  558. return true;
  559. }
  560. private function scheduleInitialInactiveSubscribersCheck() {
  561. $this->scheduleTask(
  562. InactiveSubscribers::TASK_TYPE,
  563. Carbon::createFromTimestamp($this->wp->currentTime('timestamp'))->addHour()
  564. );
  565. }
  566. private function scheduleAuthorizedSendingEmailsCheck() {
  567. if (!Bridge::isMPSendingServiceEnabled()) {
  568. return;
  569. }
  570. $this->scheduleTask(
  571. AuthorizedSendingEmailsCheck::TASK_TYPE,
  572. Carbon::createFromTimestamp($this->wp->currentTime('timestamp'))
  573. );
  574. }
  575. private function scheduleBeamer() {
  576. if (!$this->settings->get('last_announcement_date')) {
  577. $this->scheduleTask(
  578. Beamer::TASK_TYPE,
  579. Carbon::createFromTimestamp($this->wp->currentTime('timestamp'))
  580. );
  581. }
  582. }
  583. private function updateLastSubscribedAt() {
  584. global $wpdb;
  585. // perform once for versions below or equal to 3.42.0
  586. if (version_compare($this->settings->get('db_version', '3.42.1'), '3.42.0', '>')) {
  587. return false;
  588. }
  589. $query = "UPDATE `%s` SET last_subscribed_at = GREATEST(COALESCE(confirmed_at, 0), COALESCE(created_at, 0)) WHERE status != '%s' AND last_subscribed_at IS NULL;";
  590. $wpdb->query(sprintf(
  591. $query,
  592. Subscriber::$_table,
  593. Subscriber::STATUS_UNCONFIRMED
  594. ));
  595. return true;
  596. }
  597. private function scheduleUnsubscribeTokens() {
  598. $this->scheduleTask(
  599. UnsubscribeTokens::TASK_TYPE,
  600. Carbon::createFromTimestamp($this->wp->currentTime('timestamp'))
  601. );
  602. }
  603. private function scheduleSubscriberLinkTokens() {
  604. $this->scheduleTask(
  605. SubscriberLinkTokens::TASK_TYPE,
  606. Carbon::createFromTimestamp($this->wp->currentTime('timestamp'))
  607. );
  608. }
  609. private function scheduleTask($type, $datetime) {
  610. $task = ScheduledTask::where('type', $type)
  611. ->whereRaw('status = ? OR status IS NULL', [ScheduledTask::STATUS_SCHEDULED])
  612. ->findOne();
  613. if ($task) {
  614. return true;
  615. }
  616. $task = ScheduledTask::create();
  617. $task->type = $type;
  618. $task->status = ScheduledTask::STATUS_SCHEDULED;
  619. $task->scheduledAt = $datetime;
  620. $task->save();
  621. }
  622. private function enableStatsNotificationsForAutomatedEmails() {
  623. if (version_compare($this->settings->get('db_version', '3.31.2'), '3.31.1', '>')) {
  624. return;
  625. }
  626. $settings = $this->settings->get(Worker::SETTINGS_KEY);
  627. $settings['automated'] = true;
  628. $this->settings->set(Worker::SETTINGS_KEY, $settings);
  629. }
  630. private function updateSentUnsubscribeLinksToInstantUnsubscribeLinks() {
  631. if (version_compare($this->settings->get('db_version', '3.46.14'), '3.46.13', '>')) {
  632. return;
  633. }
  634. $query = "UPDATE `%s` SET `url` = '%s' WHERE `url` = '%s';";
  635. global $wpdb;
  636. $wpdb->query(sprintf(
  637. $query,
  638. NewsletterLink::$_table,
  639. NewsletterLink::INSTANT_UNSUBSCRIBE_LINK_SHORT_CODE,
  640. NewsletterLink::UNSUBSCRIBE_LINK_SHORT_CODE
  641. ));
  642. }
  643. private function pauseTasksForPausedNewsletters() {
  644. if (version_compare($this->settings->get('db_version', '3.60.5'), '3.60.4', '>')) {
  645. return;
  646. }
  647. $scheduledTaskTable = $this->entityManager->getClassMetadata(ScheduledTaskEntity::class)->getTableName();
  648. $sendingQueueTable = $this->entityManager->getClassMetadata(SendingQueueEntity::class)->getTableName();
  649. $newsletterTable = $this->entityManager->getClassMetadata(NewsletterEntity::class)->getTableName();
  650. $query = "
  651. UPDATE $scheduledTaskTable as t
  652. JOIN $sendingQueueTable as q ON t.id = q.task_id
  653. JOIN $newsletterTable as n ON n.id = q.newsletter_id
  654. SET t.status = :tStatusPaused
  655. WHERE
  656. t.status = :tStatusScheduled
  657. AND n.status = :nStatusDraft
  658. ";
  659. $this->entityManager->getConnection()->executeUpdate(
  660. $query,
  661. [
  662. 'tStatusPaused' => ScheduledTaskEntity::STATUS_PAUSED,
  663. 'tStatusScheduled' => ScheduledTaskEntity::STATUS_SCHEDULED,
  664. 'nStatusDraft' => NewsletterEntity::STATUS_DRAFT,
  665. ]
  666. );
  667. }
  668. private function addPlacementStatusToForms() {
  669. if (version_compare($this->settings->get('db_version', '3.49.0'), '3.48.1', '>')) {
  670. return;
  671. }
  672. $forms = $this->formsRepository->findAll();
  673. foreach ($forms as $form) {
  674. $settings = $form->getSettings();
  675. if (
  676. (isset($settings['place_form_bellow_all_posts']) && $settings['place_form_bellow_all_posts'] === '1')
  677. || (isset($settings['place_form_bellow_all_pages']) && $settings['place_form_bellow_all_pages'] === '1')
  678. ) {
  679. $settings['form_placement_bellow_posts_enabled'] = '1';
  680. } else {
  681. $settings['form_placement_bellow_posts_enabled'] = '';
  682. }
  683. if (
  684. (isset($settings['place_popup_form_on_all_posts']) && $settings['place_popup_form_on_all_posts'] === '1')
  685. || (isset($settings['place_popup_form_on_all_pages']) && $settings['place_popup_form_on_all_pages'] === '1')
  686. ) {
  687. $settings['form_placement_popup_enabled'] = '1';
  688. } else {
  689. $settings['form_placement_popup_enabled'] = '';
  690. }
  691. if (
  692. (isset($settings['place_fixed_bar_form_on_all_posts']) && $settings['place_fixed_bar_form_on_all_posts'] === '1')
  693. || (isset($settings['place_fixed_bar_form_on_all_pages']) && $settings['place_fixed_bar_form_on_all_pages'] === '1')
  694. ) {
  695. $settings['form_placement_fixed_bar_enabled'] = '1';
  696. } else {
  697. $settings['form_placement_fixed_bar_enabled'] = '';
  698. }
  699. if (
  700. (isset($settings['place_slide_in_form_on_all_posts']) && $settings['place_slide_in_form_on_all_posts'] === '1')
  701. || (isset($settings['place_slide_in_form_on_all_pages']) && $settings['place_slide_in_form_on_all_pages'] === '1')
  702. ) {
  703. $settings['form_placement_slide_in_enabled'] = '1';
  704. } else {
  705. $settings['form_placement_slide_in_enabled'] = '';
  706. }
  707. $form->setSettings($settings);
  708. }
  709. $this->formsRepository->flush();
  710. }
  711. private function migrateFormPlacement() {
  712. if (version_compare($this->settings->get('db_version', '3.50.0'), '3.49.1', '>')) {
  713. return;
  714. }
  715. $forms = $this->formsRepository->findAll();
  716. foreach ($forms as $form) {
  717. $settings = $form->getSettings();
  718. if (!is_array($settings)) continue;
  719. $settings['form_placement'] = [
  720. FormEntity::DISPLAY_TYPE_POPUP => [
  721. 'enabled' => $settings['form_placement_popup_enabled'],
  722. 'delay' => $settings['popup_form_delay'] ?? 0,
  723. 'styles' => $settings['popup_styles'] ?? [],
  724. 'posts' => [
  725. 'all' => $settings['place_popup_form_on_all_posts'] ?? '',
  726. ],
  727. 'pages' => [
  728. 'all' => $settings['place_popup_form_on_all_pages'] ?? '',
  729. ],
  730. ],
  731. FormEntity::DISPLAY_TYPE_FIXED_BAR => [
  732. 'enabled' => $settings['form_placement_fixed_bar_enabled'],
  733. 'delay' => $settings['fixed_bar_form_delay'] ?? 0,
  734. 'styles' => $settings['fixed_bar_styles'] ?? [],
  735. 'position' => $settings['fixed_bar_form_position'] ?? 'top',
  736. 'posts' => [
  737. 'all' => $settings['place_fixed_bar_form_on_all_posts'] ?? '',
  738. ],
  739. 'pages' => [
  740. 'all' => $settings['place_fixed_bar_form_on_all_pages'] ?? '',
  741. ],
  742. ],
  743. FormEntity::DISPLAY_TYPE_BELOW_POST => [
  744. 'enabled' => $settings['form_placement_bellow_posts_enabled'],
  745. 'styles' => $settings['below_post_styles'] ?? [],
  746. 'posts' => [
  747. 'all' => $settings['place_form_bellow_all_posts'] ?? '',
  748. ],
  749. 'pages' => [
  750. 'all' => $settings['place_form_bellow_all_pages'] ?? '',
  751. ],
  752. ],
  753. FormEntity::DISPLAY_TYPE_SLIDE_IN => [
  754. 'enabled' => $settings['form_placement_slide_in_enabled'],
  755. 'delay' => $settings['slide_in_form_delay'] ?? 0,
  756. 'position' => $settings['slide_in_form_position'] ?? 'right',
  757. 'styles' => $settings['slide_in_styles'] ?? [],
  758. 'posts' => [
  759. 'all' => $settings['place_slide_in_form_on_all_posts'] ?? '',
  760. ],
  761. 'pages' => [
  762. 'all' => $settings['place_slide_in_form_on_all_pages'] ?? '',
  763. ],
  764. ],
  765. FormEntity::DISPLAY_TYPE_OTHERS => [
  766. 'styles' => $settings['other_styles'] ?? [],
  767. ],
  768. ];
  769. if (isset($settings['form_placement_slide_in_enabled'])) unset($settings['form_placement_slide_in_enabled']);
  770. if (isset($settings['form_placement_fixed_bar_enabled'])) unset($settings['form_placement_fixed_bar_enabled']);
  771. if (isset($settings['form_placement_popup_enabled'])) unset($settings['form_placement_popup_enabled']);
  772. if (isset($settings['form_placement_bellow_posts_enabled'])) unset($settings['form_placement_bellow_posts_enabled']);
  773. if (isset($settings['place_form_bellow_all_pages'])) unset($settings['place_form_bellow_all_pages']);
  774. if (isset($settings['place_form_bellow_all_posts'])) unset($settings['place_form_bellow_all_posts']);
  775. if (isset($settings['place_popup_form_on_all_pages'])) unset($settings['place_popup_form_on_all_pages']);
  776. if (isset($settings['place_popup_form_on_all_posts'])) unset($settings['place_popup_form_on_all_posts']);
  777. if (isset($settings['popup_form_delay'])) unset($settings['popup_form_delay']);
  778. if (isset($settings['place_fixed_bar_form_on_all_pages'])) unset($settings['place_fixed_bar_form_on_all_pages']);
  779. if (isset($settings['place_fixed_bar_form_on_all_posts'])) unset($settings['place_fixed_bar_form_on_all_posts']);
  780. if (isset($settings['fixed_bar_form_delay'])) unset($settings['fixed_bar_form_delay']);
  781. if (isset($settings['fixed_bar_form_position'])) unset($settings['fixed_bar_form_position']);
  782. if (isset($settings['place_slide_in_form_on_all_pages'])) unset($settings['place_slide_in_form_on_all_pages']);
  783. if (isset($settings['place_slide_in_form_on_all_posts'])) unset($settings['place_slide_in_form_on_all_posts']);
  784. if (isset($settings['slide_in_form_delay'])) unset($settings['slide_in_form_delay']);
  785. if (isset($settings['slide_in_form_position'])) unset($settings['slide_in_form_position']);
  786. if (isset($settings['other_styles'])) unset($settings['other_styles']);
  787. if (isset($settings['slide_in_styles'])) unset($settings['slide_in_styles']);
  788. if (isset($settings['below_post_styles'])) unset($settings['below_post_styles']);
  789. if (isset($settings['fixed_bar_styles'])) unset($settings['fixed_bar_styles']);
  790. if (isset($settings['popup_styles'])) unset($settings['popup_styles']);
  791. $form->setSettings($settings);
  792. }
  793. $this->formsRepository->flush();
  794. }
  795. private function moveGoogleAnalyticsFromPremium() {
  796. global $wpdb;
  797. if (version_compare($this->settings->get('db_version', '3.38.2'), '3.38.1', '>')) {
  798. return;
  799. }
  800. $premiumTableName = $wpdb->prefix . 'mailpoet_premium_newsletter_extra_data';
  801. $premiumTableExists = (int)$wpdb->get_var(
  802. $wpdb->prepare(
  803. "SELECT COUNT(1) FROM information_schema.tables WHERE table_schema=%s AND table_name=%s;",
  804. $wpdb->dbname,
  805. $premiumTableName
  806. )
  807. );
  808. if ($premiumTableExists) {
  809. $query = "
  810. UPDATE
  811. `%s` as n
  812. JOIN %s as ped ON n.id=ped.newsletter_id
  813. SET n.ga_campaign = ped.ga_campaign
  814. ";
  815. $wpdb->query(
  816. sprintf(
  817. $query,
  818. Newsletter::$_table,
  819. $premiumTableName
  820. )
  821. );
  822. }
  823. return true;
  824. }
  825. private function detectReferral() {
  826. $this->referralDetector->detect();
  827. }
  828. private function scheduleSubscriberLastEngagementDetection() {
  829. if (version_compare($this->settings->get('db_version', '3.68.1'), '3.68.0', '>')) {
  830. return;
  831. }
  832. $this->scheduleTask(
  833. SubscribersLastEngagement::TASK_TYPE,
  834. Carbon::createFromTimestamp($this->wp->currentTime('timestamp'))
  835. );
  836. }
  837. }