PluginProbe
FireBox – WooCommerce Popup Builder, Exit Intent Popup, Email Optin & Cart Abandonment / 3.1.6
FireBox – WooCommerce Popup Builder, Exit Intent Popup, Email Optin & Cart Abandonment v3.1.6
3.1.13 3.1.12 3.1.11 3.1.10 3.1.9 3.1.8 3.1.7 trunk 1.0.0 1.0.1 1.0.10 1.0.11 1.0.12 1.0.13 1.0.14 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 All 122 releases
firebox / Inc / Core / Migrator.php

Migrator.php in FireBox – WooCommerce Popup Builder, Exit Intent Popup, Email Optin & Cart Abandonment 3.1.6, at Inc/Core/Migrator.php

662 lines 14.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @package FireBox
4 * @version 3.1.6 Free
5 *
6 * @author FirePlugins <info@fireplugins.com>
7 * @link https://www.fireplugins.com
8 * @copyright Copyright © 2026 FirePlugins All Rights Reserved
9 * @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
10 */
11
12 namespace FireBox\Core;
13
14 if (!defined('ABSPATH'))
15 {
16 exit; // Exit if accessed directly.
17 }
18
19 use FireBox\Core\Helpers\Form\Form;
20
21 class Migrator
22 {
23 /**
24 * The currently installed version.
25 *
26 * @var string
27 */
28 private $installedVersion;
29
30 /**
31 * Whether we run a migration.
32 *
33 * @var bool
34 */
35 private $run = false;
36
37 public function __construct($installedVersion = '')
38 {
39 $this->installedVersion = $installedVersion;
40 }
41
42 public function run()
43 {
44 if (!$this->installedVersion)
45 {
46 return;
47 }
48
49 $this->moveFireBoxDataToUploadsDirectory();
50 $this->installFormsTables();
51 $this->improveIndexes();
52 $this->updatePublishingRulesToConditionBuilder();
53 $this->updateEcommerceProductsInCartConditions();
54 $this->updateAnalyticsStoragePeriodSetting();
55 $this->update213version();
56 $this->addMissingCapabilities();
57
58
59 $this->addNewIndexes();
60 $this->skipOnboarding();
61
62 // Update firebox version
63 if ($this->run)
64 {
65 // Update version
66 update_option('firebox_version', FBOX_VERSION);
67 }
68 }
69
70 /**
71 * Moves plugin data to its own /wp-content/uploads/firebox folder.
72 *
73 * @since 1.1.10
74 *
75 * @return void
76 */
77 private function moveFireBoxDataToUploadsDirectory()
78 {
79 if (version_compare($this->installedVersion, '1.1.10', '>='))
80 {
81 return;
82 }
83
84 // Create dirs
85 \FireBox\Core\Helpers\Activation::createLibraryDirectories();
86
87 $this->run = true;
88 }
89
90 /**
91 * Creates the forms tables.
92 *
93 * @since 1.2.0
94 *
95 * @return void
96 */
97 private function installFormsTables()
98 {
99 if (version_compare($this->installedVersion, '1.2.0', '>='))
100 {
101 return;
102 }
103
104 if (!class_exists('Activation'))
105 {
106 require_once FBOX_PLUGIN_DIR . '/Inc/Framework/Inc/Admin/Includes/Activation.php';
107 }
108 $activation = new \Activation(firebox()->hook_data);
109 $activation->initTables();
110
111 $this->run = true;
112 }
113
114 /**
115 * Improves indexes on form and box logs tables.
116 *
117 * @since 1.2.4
118 *
119 * @return void
120 */
121 private function improveIndexes()
122 {
123 if (version_compare($this->installedVersion, '1.2.4', '>='))
124 {
125 return;
126 }
127
128 if (!$this->hasIndex('idx_box_id', 'firebox_logs'))
129 {
130 global $wpdb;
131 $wpdb->query("ALTER TABLE {$wpdb->prefix}firebox_logs ADD INDEX `idx_box_id` (`box`, `id`)");
132 }
133
134 if (!$this->hasIndex('idx_meta_key', 'firebox_submission_meta'))
135 {
136 global $wpdb;
137 $wpdb->query("ALTER TABLE {$wpdb->prefix}firebox_submission_meta ADD INDEX `idx_meta_key` (`meta_key`)");
138 }
139
140 $this->run = true;
141 }
142
143 /**
144 * Update old Publishing Rules to Condition Builder.
145 *
146 * @since 2.0.0
147 *
148 * @return void
149 */
150 private function updatePublishingRulesToConditionBuilder()
151 {
152 if (version_compare($this->installedVersion, '2.0.0', '>='))
153 {
154 return;
155 }
156
157 // Get all boxes, regardless of post status, thus we pass [] to ensure all popups are returned.
158 $boxes = \FireBox\Core\Helpers\BoxHelper::getAllBoxes([]);
159
160 if (!$boxes->posts)
161 {
162 $this->run = true;
163 return;
164 }
165
166 foreach ($boxes->posts as $box)
167 {
168 // Get post meta and add it to its object
169 $meta = \FireBox\Core\Helpers\BoxHelper::getMeta($box->ID);
170
171 // Skip popup that already has rules
172 if (isset($meta['rules']))
173 {
174 continue;
175 }
176
177 $box->params = new \FPFramework\Libs\Registry($meta);
178
179 // Pass only params
180 \FPFramework\Base\Conditions\Migrator::run($box->params);
181
182 // Update popup settings
183 update_post_meta($box->ID, 'fpframework_meta_settings', wp_slash(json_decode(wp_json_encode($box->params), true)));
184 }
185
186 $this->run = true;
187 }
188
189 /**
190 * Updates the following conditions to match the new condition settings.
191 *
192 * EDD\CartContainsProducts
193 * WooCommerce\CartContainsProducts
194 *
195 * @since 2.0.10
196 *
197 * @return void
198 */
199 private function updateEcommerceProductsInCartConditions()
200 {
201 if (version_compare($this->installedVersion, '2.0.10', '>='))
202 {
203 return;
204 }
205
206 // Get all boxes, regardless of post status, thus we pass [] to ensure all popups are returned.
207 $boxes = \FireBox\Core\Helpers\BoxHelper::getAllBoxes([]);
208
209 if (!$boxes->posts)
210 {
211 $this->run = true;
212 return;
213 }
214
215 foreach ($boxes->posts as $box)
216 {
217 $meta = \FireBox\Core\Helpers\BoxHelper::getMeta($box->ID);
218
219 if (!isset($meta['rules']) || !is_array($meta['rules']))
220 {
221 continue;
222 }
223
224 $allowed_rules = [
225 'EDD\CartContainsProducts',
226 'WooCommerce\CartContainsProducts'
227 ];
228
229 $changed = false;
230
231 foreach ($meta['rules'] as &$ruleset)
232 {
233 if (!isset($ruleset['rules']))
234 {
235 continue;
236 }
237
238 foreach ($ruleset['rules'] as &$rule)
239 {
240 if (!isset($rule['name']))
241 {
242 continue;
243 }
244
245 if (!in_array($rule['name'], $allowed_rules))
246 {
247 continue;
248 }
249
250 if (!isset($rule['value']))
251 {
252 continue;
253 }
254
255 if (!is_array($rule['value']))
256 {
257 continue;
258 }
259
260 if (!count($rule['value']))
261 {
262 continue;
263 }
264
265 $changed = true;
266
267 $rule['value'] = array_map(function($id) {
268 // Old value wasn't an array, skip if new value was found
269 if (is_array($id))
270 {
271 return $id;
272 }
273
274 return [
275 'value' => $id,
276 'quantity_operator' => 'any',
277 'quantity_value1' => '1',
278 'quantity_value2' => '1'
279 ];
280 }, $rule['value']);
281 }
282 }
283
284 if (!$changed)
285 {
286 continue;
287 }
288
289 update_post_meta($box->ID, 'fpframework_meta_settings', wp_slash(json_decode(wp_json_encode($meta), true)));
290 }
291
292 $this->run = true;
293 }
294
295 /**
296 * Updates the Analytics Storage Period setting.
297 *
298 * @since 2.1.1
299 *
300 * @return void
301 */
302 public function updateAnalyticsStoragePeriodSetting()
303 {
304 if (version_compare($this->installedVersion, '2.1.1', '>='))
305 {
306 return;
307 }
308
309 $params = get_option('firebox_settings', []);
310
311 $statsdays = isset($params['statsdays']) ? $params['statsdays'] : 730;
312 $statsdays_custom = isset($params['statsdays_custom']) ? $params['statsdays_custom'] : false;
313
314 if ($statsdays === 'custom')
315 {
316 $statsdays = $statsdays_custom;
317 }
318
319 $statsdays = (int) $statsdays;
320
321 if ($statsdays <= 365)
322 {
323 $statsdays = 365;
324 }
325 else if ($statsdays <= 365 * 2)
326 {
327 $statsdays = 365 * 2;
328 }
329 else
330 {
331 $statsdays = 365 * 5;
332 }
333
334 $params['statsdays'] = $statsdays;
335
336 update_option('firebox_settings', $params);
337
338 $this->run = true;
339 }
340
341 public function update213version()
342 {
343 $this->updateLogsDetailsParamsColumn();
344 $this->moveFormConversionsToLogsDetailsTable();
345 }
346
347 /**
348 * Adds a new column called event_source after event column.
349 * Renames the params column in the logs details table to event_label.
350 *
351 * @since 2.1.4
352 *
353 * @return void
354 */
355 public function updateLogsDetailsParamsColumn()
356 {
357 if (version_compare($this->installedVersion, '2.1.4', '>='))
358 {
359 return;
360 }
361
362 global $wpdb;
363
364 // If has column params
365 $row = $wpdb->get_results("SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = '{$wpdb->dbname}' AND table_name = '{$wpdb->prefix}firebox_logs_details' AND column_name = 'params'");
366 if (!$row)
367 {
368 $this->run = true;
369 return;
370 }
371
372 // Add column "event_source" after "event"
373 $wpdb->query("ALTER TABLE {$wpdb->prefix}firebox_logs_details ADD COLUMN `event_source` varchar(200) NOT NULL AFTER `event`");
374
375 // Rename params to event_label
376 $wpdb->query("ALTER TABLE {$wpdb->prefix}firebox_logs_details CHANGE COLUMN `params` `event_label` text NOT NULL");
377
378 $this->run = true;
379 }
380
381 /**
382 * Moves form conversions from submission meta table to logs details table.
383 *
384 * @since 2.1.4
385 *
386 * @return void
387 */
388 private function moveFormConversionsToLogsDetailsTable()
389 {
390 if (version_compare($this->installedVersion, '2.1.4', '>='))
391 {
392 return;
393 }
394
395 global $wpdb;
396
397 // Get all submission meta data
398 $boxlogids = firebox()->tables->submissionmeta->getResults([
399 'select' => [
400 "{$wpdb->prefix}firebox_submission_meta.id",
401 'l.box',
402 's.form_id',
403 "{$wpdb->prefix}firebox_submission_meta.meta_value",
404 "{$wpdb->prefix}firebox_submission_meta.created_at"
405 ],
406 'where' => [
407 'meta_key' => " = '" . absint('box_log_id') . "'"
408 ],
409 'join' => [
410 "LEFT JOIN" => " {$wpdb->prefix}firebox_submissions as s ON s.id = submission_id LEFT JOIN {$wpdb->prefix}firebox_logs as l ON l.id = meta_value",
411 ]
412 ]);
413
414 if (!$boxlogids)
415 {
416 $this->run = true;
417 return;
418 }
419
420 global $wpdb;
421
422 // Migrate to the box logs details table
423 foreach ($boxlogids as $row)
424 {
425 if (!$row->box)
426 {
427 continue;
428 }
429
430 $form = Form::getFormByID($row->form_id);
431
432 $data = [
433 'log_id' => $row->meta_value,
434 'event' => 'conversion',
435 'event_source' => 'form',
436 'event_label' => isset($form['block']['attrs']['formName']) ? $form['block']['attrs']['formName'] : 'FireBox #' . $row->box . ' Form',
437 'date' => $row->created_at
438 ];
439
440 firebox()->tables->boxlogdetails->insert($data);
441 }
442
443 // Delete all submission_meta rows
444 $ids = implode(',', array_map('intval', array_column($boxlogids, 'id')));
445 $sm_table_name = firebox()->tables->submissionmeta->getFullTableName();
446 $wpdb->query("DELETE FROM $sm_table_name WHERE id IN($ids)");// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
447
448 $this->run = true;
449 }
450
451 public function addMissingCapabilities()
452 {
453 if (version_compare($this->installedVersion, '2.1.15', '>='))
454 {
455 return;
456 }
457
458 $cap_name = 'read_fireboxes';
459
460 $admin = get_role('administrator');
461
462 if ($admin)
463 {
464 if ($admin->has_cap($cap_name))
465 {
466 return true;
467 }
468
469 $admin->add_cap($cap_name);
470 }
471 else
472 {
473 $roles = get_editable_roles();
474
475 foreach ($roles as $role_name => $data)
476 {
477 if (isset($data['capabilities']['manage_options']) && $data['capabilities']['manage_options'])
478 {
479 $role = get_role($role_name);
480
481 if ($role->has_cap($cap_name))
482 {
483 continue;
484 }
485
486 $role->add_cap($cap_name);
487 }
488 }
489 }
490
491 wp_get_current_user()->get_role_caps();
492
493 return true;
494 }
495
496 #PRO-START
497 public function update2136version()
498 {
499 if (version_compare($this->installedVersion, '2.1.36', '>='))
500 {
501 return;
502 }
503
504 // Get all boxes, regardless of post status, thus we pass [] to ensure all popups are returned.
505 $boxes = \FireBox\Core\Helpers\BoxHelper::getAllBoxes([]);
506
507 if (!$boxes->posts)
508 {
509 $this->run = true;
510 return;
511 }
512
513 foreach ($boxes->posts as $box)
514 {
515 // Get post meta and add it to its object
516 $meta = \FireBox\Core\Helpers\BoxHelper::getMeta($box->ID);
517
518 $box->params = new \FPFramework\Libs\Registry($meta);
519
520 // Migrate firing frequency
521 $box->params->set('firing_frequency', (int) $box->params->get('firing_frequency') === 1);
522
523 // Migrate scroll amount
524 if (!$box->params->get('scroll_amount'))
525 {
526 $unit = '';
527 $value = '';
528
529 $scroll_depth = $box->params->get('scroll_depth', 'percentage');
530
531 if ($scroll_depth === 'pixel')
532 {
533 $unit = 'px';
534 $value = $box->params->get('scroll_pixel', 0);
535 }
536 else
537 {
538 $unit = '%';
539 $value = $box->params->get('triggerpercentage', 0);
540 }
541
542 $box->params->set('scroll_amount', [
543 'unit' => $unit,
544 'value' => $value
545 ]);
546 }
547
548 // Update popup settings
549 update_post_meta($box->ID, 'fpframework_meta_settings', wp_slash(json_decode(wp_json_encode($box->params), true)));
550 }
551
552 $this->run = true;
553 }
554 #PRO_END
555
556
557
558 /**
559 * Adds new indexes to the logs details table.
560 *
561 * @since 3.1.0
562 *
563 * @return void
564 */
565 private function addNewIndexes()
566 {
567 if (version_compare($this->installedVersion, '3.1.0', '>='))
568 {
569 return;
570 }
571
572 if (!$this->hasIndex('idx_firebox_logs_details_event_log', 'firebox_logs_details'))
573 {
574 global $wpdb;
575 $wpdb->query("ALTER TABLE {$wpdb->prefix}firebox_logs_details ADD INDEX `idx_firebox_logs_details_event_log` (`event`, `log_id`)");
576 }
577 if (!$this->hasIndex('idx_firebox_logs_details_event_source_log', 'firebox_logs_details'))
578 {
579 global $wpdb;
580 $wpdb->query("ALTER TABLE {$wpdb->prefix}firebox_logs_details ADD INDEX `idx_firebox_logs_details_event_source_log` (`event_source`, `log_id`)");
581 }
582 if (!$this->hasIndex('idx_firebox_logs_details_event_date', 'firebox_logs_details'))
583 {
584 global $wpdb;
585 $wpdb->query("ALTER TABLE {$wpdb->prefix}firebox_logs_details ADD INDEX `idx_firebox_logs_details_event_date` (`event`, `date`)");
586 }
587 if (!$this->hasIndex('idx_firebox_logs_details_event_source_event_log', 'firebox_logs_details'))
588 {
589 global $wpdb;
590 $wpdb->query("ALTER TABLE {$wpdb->prefix}firebox_logs_details ADD INDEX `idx_firebox_logs_details_event_source_event_log` (`event_source`, `event`, `log_id`)");
591 }
592 if (!$this->hasIndex('idx_firebox_logs_details_event_source_event_date', 'firebox_logs_details'))
593 {
594 global $wpdb;
595 $wpdb->query("ALTER TABLE {$wpdb->prefix}firebox_logs_details ADD INDEX `idx_firebox_logs_details_event_source_event_date` (`event_source`, `event`, `date`)");
596 }
597
598 $this->run = true;
599 }
600
601 /**
602 * Skip onboarding for existing installations.
603 *
604 * @since 3.1.5
605 *
606 * @return void
607 */
608 private function skipOnboarding()
609 {
610 if (version_compare($this->installedVersion, '3.1.5', '>='))
611 {
612 return;
613 }
614
615 // Check if this is truly an existing installation by looking for any FireBox campaigns
616 $has_campaigns = get_posts([
617 'post_type' => 'firebox',
618 'post_status' => 'any',
619 'numberposts' => 1,
620 'fields' => 'ids'
621 ]);
622
623 // If no campaigns exist, this is likely a fresh install, so don't skip onboarding
624 if (empty($has_campaigns))
625 {
626 return;
627 }
628
629 // This is an existing installation with campaigns, so skip the onboarding tour.
630 update_option('firebox_onboarding_completed', \FireBox\Core\Admin\Includes\Onboarding::ONBOARDING_STATUS_SKIPPED);
631
632 $this->run = true;
633 }
634
635 /**
636 * Checks whether an index exists in a table.
637 *
638 * @param string $index
639 * @param string $table
640 *
641 * @return bool
642 */
643 private function hasIndex($index = '', $table = '')
644 {
645 if (empty($index) || empty($table))
646 {
647 return;
648 }
649
650 global $wpdb;
651
652 $existing = $wpdb->get_row("SHOW CREATE TABLE `{$wpdb->prefix}{$table}`", ARRAY_N);// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
653
654 if (isset($existing[1]) && strpos(strtolower($existing[1]), 'key `' . $index . '` (') !== false)
655 {
656 return true;
657 }
658
659 return false;
660 }
661 }
662