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

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