PluginProbe
FireBox – WooCommerce Popup Builder, Exit Intent Popup, Email Optin & Cart Abandonment / 3.1.8
FireBox – WooCommerce Popup Builder, Exit Intent Popup, Email Optin & Cart Abandonment v3.1.8
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 / Admin / Admin.php

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

1,058 lines 30.8 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.8 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\Admin;
13
14 if (!defined('ABSPATH'))
15 {
16 exit; // Exit if accessed directly.
17 }
18
19 class Admin
20 {
21 /**
22 * Admin Page Settings
23 *
24 * @var AdminPageSettings
25 */
26 private $pageSettings;
27
28 /**
29 * Library
30 *
31 * @var Library
32 */
33 public $library;
34
35 /**
36 * Admin constructor
37 */
38 public function __construct()
39 {
40 new \FireBox\Core\Notices\Ajax();
41
42 add_action('admin_init', [$this, 'maybeExportSubmsissions']);
43
44 add_action('admin_head', [$this, 'set_gutenberg_editor_logo']);
45
46 add_action('wp_trash_post', [$this, 'on_campaign_trash'], 10, 2);
47 add_action('untrash_post', [$this, 'on_campaign_untrash'], 10, 2);
48
49
50 add_action('admin_enqueue_scripts', [$this, 'global_backend_assets'], 20);
51
52
53 add_action('current_screen', [$this, 'current_screen']);
54
55 add_action('firebox/admin/content', [$this, 'showNotices'], -5);
56
57 // Init onboarding for new users
58 add_action('admin_init', [$this, 'initOnboarding']);
59 add_action('admin_init', [$this, 'redirectAfterActivation']);
60
61 // Register AJAX handler for onboarding (always available, not limited by page check)
62 add_action('wp_ajax_firebox_onboarding_complete', [Includes\Onboarding::class, 'handleOnboardingComplete']);
63
64 // init dependencies
65 $this->initDependencies();
66
67 // Admin Page Settings
68 $this->pageSettings = new AdminPageSettings();
69
70 // run actions
71 $this->handleActions();
72
73 // run filters
74 $this->handleFilters();
75
76 add_action('save_post', [$this, 'onSave'], 20);
77 }
78
79 /**
80 * On Save, clear the campaign cookie if closing behavior > when closed is set to "never".
81 *
82 * @param string $post_id
83 *
84 * @return void
85 */
86 public function onSave($post_id)
87 {
88 if (!isset($_POST['post_type']) || $_POST['post_type'] !== 'firebox')
89 {
90 return;
91 }
92
93 if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE)
94 {
95 return;
96 }
97
98 if ($parent_id = wp_is_post_revision($post_id))
99 {
100 $post_id = $parent_id;
101 }
102
103 $meta = get_post_meta($post_id, 'firebox_meta');
104
105 $assign_cookietype = isset($meta[0]['assign_cookietype']) ? $meta[0]['assign_cookietype'] : '';
106
107 if ($assign_cookietype === 'never')
108 {
109 setcookie('firebox_' . $post_id, '', time() - 3600, '/');
110 }
111 }
112
113 /**
114 * Set the FireBox logo in the Gutenberg editor.
115 *
116 * @return void
117 */
118 public function set_gutenberg_editor_logo()
119 {
120 if (get_post_type() !== 'firebox')
121 {
122 return;
123 }
124
125 ?>
126 <style>
127 @media screen and (min-width: 782px) {
128 .editor-header {
129 grid-template: auto / auto minmax(0, max-content) minmax(min-content, 1fr) 60px;
130 }
131
132 .editor-header:has(>.editor-header__center) {
133 grid-template: auto / auto minmax(min-content, 1fr) 2fr minmax(min-content, 1fr) 60px;
134 }
135 }
136 .editor-header__back-button .edit-post-fullscreen-mode-close {
137 background: transparent !important;
138 background-image: url("<?php echo esc_url(FBOX_MEDIA_ADMIN_URL); ?>images/logo_full.svg") !important;
139 background-size: 105px !important;
140 margin-right: 0 !important;
141 margin-left: 17px !important;
142 background-repeat: no-repeat !important;
143 background-position: center center !important;
144 width: 120px !important;
145 }
146 .editor-header__back-button .edit-post-fullscreen-mode-close:before,
147 .editor-header__back-button .edit-post-fullscreen-mode-close:after,
148 .editor-header__back-button img,
149 .editor-header__back-button svg {
150 display: none !important;
151 }
152 </style>
153 <?php
154 }
155
156 public function maybeExportSubmsissions()
157 {
158 if (!isset($_GET['task']) || $_GET['task'] !== 'export')
159 {
160 return;
161 }
162
163 if (!isset($_GET['form_id']))
164 {
165 return;
166 }
167
168 if (!isset($_GET['page']) || $_GET['page'] !== 'firebox-submissions')
169 {
170 return;
171 }
172
173 // Authorization: only users who can view submissions may export them.
174 if (!current_user_can('read_fireboxes'))
175 {
176 return;
177 }
178
179 // CSRF: verify the nonce generated on the submissions list page.
180 check_admin_referer('firebox-export-submissions');
181
182 $form_id = sanitize_text_field(wp_unslash($_GET['form_id']));
183
184 $export = $this->getSubmissionsForExport($form_id);
185
186 if (!$export)
187 {
188 return;
189 }
190
191 $filename = get_temp_dir() . 'submissions_' . $export['name'] . '_' . date('Y-m-d_H-i-s') . '.csv';
192 self::toCSV($export['rows'], $filename);
193
194 // Prompt to download the file
195 error_reporting(0);
196
197 // Send the appropriate headers to force the download in the browser
198 header('Content-Description: File Transfer');
199 header('Content-Type: application/octet-stream');
200 header('Content-Disposition: attachment; filename="' . basename($filename) . '"');
201 header('Expires: 0');
202 header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
203 header('Cache-Control: public', false);
204 header('Pragma: public');
205 header('Content-Length: ' . @filesize($filename));
206
207 // Clear the output buffer and disable output buffering
208 ob_clean();
209 flush();
210
211 readfile($filename);
212
213 unlink($filename);
214
215 exit;
216 }
217
218 /**
219 * Collects and prepares submission rows for CSV export.
220 * Returns the prepared rows (with the resolved form attached) or false.
221 *
222 * @param string $form_id
223 *
224 * @return array|false
225 */
226 protected function getSubmissionsForExport($form_id)
227 {
228 $payload = [
229 'where' => [
230 'form_id' => " = '" . sanitize_key($form_id) . "'",
231 'state' => ' = 1'
232 ],
233 'offset' => 0,
234 'limit' => 99999,
235 'orderby' => 'created_at ASC'
236 ];
237
238 if (!$submissions = firebox()->tables->submission->getResults($payload))
239 {
240 return false;
241 }
242
243 if (!$form = \FireBox\Core\Helpers\Form\Form::getFormByID($form_id, true))
244 {
245 return false;
246 }
247
248 $prepared = [];
249
250 foreach ($submissions as $item)
251 {
252 $prepared_payload = [
253 'id' => $item->id,
254 'created' => get_date_from_gmt($item->created_at),
255 'state' => $item->state === '1' ? 'Published' : 'Unpublished'
256 ];
257
258 $meta = firebox()->tables->submissionmeta->getResults([
259 'where' => [
260 'submission_id' => " = " . absint($item->id)
261 ]
262 ]);
263
264 if ($meta && $form['fields'])
265 {
266 foreach ($form['fields'] as $field)
267 {
268 foreach ($meta as $meta_item)
269 {
270 if ($field->getOptionValue('id') === $meta_item->meta_key)
271 {
272 $prepared_payload[$field->getOptionValue('name')] = $field->prepareValue($meta_item->meta_value);
273 }
274 }
275 }
276 }
277
278 $prepared[] = $prepared_payload;
279 }
280
281 return ['name' => $form['name'], 'rows' => $prepared];
282 }
283
284 /**
285 * Create a CSV file with given data
286 *
287 * @param array $data The data to populate the file
288 * @param string $destination The path where the store the CSV file
289 * @param bool $append If true, given data will be appended to the end of the file.
290 * @param boolean $excel_security If enabled, certain row values will be prefixed by a tab to avoid any CSV injection.
291 *
292 * @return void
293 */
294 private static function toCSV($data, $destination, $append = false, $excel_security = true, $check_for_duplicates = true)
295 {
296 $resource = fopen($destination, $append ? 'a+' : 'w');
297
298 if (!$append)
299 {
300 // Support UTF-8 on Microsoft Excel
301 fputs($resource, "\xEF\xBB\xBF");
302
303 // Add column names in the first line
304 fputcsv($resource, array_keys($data[0]), ',', '"', '\\');
305 }
306
307 // Get CSV content
308 $existingRows = [];
309 if ($append && $check_for_duplicates)
310 {
311 while (($existingData = fgetcsv($resource)) !== false)
312 {
313 $existingRows[(int) $existingData[0]] = $existingData;
314 }
315 }
316
317 foreach ($data as $row)
318 {
319 if (!empty($existingRows) && isset($row['id']) && array_key_exists($row['id'], $existingRows))
320 {
321 continue;
322 }
323
324 // Prevent CSV Injection: https://vel.joomla.org/articles/2140-introducing-csv-injection
325 if ($excel_security)
326 {
327 foreach ($row as &$value)
328 {
329 $value = is_array($value) ? implode(', ', $value) : $value;
330
331 $firstChar = substr($value, 0, 1);
332
333 // Prefixe values starting with a =, +, - or @ by a tab character
334 if (in_array($firstChar, array('=', '+', '-', '@')))
335 {
336 $value = ' ' . $value;
337 }
338 }
339 }
340
341 fputcsv($resource, $row, ',', '"', '\\');
342 }
343
344 fclose($resource);
345 }
346
347 /**
348 * Fires when a campaign is trashed.
349 *
350 * @param int $post_id
351 * @param string $previous_status
352 *
353 * @return void
354 */
355 public function on_campaign_trash($post_id, $previous_status)
356 {
357 $post_type = get_post_type($post_id);
358 $post_status = get_post_status($post_id);
359
360 if ($post_type === 'firebox' && $post_status === 'draft')
361 {
362 \FPFramework\Libs\AdminNotice::displaySuccess(firebox()->_('FB_CAMPAIGN_HAS_BEEN_TRASHED'));
363 }
364 }
365
366 /**
367 * Fires when a campaign is untrashed.
368 *
369 * @param int $post_id
370 * @param string $previous_status
371 *
372 * @return void
373 */
374 public function on_campaign_untrash($post_id, $previous_status)
375 {
376 $post_type = get_post_type($post_id);
377 $post_status = get_post_status($post_id);
378
379 if ($post_type === 'firebox' && $post_status === 'trash')
380 {
381 \FPFramework\Libs\AdminNotice::displaySuccess(firebox()->_('FB_CAMPAIGN_HAS_BEEN_RESTORED'));
382 }
383 }
384
385 public function showNotices()
386 {
387 \FireBox\Core\Notices\Notices::getInstance()->show();
388 }
389
390
391 public function global_backend_assets()
392 {
393 wp_register_style(
394 'firebox-admin-lite',
395 FBOX_MEDIA_ADMIN_URL . 'css/lite.css',
396 [],
397 FBOX_VERSION,
398 false
399 );
400 wp_enqueue_style('firebox-admin-lite');
401 }
402
403
404 public function current_screen($screen)
405 {
406 add_action('admin_enqueue_scripts', [$this, 'registerEditorMedia'], 11);
407 add_action('enqueue_block_assets', [$this, 'registerCampaignEditorAssets'], 12);
408
409 // Check for classic editor with firebox post type
410 if (isset($screen->id) && $screen->id === 'firebox' && !$screen->is_block_editor) {
411 add_action('admin_notices', [$this, 'showClassicEditorNotice']);
412 }
413
414 $allowed_pages = [
415 'toplevel_page_firebox',
416 'firebox_page_firebox-campaigns',
417 'firebox_page_firebox-analytics',
418 'firebox_page_firebox-submissions',
419 'firebox_page_firebox-settings',
420 'firebox_page_firebox-import'
421 ];
422
423 if (isset($screen->id) && in_array($screen->id, $allowed_pages))
424 {
425 add_action('admin_enqueue_scripts', [$this, 'registerMediaAdminPages'], 20);
426
427 add_filter('admin_footer_text', [$this, 'admin_footer_text']);
428 }
429 }
430
431 /**
432 * Shows a notice when using classic editor with firebox post type
433 *
434 * @return void
435 */
436 public function showClassicEditorNotice()
437 {
438 ?>
439 <div class="notice notice-warning">
440 <p><?php echo esc_html(firebox()->_('FB_CLASSIC_EDITOR_NOT_SUPPORTED')); ?></p>
441 </div>
442 <?php
443 }
444
445 public function registerEditorMedia()
446 {
447 wp_register_script('firebox-admin-editor', false);
448 wp_enqueue_script('firebox-admin-editor');
449
450 $data = [
451 'media_url' => FBOX_MEDIA_URL,
452 'timezone' => $this->getTimezone(),
453 'license_type' => FBOX_LICENSE_TYPE,
454 'license_plan' => FBOX_LICENSE_PLAN,
455 'langs' => [
456 'LITE' => fpframework()->_('FPF_LITE'),
457 ]
458 ];
459
460 wp_localize_script('firebox-admin-editor', 'fbox_admin_editor_js_object', $data);
461 }
462
463 public function registerCampaignEditorAssets()
464 {
465 if (!is_admin())
466 {
467 return;
468 }
469
470 // Enqueue block editor style only in Gutenberg editor
471 if (!function_exists('get_current_screen'))
472 {
473 return;
474 }
475
476 $screen = get_current_screen();
477 if (!$screen->is_block_editor)
478 {
479 return;
480 }
481
482 wp_enqueue_script(
483 'firebox-helper-store',
484 FBOX_MEDIA_ADMIN_URL . 'js/blocks/helper_store.js',
485 ['wp-data'],
486 FBOX_VERSION,
487 false
488 );
489
490 wp_enqueue_style(
491 'firebox-blocks',
492 FBOX_MEDIA_PUBLIC_URL . 'css/blocks.css',
493 [],
494 FBOX_VERSION
495 );
496
497 $css = '
498 :root {
499 --firebox-editor-background-image: url(' . FBOX_MEDIA_ADMIN_URL . 'images/browser-bg.png);
500 }
501 ';
502 wp_add_inline_style('firebox-blocks', $css);
503
504 if (get_post_type() !== 'firebox')
505 {
506 return;
507 }
508
509 wp_register_script('firebox-campaign-editor', false);
510 wp_enqueue_script('firebox-campaign-editor');
511
512 $data = [
513 'plugins' => [
514 'wpml_active' => \is_plugin_active('sitepress-multilingual-cms/sitepress.php'),
515 'edd_active' => \is_plugin_active('easy-digital-downloads/easy-digital-downloads.php') || \is_plugin_active('easy-digital-downloads-pro/easy-digital-downloads.php'),
516 'woo_active' => \is_plugin_active('woocommerce/woocommerce.php')
517 ],
518 'geolocation_updated' => !\FPFramework\Helpers\Geolocation::geoNeedsUpdate(),
519 'geolocation_update_url' => admin_url('admin.php?page=firebox-settings#geolocation'),
520 'geolocation_city_notice' => (new \FPFramework\Base\Conditions\Conditions\Geo\City())->getValueHint(),
521 'geolocation_country_notice' => (new \FPFramework\Base\Conditions\Conditions\Geo\Country())->getValueHint(),
522 'geolocation_region_notice' => (new \FPFramework\Base\Conditions\Conditions\Geo\Region())->getValueHint(),
523 'geolocation_continent_notice' => (new \FPFramework\Base\Conditions\Conditions\Geo\Continent())->getValueHint(),
524 'countries_list' => \FPFramework\Helpers\CountriesHelper::getCountriesList(),
525 'user_ip' => \FPFramework\Base\User::getIP(),
526 'currency' => $this->getCurrency()
527 ];
528
529 wp_localize_script('firebox-campaign-editor', 'firebox_campaign_editor', $data);
530 }
531
532 /**
533 * Returns the current eCommerce solution's currency.
534 *
535 * @return string
536 */
537 private function getCurrency()
538 {
539 $output = '';
540
541 $eddActive = \is_plugin_active('easy-digital-downloads/easy-digital-downloads.php') || \is_plugin_active('easy-digital-downloads-pro/easy-digital-downloads.php');
542 if ($eddActive)
543 {
544 $output = \edd_get_currency();
545 }
546 else
547 {
548 $wooActive = \is_plugin_active('woocommerce/woocommerce.php');
549 if ($wooActive)
550 {
551 $output = \get_woocommerce_currency();
552 }
553 }
554
555 return $output;
556 }
557
558 public function admin_footer_text()
559 {
560 return;
561 }
562
563 /**
564 * Load admin dependencies.
565 *
566 * @return void
567 */
568 private function initDependencies()
569 {
570 new Media();
571
572 $this->library = firebox()->library;
573 }
574
575 /**
576 * Runs all Admin Actions
577 *
578 * @return void
579 */
580 private function handleActions()
581 {
582 add_action('admin_enqueue_scripts', [$this, 'registerGlobalMedia'], 20);
583
584
585 add_action('plugin_action_links_' . plugin_basename(FBOX_PLUGIN_BASE_FILE), [$this, 'plugin_action_links']);
586
587 }
588
589 public function registerGlobalMedia()
590 {
591 wp_register_style('firebox-global-admin', false);
592 wp_enqueue_style('firebox-global-admin');
593 $css = '
594 #adminmenu li.toplevel_page_firebox .wp-menu-image {
595 padding: 4px 0 0 0;
596 height: auto;
597 }
598 #adminmenu li.toplevel_page_firebox img {
599 width: 20px !important;
600 padding: 0;
601 padding-top: 3px !important;
602 }
603 ';
604 wp_add_inline_style('firebox-global-admin', $css);
605 }
606
607
608 /**
609 * Adds extra links to the Plugins page in the free version.
610 * - Upgrade to Pro button
611 *
612 * @param array $links
613 *
614 * @return array
615 */
616 public function plugin_action_links($links)
617 {
618 $links = array_merge( $links, array(
619 '<a href="' . sprintf(FBOX_GO_PRO_URL, 'pro') . '" class="firebox-go-pro-link" title="' . fpframework()->_('FPF_UNLOCK_MORE_FEATURES_WITH_PRO_READ_MORE') . '">' . firebox()->_('FB_UPGRADE_20_OFF') . '</a>'
620 ) );
621
622 return $links;
623 }
624
625
626 /**
627 * Runs all Admin Filters
628 *
629 * @return void
630 */
631 private function handleFilters()
632 {
633 add_filter('admin_body_class', [$this, 'setPluginPageBodyClass']);
634 add_filter('plugin_row_meta' , [$this, 'addPluginMetaLinks'], 10, 4);
635 }
636
637 /**
638 * Adds extra links to the plugins page.
639 *
640 * @param array $links
641 * @param string $file
642 * @param array $plugin_data
643 * @param string $status
644 *
645 * @return array
646 */
647 public function addPluginMetaLinks($links, $file, $plugin_data, $status)
648 {
649 if ($file === FBOX_PLUGIN_BASENAME)
650 {
651 $links['rate'] = '<a href="https://wordpress.org/support/plugin/firebox/reviews/#new-post" aria-label="' . esc_attr(firebox()->_('FB_RATE_FIREBOX')) . '" target="_blank">' . esc_html(firebox()->_('FB_RATE_FIREBOX')) . '</a>';
652 $links['support'] = '<a href="' . \FPFramework\Base\Functions::getUTMURL('https://www.fireplugins.com/contact/', '', 'misc', 'support') . '" aria-label="' . esc_attr(fpframework()->_('FPF_SUPPORT')) . '" target="_blank">' . esc_html(fpframework()->_('FPF_SUPPORT')) . '</a>';
653 }
654
655 return $links;
656 }
657
658 /**
659 * Sets a class to the body of the FireBox Admin Pages
660 *
661 * @return string
662 */
663 public function setPluginPageBodyClass($classes)
664 {
665 if (!$this->isPluginPage())
666 {
667 return $classes;
668 }
669
670 $classes .= ' fpf-admin-page fpf-firebox-page';
671
672 if ($this->isControllerPage())
673 {
674 $classes .= ' fpf-controller-page';
675 }
676
677 // Set admin template theme class
678 $fireplugins_theme = isset($_COOKIE['fireplugins_theme']) ? sanitize_key($_COOKIE['fireplugins_theme']) : 'light';
679 $classes .= ' ' . $fireplugins_theme;
680
681 // Set admin template sidebar toggle class
682 $sidebar_state = isset($_COOKIE['fireplugins_sidebar_state']) ? sanitize_key($_COOKIE['fireplugins_sidebar_state']) : 'expand';
683 $classes .= ' ' . ($sidebar_state === 'expand' ? 'fpf-admin-sidebar-expand' : 'fpf-admin-sidebar-shrink');
684
685 return $classes;
686 }
687
688 /**
689 * Checks if we are in a plugin page
690 *
691 * @return boolean
692 */
693 private function isPluginPage()
694 {
695 if (in_array($this->getPageNow(), ['edit.php', 'post-new.php']) && isset($_GET['post_type']) && $_GET['post_type'] == 'firebox') //phpcs:ignore WordPress.Security.NonceVerification.Recommended
696 {
697 return true;
698 }
699
700 if ($this->getPageNow() == 'post.php')
701 {
702 return true;
703 }
704
705 if ($this->isControllerPage())
706 {
707 return true;
708 }
709
710 return false;
711 }
712
713 /**
714 * Whether we are browsing a plugin page from the plugin's menu
715 *
716 * @return boolean
717 */
718 private function isControllerPage()
719 {
720 if (!firebox()->menu)
721 {
722 return false;
723 }
724
725 $current_plugin_page = fpframework()->getPluginPage();
726 $plugin_menu_items = firebox()->menu->getPluginMenuItems();
727
728 // Only set the class to the plugin pages
729 return $this->getPageNow() == 'admin.php' && in_array($current_plugin_page, $plugin_menu_items);
730 }
731
732 /**
733 * Returns page now
734 *
735 * @return string
736 */
737 protected function getPageNow()
738 {
739 global $pagenow;
740 return $pagenow;
741 }
742
743 /**
744 * Registers CSS and JS files
745 *
746 * @return void
747 */
748 public function registerMediaAdminPages()
749 {
750 $this->registerStyles();
751 $this->registerScripts();
752 }
753
754 /**
755 * Register admin styles.
756 *
757 * @return void
758 */
759 public function registerStyles()
760 {
761 // load dashicons
762 wp_enqueue_style('dashicons');
763
764 // firebox main admin css
765 wp_register_style(
766 'firebox-admin',
767 FBOX_MEDIA_ADMIN_URL . 'css/firebox.css',
768 [],
769 FBOX_VERSION,
770 false
771 );
772 wp_enqueue_style('firebox-admin');
773
774 // firebox admin design
775 wp_register_style(
776 'firebox-design-admin',
777 FBOX_MEDIA_ADMIN_URL . 'css/firebox_design.css',
778 [],
779 FBOX_VERSION,
780 false
781 );
782 wp_enqueue_style('firebox-design-admin');
783
784 $css = '
785 :root {
786 --fpf-templates-library-header-logo: url(' . FBOX_MEDIA_ADMIN_URL . 'images/logo.svg);
787 }
788 ';
789 wp_add_inline_style('firebox-admin', $css);
790 }
791
792 /**
793 * Registers admin scripts.
794 *
795 * @return void
796 */
797 public function registerScripts()
798 {
799 wp_register_script('firebox-admin', false);
800 wp_enqueue_script('firebox-admin');
801
802
803
804 $data = array(
805 'campaigns_item_new_url' => admin_url('post-new.php?post_type=firebox'),
806 'campaigns_list_url' => admin_url('admin.php?page=firebox-campaigns'),
807 'campaigns_item_edit_url' => admin_url('post.php?post={{ID}}&action=edit'),
808 'campaigns_item_analytics_url' => admin_url('admin.php?page=firebox-analytics&campaign={{ID}}'),
809 'campaigns_analytics_url' => admin_url('admin.php?page=firebox-analytics'),
810 'submissions_page' => admin_url('admin.php?page=firebox-submissions'),
811 'flags_url' => FBOX_PLUGIN_URL . 'Inc/Framework/media/admin/images/flags/{{FLAG}}.png',
812 'license_type' => FBOX_LICENSE_TYPE,
813 'license_plan' => FBOX_LICENSE_PLAN,
814
815
816 'langs' => [
817 'CAMPAIGN_INFO' => firebox()->_('FB_CAMPAIGN_INFO'),
818 'EDIT_CAMPAIGN' => firebox()->_('FB_EDIT_CAMPAIGN'),
819 'STATUS' => fpframework()->_('FPF_STATUS'),
820 'CREATED' => fpframework()->_('FPF_CREATED'),
821 'LAST_VIEWED' => firebox()->_('FB_LAST_VIEWED'),
822 'ACTIVE' => firebox()->_('FB_ACTIVE'),
823 'DISABLED' => fpframework()->_('FPF_DISABLED'),
824 'ID' => fpframework()->_('FPF_ID'),
825 'CAMPAIGN' => firebox()->_('FB_CAMPAIGN'),
826 'VIEW' => firebox()->_('FB_VIEW'),
827 'VIEWS' => firebox()->_('FB_VIEWS'),
828 'CLICK' => firebox()->_('FB_CLICK'),
829 'CLICKS' => firebox()->_('FB_CLICKS'),
830 'ACTIONS' => firebox()->_('FB_ACTIONS'),
831 'CONVERSION' => firebox()->_('FB_CONVERSION'),
832 'CONVERSIONS' => firebox()->_('FB_CONVERSIONS'),
833 'CONVERSION_RATE' => firebox()->_('FB_CONVERSION_RATE'),
834 'NO_DATA_AVAILABLE' => firebox()->_('FB_NO_DATA_AVAILABLE'),
835 'COUNTRIES' => fpframework()->_('FPF_COUNTRIES'),
836 'FLAG' => fpframework()->_('FPF_FLAG'),
837 'DEVICES' => fpframework()->_('FPF_DEVICES'),
838 'EVENTS' => fpframework()->_('FPF_EVENTS'),
839 'PERCENTAGE_DIFFERENCE_AGAINST_PREVIOUS_PERIOD' => firebox()->_('FB_PERCENTAGE_DIFFERENCE_AGAINST_PREVIOUS_PERIOD'),
840 'NO_CAMPAIGN_DATA_FOUND' => firebox()->_('FB_NO_CAMPAIGN_DATA_FOUND'),
841 'MOST_POPULAR_CAMPAIGNS' => firebox()->_('FB_MOST_POPULAR_CAMPAIGNS'),
842 'TOP_CAMPAIGNS' => firebox()->_('FB_TOP_CAMPAIGNS'),
843 'N/A' => fpframework()->_('FPF_N/A'),
844 'ALL_DAYS' => firebox()->_('FB_ALL_DAYS'),
845 'MONDAY' => firebox()->_('FB_MONDAY'),
846 'TUESDAY' => firebox()->_('FB_TUESDAY'),
847 'WEDNESDAY' => firebox()->_('FB_WEDNESDAY'),
848 'THURSDAY' => firebox()->_('FB_THURSDAY'),
849 'FRIDAY' => firebox()->_('FB_FRIDAY'),
850 'SATURDAY' => firebox()->_('FB_SATURDAY'),
851 'SUNDAY' => firebox()->_('FB_SUNDAY'),
852 'VIEW_HOURS' => firebox()->_('FB_VIEW_HOURS'),
853 'PATHS' => fpframework()->_('FPF_PATHS'),
854 'REFERRERS' => fpframework()->_('FPF_REFERRERS'),
855 'S' => fpframework()->_('FPF_S'),
856 'VIEW_CAMPAIGN_ANALYTICS' => firebox()->_('FB_VIEW_CAMPAIGN_ANALYTICS'),
857 'ACTIVATE' => fpframework()->_('FPF_ACTIVATE'),
858 'DEACTIVATE' => fpframework()->_('FPF_DEACTIVATE'),
859 'EDIT' => fpframework()->_('FPF_EDIT'),
860 'DELETE' => fpframework()->_('FPF_DELETE'),
861 'DUPLICATE' => fpframework()->_('FPF_DUPLICATE'),
862 'ARE_YOU_SURE_YOU_WANT_TO_DELETE_THIS_CAMPAIGN' => firebox()->_('FB_ARE_YOU_SURE_YOU_WANT_TO_DELETE_THIS_CAMPAIGN'),
863 'RECENT_CAMPAIGNS' => firebox()->_('FB_RECENT_CAMPAIGNS'),
864 'VIEW_ALL' => firebox()->_('FB_VIEW_ALL'),
865 'YOU_HAVENT_CREATED_ANY_CAMPAIGNS_YET' => firebox()->_('FB_YOU_HAVENT_CREATED_ANY_CAMPAIGNS_YET'),
866 'NEW_CAMPAIGN' => firebox()->_('FB_NEW_CAMPAIGN'),
867 'NUMBER_OF_VIEWS_IN_THE_LAST_30_DAYS' => firebox()->_('FB_NUMBER_OF_VIEWS_IN_THE_LAST_30_DAYS'),
868 'NUMBER_OF_CONVERSIONS_IN_THE_LAST_30_DAYS' => firebox()->_('FB_NUMBER_OF_CONVERSIONS_IN_THE_LAST_30_DAYS'),
869 'CONVERSION_RATE_IN_THE_LAST_30_DAYS' => firebox()->_('FB_CONVERSION_RATE_IN_THE_LAST_30_DAYS'),
870 'LOADING_CAMPAIGNS' => firebox()->_('FB_LOADING_CAMPAIGNS'),
871 'NO_CAMPAIGNS_FOUND' => firebox()->_('FB_NO_CAMPAIGNS_FOUND'),
872 'SEARCH_DOTS' => firebox()->_('FB_SEARCH_DOTS'),
873 'TODAY' => firebox()->_('FB_TODAY'),
874 'YESTERDAY' => firebox()->_('FB_YESTERDAY'),
875 'LAST_7_DAYS' => firebox()->_('FB_LAST_7_DAYS'),
876 'LAST_30_DAYS' => firebox()->_('FB_LAST_30_DAYS'),
877 'LAST_WEEK' => firebox()->_('FB_LAST_WEEK'),
878 'MONTH_TO_DATE' => firebox()->_('FB_MONTH_TO_DATE'),
879 'LAST_MONTH' => firebox()->_('FB_LAST_MONTH'),
880 'YEAR_TO_DATE' => firebox()->_('FB_YEAR_TO_DATE'),
881 'CUSTOM' => firebox()->_('FB_CUSTOM'),
882 'READ_MORE' => firebox()->_('FB_READ_MORE'),
883 'AVG_TIME_OPEN' => firebox()->_('FB_AVG_TIME_OPEN'),
884 'CONVERSION_RATE_TOOLTIP_DESC' => firebox()->_('FB_CONVERSION_RATE_TOOLTIP_DESC'),
885 'CONVERSIONS_TOOLTIP_DESC' => firebox()->_('FB_CONVERSIONS_TOOLTIP_DESC'),
886 'VS_PREVIOUS_PERIOD' => firebox()->_('FB_VS_PREVIOUS_PERIOD'),
887 'VIEWS_TOOLTIP_DESC' => firebox()->_('FB_VIEWS_TOOLTIP_DESC'),
888 'CLICKS_TOOLTIP_DESC' => firebox()->_('FB_CLICKS_TOOLTIP_DESC'),
889 'NO' => firebox()->_('FB_NO'),
890 'DATA_AVAILABLE' => firebox()->_('FB_DATA_AVAILABLE'),
891 'PERFORMANCE' => firebox()->_('FB_PERFORMANCE'),
892 'TRENDING_TEMPLATES' => firebox()->_('FB_TRENDING_TEMPLATES'),
893 'THERE_ARE_NO_TRENDING_TEMPLATES_TO_SHOW' => firebox()->_('FB_THERE_ARE_NO_TRENDING_TEMPLATES_TO_SHOW'),
894 'INSERT_TEMPLATE' => firebox()->_('FB_INSERT_TEMPLATE'),
895 'INSERT' => firebox()->_('FB_INSERT'),
896 'VIEW_ALL_ANALYTICS' => firebox()->_('FB_VIEW_ALL_ANALYTICS'),
897 'DAILY' => firebox()->_('FB_DAILY'),
898 'WEEKLY' => firebox()->_('FB_WEEKLY'),
899 'MONTHLY' => firebox()->_('FB_MONTHLY'),
900 'UPGRADE_TO_PRO' => fpframework()->_('FPF_UPGRADE_TO_PRO'),
901 'ALL_CAMPAIGNS' => firebox()->_('FB_ALL_CAMPAIGNS'),
902 'OVERVIEW' => fpframework()->_('FPF_OVERVIEW'),
903 'TO' => fpframework()->_('FPF_TO'),
904 'SHOWING_TOP_30_RESULTS' => firebox()->_('FB_SHOWING_TOP_30_RESULTS'),
905 'DAY_OF_THE_WEEK' => firebox()->_('FB_DAY_OF_THE_WEEK'),
906 'ANALYTICS' => fpframework()->_('FPF_ANALYTICS'),
907 'SALES_FUNNEL' => firebox()->_('FB_SALES_FUNNEL'),
908 'SALES_FUNNEL_LOCKED_COPY' => firebox()->_('FB_SALES_FUNNEL_LOCKED_COPY'),
909 'PURCHASE' => firebox()->_('FB_PURCHASE'),
910 'PURCHASES' => firebox()->_('FB_PURCHASES'),
911 'INTERACTIONS' => firebox()->_('FB_INTERACTIONS'),
912 'FUNNEL_VISUALIZATION' => firebox()->_('FB_FUNNEL_VISUALIZATION'),
913 'OVERALL_CONVERSION_RATE' => firebox()->_('FB_OVERALL_CONVERSION_RATE'),
914 'REVENUE_CONVERSIONS' => firebox()->_('FB_REVENUE_CONVERSIONS'),
915 'LITE' => fpframework()->_('FPF_LITE'),
916 'FREE' => fpframework()->_('FPF_FREE'),
917 'PRO' => fpframework()->_('FPF_PRO'),
918 'FROM' => firebox()->_('FB_FROM'),
919 'OF' => firebox()->_('FB_OF'),
920 'USERS' => firebox()->_('FB_USERS'),
921 'TOTAL' => firebox()->_('FB_TOTAL'),
922 'TOTAL_POPUP_IMPRESSIONS' => firebox()->_('FB_TOTAL_POPUP_IMPRESSIONS'),
923 'REVENUE' => firebox()->_('FB_REVENUE'),
924 'REVENUE_TOOLTIP_DESC' => firebox()->_('FB_REVENUE_TOOLTIP_DESC'),
925 'VIEW_THROUGH_REVENUE' => firebox()->_('FB_VIEW_THROUGH_REVENUE'),
926 'VIEW_THROUGH_REVENUE_TOOLTIP_DESC' => firebox()->_('FB_VIEW_THROUGH_REVENUE_TOOLTIP_DESC'),
927 'CONVERSION_THROUGH_REVENUE' => firebox()->_('FB_CONVERSION_THROUGH_REVENUE'),
928 'CONVERSION_THROUGH_REVENUE_TOOLTIP_DESC' => firebox()->_('FB_CONVERSION_THROUGH_REVENUE_TOOLTIP_DESC'),
929 'REVENUE_ROI' => firebox()->_('FB_REVENUE_ROI'),
930 'REVENUE_ROI_TOOLTIP_TITLE' => firebox()->_('FB_REVENUE_ROI_TOOLTIP_TITLE'),
931 'REVENUE_ROI_TOTAL_REVENUE_GENERATED' => firebox()->_('FB_REVENUE_ROI_TOTAL_REVENUE_GENERATED'),
932 'REVENUE_ROI_LITE_MESSAGE' => firebox()->_('FB_REVENUE_ROI_LITE_MESSAGE'),
933 'REVENUE_ROI_PRO_MESSAGE' => firebox()->_('FB_REVENUE_ROI_PRO_MESSAGE'),
934 'LAST_4_WEEKS' => firebox()->_('FB_LAST_4_WEEKS'),
935 'LAST_6_MONTHS' => firebox()->_('FB_LAST_6_MONTHS'),
936 'LAST_12_MONTHS' => firebox()->_('FB_LAST_12_MONTHS'),
937 'QUARTER_TO_DATE' => firebox()->_('FB_QUARTER_TO_DATE'),
938 'AVAILABLE_IN_PRO' => firebox()->_('FB_AVAILABLE_IN_PRO'),
939 'PLAN_COST' => firebox()->_('FB_PLAN_COST'),
940 'LIFETIME_REVENUE' => firebox()->_('FB_LIFETIME_REVENUE'),
941 'YOUR_ROI' => firebox()->_('FB_YOUR_ROI'),
942 'UNLOCK_REVENUE_ROI' => firebox()->_('FB_UNLOCK_REVENUE_ROI'),
943 'GROWTH' => firebox()->_('FB_GROWTH'),
944 'AVAILABLE_IN' => firebox()->_('FB_AVAILABLE_IN'),
945 'PRO' => firebox()->_('FB_PRO'),
946 'BASIC' => firebox()->_('FB_BASIC'),
947 'UPGRADE_TO_X' => fpframework()->_('FPF_UPGRADE_TO_X'),
948 'UPGRADE_TO_X_PLAN' => fpframework()->_('FPF_UPGRADE_TO_X_PLAN'),
949 'FEATURE_AVAILABLE_IN_X_PLAN' => firebox()->_('FB_FEATURE_AVAILABLE_IN_X_PLAN'),
950 'SORRY_FEATURE_NOT_AVAILABLE_IN_YOUR_PLAN' => fpframework()->_('FPF_SORRY_FEATURE_NOT_AVAILABLE_IN_YOUR_PLAN'),
951 'PRO_MODAL_IS_PRO_FEATURE' => fpframework()->_('FPF_PRO_MODAL_IS_PRO_FEATURE'),
952 'PRO_MODAL_WERE_SORRY' => fpframework()->_('FPF_PRO_MODAL_WERE_SORRY'),
953 'PRO_MODAL_PERCENTAGE_OFF' => fpframework()->_('FPF_PRO_MODAL_PERCENTAGE_OFF'),
954 'CLICKS_TOOLTIP_DESC' => firebox()->_('FB_CLICKS_TOOLTIP_DESC'),
955 'VIEW_REVENUE' => firebox()->_('FB_VIEW_REVENUE'),
956 'CONVERSION_REVENUE' => firebox()->_('FB_CONVERSION_REVENUE'),
957 ]
958 );
959
960 wp_localize_script('firebox-admin', 'fbox_admin_js_object', $data);
961 }
962
963 /**
964 * Returns the timezone in format: +-XX:XX
965 *
966 * @return string
967 */
968 private function getTimezone()
969 {
970 $offset = get_option('gmt_offset');
971 $hours = (int) $offset;
972 $minutes = abs(($offset - (int) $offset) * 60);
973 return sprintf('%+03d:%02d', $hours, $minutes);
974 }
975
976
977
978
979
980 /**
981 * Initialize onboarding for new users
982 * Show on FireBox dashboard and all FireBox admin pages
983 *
984 * @return void
985 */
986 public function initOnboarding()
987 {
988 if (!current_user_can('manage_options'))
989 {
990 return;
991 }
992
993 $current_page = isset($_GET['page']) ? sanitize_key($_GET['page']) : ''; //phpcs:ignore WordPress.Security.NonceVerification.Recommended
994 $post_type = isset($_GET['post_type']) ? sanitize_key($_GET['post_type']) : ''; //phpcs:ignore WordPress.Security.NonceVerification.Recommended
995 $post_id = isset($_GET['post']) ? absint($_GET['post']) : 0; //phpcs:ignore WordPress.Security.NonceVerification.Recommended
996
997 $resolved_post_type = $post_type;
998 if (!$resolved_post_type && $post_id)
999 {
1000 $post = get_post($post_id);
1001 $resolved_post_type = $post ? $post->post_type : '';
1002 }
1003
1004 // Allowed FireBox dashboard pages
1005 $allowed_pages = [
1006 'firebox',
1007 'firebox-campaigns',
1008 'firebox-analytics',
1009 'firebox-submissions',
1010 'firebox-settings',
1011 'firebox-import'
1012 ];
1013
1014 $on_firebox_admin_page = in_array($current_page, $allowed_pages, true);
1015 $on_firebox_editor = ($resolved_post_type === 'firebox');
1016
1017 if (!$on_firebox_admin_page && !$on_firebox_editor)
1018 {
1019 return;
1020 }
1021
1022 new Includes\Onboarding();
1023 }
1024
1025 /**
1026 * Redirect to FireBox dashboard after plugin activation
1027 *
1028 * @return void
1029 */
1030 public function redirectAfterActivation()
1031 {
1032 // Check if activation redirect option exists
1033 if (!get_option('firebox_activation_redirect'))
1034 {
1035 return;
1036 }
1037
1038 // Clear the option
1039 delete_option('firebox_activation_redirect');
1040
1041 // Only redirect on the plugins page
1042 if (!isset($_GET['activate'])) //phpcs:ignore WordPress.Security.NonceVerification.Recommended
1043 {
1044 return;
1045 }
1046
1047 // Prevent redirect if activating multiple plugins
1048 if (is_network_admin() || isset($_GET['activate-multi'])) //phpcs:ignore WordPress.Security.NonceVerification.Recommended
1049 {
1050 return;
1051 }
1052
1053 // Redirect to FireBox dashboard
1054 wp_safe_redirect(admin_url('admin.php?page=firebox'));
1055 exit;
1056 }
1057 }
1058