PluginProbe ʕ •ᴥ•ʔ
MailPoet – Newsletters, Email Marketing, and Automation / 5.36.0
MailPoet – Newsletters, Email Marketing, and Automation v5.36.0
5.36.0 5.35.1 5.35.0 5.34.3 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 / Migrations / Db / Migration_20230831_143755_Db.php
mailpoet / lib / Migrations / Db Last commit date
Migration_20221028_105818.php 3 months ago Migration_20221110_151621.php 3 years ago Migration_20230111_120000.php 2 years ago Migration_20230111_130000.php 3 years ago Migration_20230215_050813.php 3 months ago Migration_20230221_200520.php 3 years ago Migration_20230421_135915.php 3 years ago Migration_20230503_210945.php 3 years ago Migration_20230605_174836.php 3 years ago Migration_20230703_105957.php 3 years ago Migration_20230716_130221_Db.php 2 years ago Migration_20230824_054259_Db.php 2 years ago Migration_20230831_124214_Db.php 2 years ago Migration_20230831_143755_Db.php 1 year ago Migration_20240119_113943_Db.php 2 years ago Migration_20240617_122847_Db.php 2 years ago Migration_20240725_182318_Db.php 2 years ago Migration_20241007_170437_Db.php 1 year ago Migration_20241108_103249_Db.php 3 months ago Migration_20250903_151331_Db.php 11 months ago Migration_20250926_153050_Db.php 10 months ago Migration_20260415_090055_Db.php 3 months ago Migration_20260427_100000.php 3 months ago Migration_20260428_120000.php 3 months ago Migration_20260430_103000_Db.php 3 months ago Migration_20260430_120000.php 3 months ago Migration_20260504_120000_Db.php 3 months ago Migration_20260514_120000_Db.php 3 months ago Migration_20260609_120000_Db.php 2 months ago Migration_20260610_120000_Db.php 1 month ago Migration_20260622_120000_Db.php 1 month ago Migration_20260709_120000_Db.php 1 month ago Migration_20260715_100000_Db.php 1 month ago index.php 3 years ago
Migration_20230831_143755_Db.php
151 lines
1 <?php declare(strict_types = 1);
2
3 namespace MailPoet\Migrations\Db;
4
5 if (!defined('ABSPATH')) exit;
6
7
8 use MailPoet\Doctrine\WPDB\Connection;
9 use MailPoet\Migrator\DbMigration;
10
11 class Migration_20230831_143755_Db extends DbMigration {
12 public function run(): void {
13 global $wpdb;
14 $logsTable = $wpdb->prefix . 'mailpoet_automation_run_logs';
15
16 // add "updated_at" column
17 if (!$this->columnExists($logsTable, 'updated_at')) {
18 $this->connection->executeStatement("ALTER TABLE $logsTable CHANGE `started_at` `started_at` timestamp NULL"); // prevent ER_TOO_MUCH_AUTO_TIMESTAMP_COLS
19 $this->connection->executeStatement("ALTER TABLE $logsTable ADD COLUMN updated_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP AFTER `started_at`");
20 }
21
22 // add "step_type" column
23 if (!$this->columnExists($logsTable, 'step_type')) {
24 $this->connection->executeStatement("ALTER TABLE $logsTable ADD COLUMN step_type VARCHAR(255) NOT NULL DEFAULT 'action' AFTER `step_id`");
25
26 // Temporarily use a full column definition to drop default in WP Playground.
27 // DROP DEFAULT is not yet supported by the SQLite integration.
28 if (Connection::isSQLite()) {
29 $this->connection->executeStatement("ALTER TABLE $logsTable CHANGE COLUMN step_type step_type VARCHAR(255) NOT NULL");
30 } else {
31 $this->connection->executeStatement("ALTER TABLE $logsTable ALTER COLUMN step_type DROP DEFAULT");
32 }
33 }
34
35 // add "step_key" column
36 if (!$this->columnExists($logsTable, 'step_key')) {
37 $this->connection->executeStatement("ALTER TABLE $logsTable ADD COLUMN step_key VARCHAR(255) NOT NULL DEFAULT '' AFTER `step_type`");
38
39 // Temporarily use a full column definition to drop default in WP Playground.
40 // DROP DEFAULT is not yet supported by the SQLite integration.
41 if (Connection::isSQLite()) {
42 $this->connection->executeStatement("ALTER TABLE $logsTable CHANGE COLUMN step_key step_key VARCHAR(255) NOT NULL");
43 } else {
44 $this->connection->executeStatement("ALTER TABLE $logsTable ALTER COLUMN step_key DROP DEFAULT");
45 }
46 }
47
48 // add "run_number" column
49 if (!$this->columnExists($logsTable, 'run_number')) {
50 $this->connection->executeStatement("ALTER TABLE $logsTable ADD COLUMN run_number INT NOT NULL DEFAULT 1 AFTER `updated_at`");
51
52 // Temporarily use a full column definition to drop default in WP Playground.
53 // DROP DEFAULT is not yet supported by the SQLite integration.
54 if (Connection::isSQLite()) {
55 $this->connection->executeStatement("ALTER TABLE $logsTable CHANGE COLUMN run_number run_number INT NOT NULL");
56 } else {
57 $this->connection->executeStatement("ALTER TABLE $logsTable ALTER COLUMN run_number DROP DEFAULT");
58 }
59 }
60
61 // go through automation data and backfill step keys and trigger logs
62 $this->backfillStepKeysAndTriggers();
63
64 // fix mix of 'complete' and 'completed' statuses
65 $this->connection->executeStatement("UPDATE $logsTable SET status = 'complete' WHERE status = 'completed'");
66
67 // fix empty values for errors and data
68 $this->connection->executeStatement("ALTER TABLE $logsTable CHANGE `data` `data` longtext NOT NULL AFTER run_number");
69 $this->connection->executeStatement("UPDATE $logsTable SET data = '{}' WHERE data = '[]' OR data IS NULL");
70 $this->connection->executeStatement("UPDATE $logsTable SET error = NULL WHERE error = '[]' OR error IS NULL");
71
72 // remove "completed_at" column (with "updated_at" it's no longer needed), backfill "updated_at"
73 if ($this->columnExists($logsTable, 'completed_at')) {
74 $this->connection->executeStatement("UPDATE $logsTable SET updated_at = COALESCE(completed_at, started_at)");
75 $this->connection->executeStatement("ALTER TABLE $logsTable DROP COLUMN completed_at");
76 }
77
78 // add unique index, remove no longer needed index
79 if (!$this->indexExists($logsTable, 'automation_run_id_step_id')) {
80 $this->connection->executeStatement(
81 "DELETE t1 FROM $logsTable as t1, $logsTable as t2 WHERE t1.id < t2.id AND t1.automation_run_id = t2.automation_run_id AND t1.step_id=t2.step_id"
82 );
83 $this->connection->executeStatement("ALTER TABLE $logsTable ADD UNIQUE automation_run_id_step_id (automation_run_id, step_id)");
84 }
85 if ($this->indexExists($logsTable, 'automation_run_id')) {
86 $this->connection->executeStatement("ALTER TABLE $logsTable DROP INDEX automation_run_id");
87 }
88 }
89
90 private function backfillStepKeysAndTriggers(): void {
91 global $wpdb;
92 $logsTable = $wpdb->prefix . 'mailpoet_automation_run_logs';
93 $runsTable = $wpdb->prefix . 'mailpoet_automation_runs';
94 $versionsTable = $wpdb->prefix . 'mailpoet_automation_versions';
95
96 $triggerAddedMap = [];
97 while (true) {
98 $data = $this->connection->executeQuery("
99 SELECT rl.id, rl.automation_run_id, rl.step_id, rl.started_at, v.steps
100 FROM {$logsTable} rl
101 JOIN {$runsTable} r ON r.id = rl.automation_run_id
102 JOIN {$versionsTable} v ON v.id = r.version_id
103 WHERE rl.step_key = ''
104 ORDER BY rl.id ASC
105 LIMIT 50
106 ")->fetchAllAssociative();
107
108 if (count($data) === 0) {
109 break;
110 }
111
112 $queries = [];
113 /** @var array<int, array{id:int, automation_run_id:int, step_id:int, started_at:string, steps:string}> $data */
114 foreach ($data as $item) {
115 /** @var array $steps */
116 $steps = json_decode(strval($item['steps']), true);
117 $id = intval($item['id']);
118 $stepId = strval($item['step_id']);
119 $stepKey = strval($steps[$stepId]['key'] ?? 'unknown');
120 $triggerId = $steps['root']['next_steps'][0]['id'];
121 $triggerKey = $steps['root']['next_steps'][0]['key'] ?? 'unknown';
122
123 $queries[] = "UPDATE {$logsTable} SET step_key = '{$stepKey}' WHERE id = {$id}";
124
125 // backfill triggers
126 $runId = intval($item['automation_run_id']);
127 if (!isset($triggerAddedMap[$runId])) {
128 $startedAt = strval($item['started_at']);
129 $date = "DATE_SUB('$startedAt', INTERVAL 1 SECOND)";
130 $queries[] = "
131 INSERT INTO {$logsTable} (automation_run_id, step_id, step_type, step_key, status, started_at, updated_at, run_number, data)
132 VALUES ($runId, '$triggerId', 'trigger', '$triggerKey', 'complete', $date, $date, 1, '{}')
133 ";
134 $triggerAddedMap[$runId] = true;
135 }
136 }
137
138 $nativeConnection = $this->connection->getNativeConnection();
139 // If the connection is a mysqli object, we can use the multi_query method
140 if (is_object($nativeConnection) && get_class($nativeConnection) === 'mysqli') {
141 $query = implode(';', $queries);
142 $nativeConnection->multi_query($query);
143 } else { // Otherwise, we need to execute each query individually (e.g. PDO or SQLite)
144 foreach ($queries as $query) {
145 $this->connection->executeStatement($query);
146 }
147 }
148 }
149 }
150 }
151