PluginProbe
FireBox – WooCommerce Popup Builder, Exit Intent Popup, Email Optin & Cart Abandonment / 2.1.23
FireBox – WooCommerce Popup Builder, Exit Intent Popup, Email Optin & Cart Abandonment v2.1.23
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 / FB / Box.php

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

787 lines 17.0 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 2.1.23 Free
5 *
6 * @author FirePlugins <info@fireplugins.com>
7 * @link https://www.fireplugins.com
8 * @copyright Copyright © 2024 FirePlugins All Rights Reserved
9 * @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
10 */
11
12 namespace FireBox\Core\FB;
13
14 if (!defined('ABSPATH'))
15 {
16 exit; // Exit if accessed directly.
17 }
18
19 use FireBox\Core\Helpers\BoxHelper;
20 use FPFramework\Libs\Registry;
21 use FPFramework\Helpers\Fields\DimensionsHelper;
22 use FPFramework\Helpers\CSS;
23
24 class Box
25 {
26 /**
27 * Send useful JS snippet once in first box
28 *
29 * @var boolean
30 */
31 static $loadedLocalizedScript = false;
32
33 /**
34 * The box.
35 *
36 * @param object
37 */
38 private $box = null;
39
40 /**
41 * Factory
42 *
43 * @var Factory
44 */
45 private $factory = null;
46
47 /**
48 * FireBox settings.
49 *
50 * @var object
51 */
52 private $params = null;
53
54 /**
55 * Popup CSS.
56 *
57 * @var CSS
58 */
59 public $css = null;
60
61 /**
62 * Constructor.
63 *
64 * @param object $box
65 * @param object $factory
66 *
67 * @return void
68 */
69 public function __construct($box = null, $factory = null)
70 {
71 if ($box)
72 {
73 $this->box = $this->prepareConstructorBox($box);
74 }
75
76 if (!$factory)
77 {
78 $factory = new \FPFramework\Base\Factory();
79 }
80 $this->factory = $factory;
81
82 $this->params = new Registry(BoxHelper::getParams());
83 }
84
85 /**
86 * Allow to set either a box ID or box object
87 * and we then set the box object.
88 *
89 * @param mixed $box
90 *
91 * @return object
92 */
93 private function prepareConstructorBox($box)
94 {
95 if (!is_object($box))
96 {
97 $box = $this->get($box);
98 }
99
100 return $box;
101 }
102
103 /**
104 * Get a box.
105 *
106 * @param int $id
107 * @param string $status
108 *
109 * @return object
110 */
111 public function get($id = null, $status = null)
112 {
113 if (!$id)
114 {
115 return;
116 }
117
118 $payload = [
119 'where' => [
120 'ID' => ' = ' . esc_sql(intval($id)),
121 'post_type' => " = 'firebox'"
122 ]
123 ];
124
125 // apply status if given
126 if ($status)
127 {
128 $payload['where']['post_status'] = ' = \'' . esc_sql($status) . '\'';
129 }
130
131 if (!$box = firebox()->tables->box->getResults($payload))
132 {
133 return [];
134 }
135
136 if (!isset($box[0]))
137 {
138 return [];
139 }
140
141 $this->box = $box[0];
142
143 // get meta options for box
144 $meta = \FireBox\Core\Helpers\BoxHelper::getMeta($id);
145 $this->box->params = new Registry($meta);
146
147 return $this->box;
148 }
149
150 /**
151 * Renders the box.
152 *
153 * @return void
154 */
155 public function render()
156 {
157 // Check Publishing Assignments
158 if (!$this->pass())
159 {
160 return false;
161 }
162
163 $fbox = $this->box;
164
165 add_action('wp_enqueue_scripts', function() use ($fbox) {
166 // Loads all media files.
167 $this->loadBoxMedia($fbox);
168 });
169
170 /**
171 * Runs before rendering the box.
172 */
173 do_action('firebox/box/before_render', $this->box);
174
175 $this->prepare();
176
177 $css = $this->getCustomCSS();
178
179 add_action('wp_enqueue_scripts', function() use ($fbox, $css) {
180 // Load CSS
181 if ($css)
182 {
183 wp_add_inline_style('firebox', $css);
184 }
185
186
187 });
188
189 // Allow to manipulate the box before rendering
190 $this->box = apply_filters('firebox/box/edit', $this->box);
191
192 // payload
193 $payload = [
194 'box' => $this->box,
195 'params' => $this->params,
196 ];
197
198 // print campaign HTML
199 add_action('wp_footer', function() use ($payload) {
200 echo $this->getFinalCampaignHTML($payload); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
201 });
202
203 return true;
204 }
205
206 public function renderEmbed()
207 {
208 // Check Publishing Assignments
209 if (!$this->pass())
210 {
211 return false;
212 }
213
214 $fbox = $this->box;
215
216 // Loads all media files.
217 $this->loadBoxMedia($fbox);
218
219 /**
220 * Runs before rendering the box.
221 */
222 do_action('firebox/box/before_render', $this->box);
223
224 $this->prepare();
225
226 $css = $this->getCustomCSS();
227
228 wp_register_style('fireboxStyle', false);
229 wp_enqueue_style('fireboxStyle');
230
231 // Load CSS
232 if ($css)
233 {
234 wp_add_inline_style('fireboxStyle', $css);
235 }
236
237
238
239 // Allow to manipulate the box before rendering
240 $this->box = apply_filters('firebox/box/edit', $this->box);
241
242 // payload
243 $payload = [
244 'box' => $this->box,
245 'params' => $this->params,
246 ];
247
248 // return box template
249 return $this->getFinalCampaignHTML($payload);
250 }
251
252 public function getFinalCampaignHTML($payload)
253 {
254 $html = firebox()->renderer->public->render('box', $payload, true);
255
256 /**
257 * Runs after rendering the box.
258 */
259 return apply_filters('firebox/box/after_render', $html, $payload['box']);
260 }
261
262 /**
263 * Gets the Custom CSS of the popup.
264 *
265 * @return string
266 */
267 public function getCustomCSS()
268 {
269 return $this->box->params->get('customcss', '');
270 }
271
272 /**
273 * Send a helpful object to JavaScript files
274 *
275 * @return void
276 */
277 public static function setJSObject()
278 {
279 if (self::$loadedLocalizedScript)
280 {
281 return;
282 }
283 self::$loadedLocalizedScript = true;
284
285 $data = [
286 'ajax_url' => admin_url('admin-ajax.php'),
287 'nonce' => wp_create_nonce('fbox_js_nonce'),
288 'site_url' => site_url('/'),
289 'referrer' => isset($_SERVER['HTTP_REFERER']) ? sanitize_url(wp_unslash($_SERVER['HTTP_REFERER'])) : ''
290 ];
291
292 wp_add_inline_script('firebox-main', 'const fbox_js_object = ' . wp_json_encode($data), 'before');
293 }
294
295 /**
296 * Load Box Media
297 *
298 * @return void
299 */
300 public function loadBoxMedia($box)
301 {
302 $box = new Registry($box);
303
304 /**
305 * Velocity
306 */
307 if ($this->params->get('loadVelocity', true))
308 {
309 wp_enqueue_script(
310 'firebox-velocity',
311 FBOX_MEDIA_PUBLIC_URL . 'js/vendor/velocity.js',
312 [],
313 FBOX_VERSION,
314 true
315 );
316 wp_enqueue_script(
317 'firebox-velocity-ui',
318 FBOX_MEDIA_PUBLIC_URL . 'js/vendor/velocity.ui.js',
319 ['firebox-velocity'],
320 FBOX_VERSION,
321 true
322 );
323
324 /**
325 * Animations
326 */
327 if (strpos($box->get('params.data.animationin'), 'firebox') !== false || strpos($box->get('params.data.animationout'), 'firebox') !== false)
328 {
329 wp_enqueue_script(
330 'firebox-animations',
331 FBOX_MEDIA_PUBLIC_URL . 'js/animations.js',
332 ['firebox-velocity-ui'],
333 FBOX_VERSION,
334 true
335 );
336 }
337 }
338
339 /**
340 * FireBox JS
341 */
342 wp_enqueue_script(
343 'firebox-main',
344 FBOX_MEDIA_PUBLIC_URL . 'js/firebox.js',
345 [],
346 FBOX_VERSION,
347 true
348 );
349
350 // run above the main JS script to run only once
351 self::setJSObject();
352
353 /**
354 * FireBox CSS
355 */
356 if ($this->params->get('loadCSS', true))
357 {
358 wp_enqueue_style(
359 'firebox',
360 FBOX_MEDIA_PUBLIC_URL . 'css/firebox.css',
361 [],
362 FBOX_VERSION
363 );
364 }
365
366 /**
367 * Page Slide mode JS
368 */
369 if ($box->get('params.data.mode') == 'pageslide')
370 {
371 wp_enqueue_script(
372 'firebox-pageslide-mode',
373 FBOX_MEDIA_PUBLIC_URL . 'js/pageslide_mode.js',
374 ['firebox-main'],
375 FBOX_VERSION,
376 true
377 );
378 }
379
380
381
382 $this->loadThemeCSSOverrides();
383 }
384
385 /**
386 * Some themes require overrides to preserve as much as we can the styling of the popups.
387 *
388 * @return void
389 */
390 private function loadThemeCSSOverrides()
391 {
392 $active_theme = wp_get_theme();
393 $theme = $active_theme->template;
394
395 /**
396 * This is the listed of the themes that we have created overrides
397 */
398 $themes = [
399 'twentytwentyone'
400 ];
401
402 if (!in_array($theme, $themes))
403 {
404 return;
405 }
406
407 wp_enqueue_style(
408 'firebox-theme-' . $theme . '-override',
409 FBOX_MEDIA_PUBLIC_URL . 'css/themes/' . $theme . '.css',
410 [],
411 FBOX_VERSION
412 );
413 }
414
415 /**
416 * Prepares the box before rendering
417 *
418 * @return void
419 */
420 public function prepare()
421 {
422 $this->css = new Styling\CSS($this->box);
423
424 $cParam = BoxHelper::getParams();
425 $cParam = new Registry($cParam);
426
427 $this->box->post_content = apply_filters('the_content', $this->box->post_content);
428
429 /* Classes */
430 $css_class = [
431 $this->box->ID
432 ];
433
434 if ($this->box->params->get('mode') === 'popup')
435 {
436 $position = $this->box->params->get('position', '');
437 $position = !is_string($position) ? '' : $position;
438 if ($position)
439 {
440 $css_class[] = $position;
441 }
442 }
443
444 $rtl = $this->box->params->get('rtl', '0');
445 if ($rtl == '1')
446 {
447 $css_class[] = 'rtl';
448 }
449
450 self::prefixCSSClasses($css_class);
451
452 // Class suffix
453 $classSuffix = $this->box->params->get('classsuffix', '');
454 $classSuffix = is_string($classSuffix) ? $classSuffix : '';
455
456 $css_class[] = $classSuffix;
457
458 $this->box->classes = $css_class;
459
460 // Box shadow
461 $boxshadow = (is_string($this->box->params->get('boxshadow', '1')) || is_int($this->box->params->get('boxshadow', '1'))) ? $this->box->params->get('boxshadow', '1') : '0';
462
463 $dialog_css_classes = [
464 $boxshadow != '0' ? 'shd' . $boxshadow : null
465 ];
466
467 // Align Content
468 $aligncontent = is_string($this->box->params->get('aligncontent')) ? explode(' ', $this->box->params->get('aligncontent')) : [];
469 $dialog_css_classes = array_merge($dialog_css_classes, $aligncontent);
470
471 self::prefixCSSClasses($dialog_css_classes);
472 $this->box->dialog_classes = $dialog_css_classes;
473
474 $trigger_point_methods = [
475 'pageready' => 'onPageReady',
476 'pageload' => 'onPageLoad',
477 'onclick' => 'onClick',
478 'elementHover' => 'onHover',
479 'ondemand' => 'onDemand',
480
481 ];
482
483 /* Other Settings */
484 $scroll_depth = $this->box->params->get('scroll_depth', 'percentage');
485 $scroll_depth = is_string($scroll_depth) ? $scroll_depth : '';
486
487 $animation_duration = $this->box->params->get('duration') ? (float) $this->box->params->get('duration') : 0;
488
489 $delay = in_array($this->box->params->get('triggermethod'), ['floatingbutton', 'onexternallink']) ? 0 : (int) $this->box->params->get('triggerdelay') * 1000;
490
491 $trigger_method = (is_string($this->box->params->get('triggermethod'))) && array_key_exists($this->box->params->get('triggermethod'), $trigger_point_methods) ? $trigger_point_methods[$this->box->params->get('triggermethod')] : $this->box->params->get('triggermethod');
492
493 $trigger_element = is_scalar($this->box->params->get('triggerelement', '')) ? $this->box->params->get('triggerelement', '') : '';
494
495 // Use Namespaced classes for each trigger point and let them manipulate the settings dynamicaly.
496 $this->box->settings = [
497 'name' => $this->box->post_title,
498 'trigger' => $trigger_method,
499 'trigger_selector' => $trigger_method === 'onExternalLink' ? '' : rtrim($trigger_element, ','),
500 'delay' => $delay,
501
502 'animation_open' => $this->box->params->get('animationin'),
503 'animation_close' => $this->box->params->get('animationout'),
504 'animation_duration' => (float) $animation_duration * 1000,
505 'prevent_default' => (bool) $this->box->params->get('preventdefault', true),
506 'backdrop' => (bool) $this->box->params->get('overlay'),
507 'backdrop_color' => $this->box->params->get('overlay_color'),
508 'backdrop_click' => (bool) $this->box->params->get('overlayclick'),
509 'disable_page_scroll' => (bool) $this->box->params->get('preventpagescroll'),
510 'test_mode' => (bool) $this->box->params->get('testmode'),
511 'debug' => (bool) $cParam->get('debug', false),
512 'auto_focus' => (bool) $this->box->params->get('autofocus', false),
513 'mode' => $this->box->params->get('mode')
514 ];
515
516 // Apply Popup CSS
517 $this->box->params->set('customcss', $this->box->params->get('customcss') . $this->css->getCSS());
518
519 $this->replaceBoxSmartTags();
520 }
521
522 /**
523 * Replaces all box smart tags
524 *
525 * @return object
526 */
527 public function replaceBoxSmartTags()
528 {
529 $tags = new \FPFramework\Base\SmartTags\SmartTags();
530
531 // register FB Smart Tags
532 $tags->register('\FireBox\Core\SmartTags', FBOX_BASE_FOLDER . '/Inc/Core/SmartTags', $this->box);
533
534 $this->box = $tags->replace($this->box);
535 }
536
537 /**
538 * Checks if a box passes assignments
539 *
540 * @return boolean
541 */
542 public function pass()
543 {
544 if (!$this->box || !is_object($this->box))
545 {
546 return false;
547 }
548
549 // Check first local assignments
550 if (!$this->passLocalAssignments())
551 {
552 return false;
553 }
554
555 $displayConditionsType = $this->box->params->get('display_conditions_type', '');
556
557 // If empty, display popup sitewide
558 if (empty($displayConditionsType) || $displayConditionsType === 'all')
559 {
560 return true;
561 }
562
563 // Mirror Display Conditions of another popup.
564 if ($displayConditionsType == 'mirror' && $mirror_box_id = $this->box->params->get('mirror_box'))
565 {
566 $this->box->params->merge(self::getAssignmentsForMirroring($mirror_box_id));
567 }
568
569 // Get a recursive array of all rules
570 $rules = $this->box->params->get('rules', []);
571 $rules = is_string($rules) ? json_decode($rules, true) : json_decode(wp_json_encode($rules), true);
572
573 // If testmode is enabled disable the User Groups condition
574 if ($this->box->params->get('testmode'))
575 {
576 foreach ($rules as $key => &$group)
577 {
578 foreach ($group['rules'] as $_key => &$rule)
579 {
580 if (!isset($rule['name']) || empty($rule['name']))
581 {
582 continue;
583 }
584
585 if ($rule['name'] === 'WP\UserGroup')
586 {
587 unset($group['rules'][$_key]);
588 }
589 }
590 }
591 }
592
593 // Check framework based conditions
594 return \FPFramework\Base\Conditions\ConditionBuilder::pass($rules, $this->factory);
595 }
596
597 /**
598 * Check if a box passes local conditions
599 *
600 * @return boolean
601 */
602 private function passLocalAssignments()
603 {
604 $localAssignments = new \FireBox\Core\FB\Assignments($this, $this->factory);
605 return $localAssignments->passAll();
606 }
607
608 /**
609 * Gets assignments of mirrored box
610 *
611 * @param int $box_id
612 *
613 * @return object
614 */
615 private function getAssignmentsForMirroring($box_id)
616 {
617 $payload = [
618 'where' => [
619 'ID' => ' = ' . intval($box_id),
620 'post_status' => " = 'publish'",
621 'post_type' => " = 'firebox'"
622 ]
623 ];
624
625 // Load box
626 if (!$box = firebox()->tables->box->getResults($payload))
627 {
628 return;
629 }
630
631 $box = $box[0];
632
633 // get meta options for box
634 $meta = get_post_meta($box_id, 'fpframework_meta_settings', true);
635 $box->params = new Registry($meta);
636
637 return new Registry(['rules' => $box->params->get('rules')]);
638 }
639
640 /**
641 * Prefixes the CSS classes
642 *
643 * @param array $classes
644 * @param string $prefix
645 *
646 * @return void
647 */
648 private static function prefixCSSClasses(&$classes, $prefix = 'fb-')
649 {
650 $classes = array_filter($classes);
651
652 if (empty($classes))
653 {
654 return;
655 }
656
657 foreach ($classes as &$class)
658 {
659 $class = $prefix . $class;
660 }
661 }
662
663 /**
664 * Track box open
665 *
666 * @param integer $box_id
667 * @param string $page
668 * @param string $referrer
669 *
670 * @return void
671 */
672 public function logOpenEvent($box_id, $page = null, $referrer = null)
673 {
674 $box = $this->get($box_id);
675
676 // Do not track if statistics option is disabled
677 $track_open_event = (bool) (is_null($box->params->get('stats', null)) ? BoxHelper::getParams()->get('stats', 1) : $box->params->get('stats'));
678 if (!$track_open_event)
679 {
680 return;
681 }
682
683 return firebox()->log->track($box_id, 1, null, $page, $referrer);
684 }
685
686 /**
687 * Track box close
688 *
689 * @param integer $box_id
690 * @param integer $box_log_id
691 *
692 * @return void
693 */
694 public function logCloseEvent($box_id, $box_log_id)
695 {
696 $box = $this->get($box_id);
697
698 // Do not track if statistics option is disabled
699 $track_open_event = (bool) (is_null($box->params->get('stats', null)) ? BoxHelper::getParams()->get('stats', 1) : $box->params->get('stats'));
700 if (!$track_open_event)
701 {
702 return null;
703 }
704
705 firebox()->log->track($box_id, 2, $box_log_id);
706 }
707
708 /**
709 * Get total box impressions
710 *
711 * @param array $payload
712 *
713 * @return array
714 */
715 public function getTotalImpressions($payload)
716 {
717 $impressions = firebox()->tables->boxlog->getResults($payload);
718
719 return count($impressions);
720 }
721
722 /**
723 * Returns the cookie instance.
724 *
725 * @return mixed
726 */
727 public function getCookie()
728 {
729 if (!$this->box)
730 {
731 return;
732 }
733
734 return new Cookie($this->box);
735 }
736
737 /**
738 * Returns the box.
739 *
740 * @return object
741 */
742 public function getBox()
743 {
744 return $this->box;
745 }
746
747 /**
748 * Sets the box.
749 *
750 * @param object $box
751 *
752 * @return Box
753 */
754 public function setBox($box)
755 {
756 $this->box = $box;
757
758 return $this;
759 }
760
761 public function getParams()
762 {
763 return $this->params;
764 }
765
766 public function setParams($params)
767 {
768 $this->params = $params;
769
770 return $this;
771 }
772
773 public function getCampaignParams()
774 {
775 return isset($this->box->params) ? $this->box->params : null;
776 }
777
778 public function setCampaignParams($params)
779 {
780 if (isset($this->box->params))
781 {
782 $this->box->params = $params;
783 }
784
785 return $this;
786 }
787 }