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

698 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.1.0 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 $delay = in_array($this->box->params->get('triggermethod'), ['floatingbutton', 'onexternallink']) ? 0 : (int) $this->box->params->get('triggerdelay') * 1000;
434
435 // Use Namespaced classes for each trigger point and let them manipulate the settings dynamicaly.
436 $this->box->settings = [
437 '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'),
438 'trigger_selector' => $this->box->params->get('triggerelement'),
439 'delay' => $delay,
440
441 'animation_open' => $this->box->params->get('animationin'),
442 'animation_close' => $this->box->params->get('animationout'),
443 'animation_duration' => (float) $animation_duration * 1000,
444 'prevent_default' => (bool) $this->box->params->get('preventdefault', true),
445 'backdrop' => (bool) $this->box->params->get('overlay'),
446 'backdrop_color' => $this->box->params->get('overlay_color'),
447 'backdrop_click' => (bool) $this->box->params->get('overlayclick'),
448 'disable_page_scroll' => (bool) $this->box->params->get('preventpagescroll'),
449 'test_mode' => (bool) $this->box->params->get('testmode'),
450 'debug' => (bool) $cParam->get('debug', false),
451
452 'auto_focus' => (bool) $this->box->params->get('autofocus', false)
453 ];
454
455 // Apply Popup CSS
456 $this->box->params->set('customcss', $this->box->params->get('customcss') . $this->css->getCSS());
457
458 $this->replaceBoxSmartTags();
459 }
460
461 /**
462 * Replaces all box smart tags
463 *
464 * @return object
465 */
466 public function replaceBoxSmartTags()
467 {
468 $tags = new \FPFramework\Base\SmartTags\SmartTags();
469
470 // register FB Smart Tags
471 $tags->register('\FireBox\Core\SmartTags', FBOX_BASE_FOLDER . '/Inc/Core/SmartTags', $this->box);
472
473 $this->box = $tags->replace($this->box);
474 }
475
476 /**
477 * Checks if a box passes assignments
478 *
479 * @return boolean
480 */
481 public function pass()
482 {
483 if (!$this->box || !is_object($this->box))
484 {
485 return false;
486 }
487
488 // Check first local assignments
489 if (!$this->passLocalAssignments())
490 {
491 return false;
492 }
493
494 $displayConditionsType = $this->box->params->get('display_conditions_type', '');
495
496 // If empty, display popup sitewide
497 if (empty($displayConditionsType) || $displayConditionsType === 'all')
498 {
499 return true;
500 }
501
502 // Mirror Display Conditions of another popup.
503 if ($displayConditionsType == 'mirror' && $mirror_box_id = $this->box->params->get('mirror_box'))
504 {
505 $this->box->params->merge(self::getAssignmentsForMirroring($mirror_box_id));
506 }
507
508 // Get a recursive array of all rules
509 $rules = json_decode(json_encode($this->box->params->get('rules', [])), true);
510
511 // If testmode is enabled disable the User Groups assignment
512 if ($this->box->params->get('testmode'))
513 {
514 foreach ($rules as $key => &$group)
515 {
516 foreach ($group['rules'] as $_key => &$rule)
517 {
518 if (!isset($rule['name']) || empty($rule['name']))
519 {
520 continue;
521 }
522
523 if ($rule['name'] === 'WP\UserGroup')
524 {
525 unset($group['rules'][$_key]);
526 }
527 }
528 }
529 }
530
531 // Check framework based assignments
532 return \FPFramework\Base\Conditions\ConditionBuilder::pass($rules, $this->factory);
533 }
534
535 /**
536 * Check if a box passes local assignments
537 *
538 * @return boolean
539 */
540 private function passLocalAssignments()
541 {
542 $localAssignments = new \FireBox\Core\FB\Assignments($this, $this->factory);
543 return $localAssignments->passAll();
544 }
545
546 /**
547 * Gets assignments of mirrored box
548 *
549 * @param int $box_id
550 *
551 * @return object
552 */
553 private function getAssignmentsForMirroring($box_id)
554 {
555 $payload = [
556 'where' => [
557 'ID' => ' = ' . intval($box_id),
558 'post_status' => " = 'publish'",
559 'post_type' => " = 'firebox'"
560 ]
561 ];
562
563 // Load box
564 if (!$box = firebox()->tables->box->getResults($payload))
565 {
566 return;
567 }
568
569 $box = $box[0];
570
571 // get meta options for box
572 $meta = get_post_meta($box_id, 'fpframework_meta_settings', true);
573 $box->params = new Registry($meta);
574
575 return new Registry(['rules' => $box->params->get('rules')]);
576 }
577
578 /**
579 * Prefixes the CSS classes
580 *
581 * @param array $classes
582 * @param string $prefix
583 *
584 * @return void
585 */
586 private static function prefixCSSClasses(&$classes, $prefix = 'fb-')
587 {
588 $classes = array_filter($classes);
589
590 if (empty($classes))
591 {
592 return;
593 }
594
595 foreach ($classes as &$class)
596 {
597 $class = $prefix . $class;
598 }
599 }
600
601 /**
602 * Track box open
603 *
604 * @param integer $box_id
605 * @param string $page
606 * @param string $referrer
607 *
608 * @return void
609 */
610 public function logOpenEvent($box_id, $page = null, $referrer = null)
611 {
612 $box = $this->get($box_id);
613
614 // Do not track if statistics option is disabled
615 $track_open_event = (bool) (is_null($box->params->get('stats', null)) ? BoxHelper::getParams()->get('stats', 1) : $box->params->get('stats'));
616 if (!$track_open_event)
617 {
618 return;
619 }
620
621 return firebox()->log->track($box_id, 1, null, $page, $referrer);
622 }
623
624 /**
625 * Track box close
626 *
627 * @param integer $box_id
628 * @param integer $box_log_id
629 *
630 * @return void
631 */
632 public function logCloseEvent($box_id, $box_log_id)
633 {
634 $box = $this->get($box_id);
635
636 // Do not track if statistics option is disabled
637 $track_open_event = (bool) (is_null($box->params->get('stats', null)) ? BoxHelper::getParams()->get('stats', 1) : $box->params->get('stats'));
638 if (!$track_open_event)
639 {
640 return null;
641 }
642
643 firebox()->log->track($box_id, 2, $box_log_id);
644 }
645
646 /**
647 * Get total box impressions
648 *
649 * @param array $payload
650 *
651 * @return array
652 */
653 public function getTotalImpressions($payload)
654 {
655 $impressions = firebox()->tables->boxlog->getResults($payload);
656
657 return count($impressions);
658 }
659
660 /**
661 * Returns the cookie instance.
662 *
663 * @return mixed
664 */
665 public function getCookie()
666 {
667 if (!$this->box)
668 {
669 return;
670 }
671
672 return new Cookie($this->box->id);
673 }
674
675 /**
676 * Returns the box.
677 *
678 * @return object
679 */
680 public function getBox()
681 {
682 return $this->box;
683 }
684
685 /**
686 * Sets the box.
687 *
688 * @param object $box
689 *
690 * @return Box
691 */
692 public function setBox($box)
693 {
694 $this->box = $box;
695
696 return $this;
697 }
698 }