PluginProbe
FireBox – WooCommerce Popup Builder, Exit Intent Popup, Email Optin & Cart Abandonment / 2.1.4
FireBox – WooCommerce Popup Builder, Exit Intent Popup, Email Optin & Cart Abandonment v2.1.4
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.4, at Inc/Core/FB/Box.php

705 lines 15.7 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.4 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;
161 }
162
163 $fbox = $this->box;
164
165 $this->prepare();
166
167 $css = $this->getCustomCSS();
168
169 add_action('wp_enqueue_scripts', function() use ($fbox, $css) {
170 // Loads all media files.
171 $this->loadBoxMedia($fbox);
172
173 // Load CSS
174 if ($css)
175 {
176 wp_add_inline_style('firebox', $css);
177 }
178
179
180 });
181
182 /**
183 * Runs before rendering the box.
184 */
185 do_action('firebox/box/before_render', $this->box);
186
187 // Allow to manipulate the box before rendering
188 $this->box = apply_filters('firebox/box/edit', $this->box);
189
190 // payload
191 $payload = [
192 'box' => $this->box,
193 'params' => $this->params,
194 ];
195
196 // return box template
197 add_action('wp_footer', function() use ($payload) {
198 echo firebox()->renderer->public->render('box', $payload, true);
199 });
200 }
201
202 /**
203 * Gets the Custom CSS of the popup.
204 *
205 * @return string
206 */
207 private function getCustomCSS()
208 {
209 return $this->box->params->get('customcss', '');
210 }
211
212 /**
213 * Send a helpful object to JavaScript files
214 *
215 * @return void
216 */
217 public static function setJSObject()
218 {
219 if (self::$loadedLocalizedScript)
220 {
221 return;
222 }
223 self::$loadedLocalizedScript = true;
224
225 $data = array(
226 'ajax_url' => admin_url('admin-ajax.php'),
227 'nonce' => wp_create_nonce('fbox_js_nonce'),
228 'site_url' => site_url('/'),
229 'referrer' => isset($_SERVER['HTTP_REFERER']) ? sanitize_text_field($_SERVER['HTTP_REFERER']) : ''
230 );
231
232 wp_localize_script('firebox', 'fbox_js_object', $data);
233 }
234
235 /**
236 * Load Box Media
237 *
238 * @return void
239 */
240 public function loadBoxMedia($box)
241 {
242 $box = new Registry($box);
243
244 // Add polyfills for Internet Explorer
245 $browser = $this->factory->getBrowser();
246 if ($browser && is_array($browser) && array_key_exists('name', $browser) && $browser['name'] === 'ie')
247 {
248 wp_enqueue_script(
249 'firebox-ie11-polyfill',
250 'https://polyfill.io/v3/polyfill.min.js?features=NodeList.prototype.forEach%2CElement.prototype.closest%2CArray.prototype.forEach%2CArray.prototype.find%2CIntersectionObserver%2CIntersectionObserverEntry',
251 [],
252 FBOX_VERSION,
253 true
254 );
255 }
256
257 /**
258 * Velocity
259 */
260 if ($this->params->get('loadVelocity', true))
261 {
262 wp_enqueue_script(
263 'firebox-velocity',
264 FBOX_MEDIA_PUBLIC_URL . 'js/vendor/velocity.js',
265 [],
266 FBOX_VERSION,
267 true
268 );
269 wp_enqueue_script(
270 'firebox-velocity-ui',
271 FBOX_MEDIA_PUBLIC_URL . 'js/vendor/velocity.ui.js',
272 [],
273 FBOX_VERSION,
274 true
275 );
276
277 /**
278 * Animations
279 */
280 if (strpos($box->get('params.data.animationin'), 'firebox') !== false || strpos($box->get('params.data.animationout'), 'firebox') !== false)
281 {
282 wp_enqueue_script(
283 'firebox-animations',
284 FBOX_MEDIA_PUBLIC_URL . 'js/animations.js',
285 [],
286 FBOX_VERSION,
287 true
288 );
289 }
290 }
291
292 /**
293 * FireBox JS
294 */
295 wp_enqueue_script(
296 'firebox',
297 FBOX_MEDIA_PUBLIC_URL . 'js/firebox.js',
298 [],
299 FBOX_VERSION,
300 true
301 );
302
303 // run above the main JS script to run only once
304 self::setJSObject();
305
306 /**
307 * FireBox CSS
308 */
309 if ($this->params->get('loadCSS', true))
310 {
311 wp_enqueue_style(
312 'firebox',
313 FBOX_MEDIA_PUBLIC_URL . 'css/firebox.css',
314 [],
315 FBOX_VERSION
316 );
317 }
318
319 /**
320 * Page Slide mode JS
321 */
322 if ($box->get('params.data.mode') == 'pageslide')
323 {
324 wp_enqueue_script(
325 'firebox-pageslide-mode',
326 FBOX_MEDIA_PUBLIC_URL . 'js/pageslide_mode.js',
327 [],
328 FBOX_VERSION,
329 true
330 );
331 }
332
333
334
335 $this->loadThemeCSSOverrides();
336 }
337
338 /**
339 * Some themes require overrides to preserve as much as we can the styling of the popups.
340 *
341 * @return void
342 */
343 private function loadThemeCSSOverrides()
344 {
345 $active_theme = wp_get_theme();
346 $theme = $active_theme->template;
347
348 /**
349 * This is the listed of the themes that we have created overrides
350 */
351 $themes = [
352 'twentytwentyone'
353 ];
354
355 if (!in_array($theme, $themes))
356 {
357 return;
358 }
359
360 wp_enqueue_style(
361 'firebox-theme-' . $theme . '-override',
362 FBOX_MEDIA_PUBLIC_URL . 'css/themes/' . $theme . '.css',
363 [],
364 FBOX_VERSION
365 );
366 }
367
368 /**
369 * Prepares the box before rendering
370 *
371 * @return void
372 */
373 public function prepare()
374 {
375 $this->css = new Styling\CSS($this->box);
376
377 $cParam = BoxHelper::getParams();
378 $cParam = new Registry($cParam);
379
380 $this->box->post_content = apply_filters('the_content', $this->box->post_content);
381
382 $position = $this->box->params->get('position', '');
383 $position = !is_string($position) ? '' : $position;
384
385 /* Classes */
386 $css_class = [
387 $this->box->ID,
388 $position
389 ];
390
391 $rtl = $this->box->params->get('rtl', '0');
392 if ($rtl == '1')
393 {
394 $css_class[] = 'rtl';
395 }
396
397 self::prefixCSSClasses($css_class);
398
399 // Class suffix
400 $classSuffix = $this->box->params->get('classsuffix', '');
401 $classSuffix = is_string($classSuffix) ? $classSuffix : '';
402
403 $css_class[] = $classSuffix;
404
405 $this->box->classes = $css_class;
406
407 // Box shadow
408 $boxshadow = (is_string($this->box->params->get('boxshadow', '1')) || is_int($this->box->params->get('boxshadow', '1'))) ? $this->box->params->get('boxshadow', '1') : '0';
409
410 $dialog_css_classes = [
411 $boxshadow != '0' ? 'shd' . $boxshadow : null
412 ];
413
414 // Align Content
415 $aligncontent = is_string($this->box->params->get('aligncontent')) ? explode(' ', $this->box->params->get('aligncontent')) : [];
416 $dialog_css_classes = array_merge($dialog_css_classes, $aligncontent);
417
418 self::prefixCSSClasses($dialog_css_classes);
419 $this->box->dialog_classes = $dialog_css_classes;
420
421 $trigger_point_methods = [
422 'pageready' => 'onPageReady',
423 'pageload' => 'onPageLoad',
424 'onclick' => 'onClick',
425 'elementHover' => 'onHover',
426 'ondemand' => 'onDemand',
427
428 ];
429
430 /* Other Settings */
431 $scroll_depth = $this->box->params->get('scroll_depth', 'percentage');
432 $scroll_depth = is_string($scroll_depth) ? $scroll_depth : '';
433
434 $animation_duration = $this->box->params->get('duration') ? (float) $this->box->params->get('duration') : 0;
435
436 $delay = in_array($this->box->params->get('triggermethod'), ['floatingbutton', 'onexternallink']) ? 0 : (int) $this->box->params->get('triggerdelay') * 1000;
437
438 $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');
439
440 $trigger_element = is_scalar($this->box->params->get('triggerelement', '')) ? $this->box->params->get('triggerelement', '') : '';
441
442 // Use Namespaced classes for each trigger point and let them manipulate the settings dynamicaly.
443 $this->box->settings = [
444 'name' => $this->box->post_title,
445 'trigger' => $trigger_method,
446 'trigger_selector' => $trigger_method === 'onExternalLink' ? '' : rtrim($trigger_element, ','),
447 'delay' => $delay,
448
449 'animation_open' => $this->box->params->get('animationin'),
450 'animation_close' => $this->box->params->get('animationout'),
451 'animation_duration' => (float) $animation_duration * 1000,
452 'prevent_default' => (bool) $this->box->params->get('preventdefault', true),
453 'backdrop' => (bool) $this->box->params->get('overlay'),
454 'backdrop_color' => $this->box->params->get('overlay_color'),
455 'backdrop_click' => (bool) $this->box->params->get('overlayclick'),
456 'disable_page_scroll' => (bool) $this->box->params->get('preventpagescroll'),
457 'test_mode' => (bool) $this->box->params->get('testmode'),
458 'debug' => (bool) $cParam->get('debug', false),
459 'auto_focus' => (bool) $this->box->params->get('autofocus', false)
460 ];
461
462 // Apply Popup CSS
463 $this->box->params->set('customcss', $this->box->params->get('customcss') . $this->css->getCSS());
464
465 $this->replaceBoxSmartTags();
466 }
467
468 /**
469 * Replaces all box smart tags
470 *
471 * @return object
472 */
473 public function replaceBoxSmartTags()
474 {
475 $tags = new \FPFramework\Base\SmartTags\SmartTags();
476
477 // register FB Smart Tags
478 $tags->register('\FireBox\Core\SmartTags', FBOX_BASE_FOLDER . '/Inc/Core/SmartTags', $this->box);
479
480 $this->box = $tags->replace($this->box);
481 }
482
483 /**
484 * Checks if a box passes assignments
485 *
486 * @return boolean
487 */
488 public function pass()
489 {
490 if (!$this->box || !is_object($this->box))
491 {
492 return false;
493 }
494
495 // Check first local assignments
496 if (!$this->passLocalAssignments())
497 {
498 return false;
499 }
500
501 $displayConditionsType = $this->box->params->get('display_conditions_type', '');
502
503 // If empty, display popup sitewide
504 if (empty($displayConditionsType) || $displayConditionsType === 'all')
505 {
506 return true;
507 }
508
509 // Mirror Display Conditions of another popup.
510 if ($displayConditionsType == 'mirror' && $mirror_box_id = $this->box->params->get('mirror_box'))
511 {
512 $this->box->params->merge(self::getAssignmentsForMirroring($mirror_box_id));
513 }
514
515 // Get a recursive array of all rules
516 $rules = json_decode(json_encode($this->box->params->get('rules', [])), true);
517
518 // If testmode is enabled disable the User Groups assignment
519 if ($this->box->params->get('testmode'))
520 {
521 foreach ($rules as $key => &$group)
522 {
523 foreach ($group['rules'] as $_key => &$rule)
524 {
525 if (!isset($rule['name']) || empty($rule['name']))
526 {
527 continue;
528 }
529
530 if ($rule['name'] === 'WP\UserGroup')
531 {
532 unset($group['rules'][$_key]);
533 }
534 }
535 }
536 }
537
538 // Check framework based assignments
539 return \FPFramework\Base\Conditions\ConditionBuilder::pass($rules, $this->factory);
540 }
541
542 /**
543 * Check if a box passes local assignments
544 *
545 * @return boolean
546 */
547 private function passLocalAssignments()
548 {
549 $localAssignments = new \FireBox\Core\FB\Assignments($this, $this->factory);
550 return $localAssignments->passAll();
551 }
552
553 /**
554 * Gets assignments of mirrored box
555 *
556 * @param int $box_id
557 *
558 * @return object
559 */
560 private function getAssignmentsForMirroring($box_id)
561 {
562 $payload = [
563 'where' => [
564 'ID' => ' = ' . intval($box_id),
565 'post_status' => " = 'publish'",
566 'post_type' => " = 'firebox'"
567 ]
568 ];
569
570 // Load box
571 if (!$box = firebox()->tables->box->getResults($payload))
572 {
573 return;
574 }
575
576 $box = $box[0];
577
578 // get meta options for box
579 $meta = get_post_meta($box_id, 'fpframework_meta_settings', true);
580 $box->params = new Registry($meta);
581
582 return new Registry(['rules' => $box->params->get('rules')]);
583 }
584
585 /**
586 * Prefixes the CSS classes
587 *
588 * @param array $classes
589 * @param string $prefix
590 *
591 * @return void
592 */
593 private static function prefixCSSClasses(&$classes, $prefix = 'fb-')
594 {
595 $classes = array_filter($classes);
596
597 if (empty($classes))
598 {
599 return;
600 }
601
602 foreach ($classes as &$class)
603 {
604 $class = $prefix . $class;
605 }
606 }
607
608 /**
609 * Track box open
610 *
611 * @param integer $box_id
612 * @param string $page
613 * @param string $referrer
614 *
615 * @return void
616 */
617 public function logOpenEvent($box_id, $page = null, $referrer = null)
618 {
619 $box = $this->get($box_id);
620
621 // Do not track if statistics option is disabled
622 $track_open_event = (bool) (is_null($box->params->get('stats', null)) ? BoxHelper::getParams()->get('stats', 1) : $box->params->get('stats'));
623 if (!$track_open_event)
624 {
625 return;
626 }
627
628 return firebox()->log->track($box_id, 1, null, $page, $referrer);
629 }
630
631 /**
632 * Track box close
633 *
634 * @param integer $box_id
635 * @param integer $box_log_id
636 *
637 * @return void
638 */
639 public function logCloseEvent($box_id, $box_log_id)
640 {
641 $box = $this->get($box_id);
642
643 // Do not track if statistics option is disabled
644 $track_open_event = (bool) (is_null($box->params->get('stats', null)) ? BoxHelper::getParams()->get('stats', 1) : $box->params->get('stats'));
645 if (!$track_open_event)
646 {
647 return null;
648 }
649
650 firebox()->log->track($box_id, 2, $box_log_id);
651 }
652
653 /**
654 * Get total box impressions
655 *
656 * @param array $payload
657 *
658 * @return array
659 */
660 public function getTotalImpressions($payload)
661 {
662 $impressions = firebox()->tables->boxlog->getResults($payload);
663
664 return count($impressions);
665 }
666
667 /**
668 * Returns the cookie instance.
669 *
670 * @return mixed
671 */
672 public function getCookie()
673 {
674 if (!$this->box)
675 {
676 return;
677 }
678
679 return new Cookie($this->box->id);
680 }
681
682 /**
683 * Returns the box.
684 *
685 * @return object
686 */
687 public function getBox()
688 {
689 return $this->box;
690 }
691
692 /**
693 * Sets the box.
694 *
695 * @param object $box
696 *
697 * @return Box
698 */
699 public function setBox($box)
700 {
701 $this->box = $box;
702
703 return $this;
704 }
705 }