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

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