PluginProbe
FireBox – WooCommerce Popup Builder, Exit Intent Popup, Email Optin & Cart Abandonment / 3.1.14
FireBox – WooCommerce Popup Builder, Exit Intent Popup, Email Optin & Cart Abandonment v3.1.14
3.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 All 123 releases
firebox / Inc / Framework / Inc / Base / Conditions / ConditionBuilder.php

ConditionBuilder.php in FireBox – WooCommerce Popup Builder, Exit Intent Popup, Email Optin & Cart Abandonment 3.1.14, at Inc/Framework/Inc/Base/Conditions/ConditionBuilder.php

262 lines 7.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @package FirePlugins Framework
4 * @version 1.2.6
5 *
6 * @author FirePlugins <[email protected]>
7 * @link https://www.fireplugins.com
8 * @copyright Copyright © 2026 FirePlugins All Rights Reserved
9 * @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
10 */
11
12 namespace FPFramework\Base\Conditions;
13
14 if (!defined('ABSPATH'))
15 {
16 exit; // Exit if accessed directly.
17 }
18
19 use FPFramework\Base\Conditions\ConditionsHelper;
20 use FPFramework\Base\Extension;
21 use FPFramework\Base\FieldsParser;
22
23 class ConditionBuilder
24 {
25 public static function pass($rules, $factory = null)
26 {
27 $rules = self::prepareRules($rules);
28
29 if (empty($rules))
30 {
31 return true;
32 }
33
34 return ConditionsHelper::getInstance($factory)->passSets($rules);
35 }
36
37 /**
38 * Like pass(), but defers client-side conditions (Condition::isClientSide())
39 * to the frontend runtime instead of evaluating them on the server.
40 *
41 * Rule groups are OR'ed together; within a group, rules combine per its
42 * matching_method (all|any). Server-side rules are evaluated here; when a
43 * group's outcome still depends on client-side rules, those rules are
44 * returned so the caller can ship them to the browser.
45 *
46 * Returns:
47 * - pass: whether the campaign should be rendered on the page.
48 * - client_groups: groups the browser must resolve before showing the
49 * campaign (empty when a group already passed outright —
50 * the campaign then shows unconditionally).
51 *
52 * @param array $rules
53 * @param object $factory
54 *
55 * @return array ['pass' => bool, 'client_groups' => array]
56 */
57 public static function passWithClientRules($rules, $factory = null)
58 {
59 $rules = self::prepareRules($rules);
60
61 if (empty($rules))
62 {
63 return ['pass' => true, 'client_groups' => []];
64 }
65
66 $helper = ConditionsHelper::getInstance($factory);
67
68 $clientGroups = [];
69
70 foreach ($rules as $group)
71 {
72 $matchingMethod = isset($group['matching_method']) ? $group['matching_method'] : 'all';
73
74 $serverRules = [];
75 $clientRules = [];
76
77 foreach ($group['rules'] as $rule)
78 {
79 if ($helper->isClientSideCondition($rule['name']))
80 {
81 $clientRules[] = [
82 'name' => $rule['name'],
83 'operator' => isset($rule['operator']) ? $rule['operator'] : '',
84 'value' => isset($rule['value']) ? $rule['value'] : ''
85 ];
86 continue;
87 }
88
89 $serverRules[] = $rule;
90 }
91
92 $serverPass = empty($serverRules) ? null : $helper->passSet($serverRules, $matchingMethod);
93
94 if ($matchingMethod === 'any')
95 {
96 // A passing server rule settles the group, and a passing group settles the check.
97 if ($serverPass === true)
98 {
99 return ['pass' => true, 'client_groups' => []];
100 }
101
102 // The group can still pass if a client rule passes in the browser.
103 if (!empty($clientRules))
104 {
105 $clientGroups[] = ['matching_method' => 'any', 'rules' => $clientRules];
106 }
107
108 continue;
109 }
110
111 // 'all': a failing server rule sinks the group regardless of client rules.
112 if ($serverPass === false)
113 {
114 continue;
115 }
116
117 // Every server rule passed; the group is settled unless client rules remain.
118 if (empty($clientRules))
119 {
120 return ['pass' => true, 'client_groups' => []];
121 }
122
123 $clientGroups[] = ['matching_method' => 'all', 'rules' => $clientRules];
124 }
125
126 // No group passed outright: render only if the browser can still resolve one.
127 return [
128 'pass' => !empty($clientGroups),
129 'client_groups' => $clientGroups
130 ];
131 }
132
133 /**
134 * Prepare rules object to run checks
135 *
136 * @return array
137 */
138 public static function prepareRules($rules = [])
139 {
140 if (!$rules || !is_array($rules))
141 {
142 return [];
143 }
144
145 $rules_ = [];
146
147 foreach ($rules as $key => $group)
148 {
149 if (isset($group['enabled']) AND !(bool) $group['enabled'])
150 {
151 continue;
152 }
153
154 // A group without rules, doesn't make sense.
155 if (!isset($group['rules']) OR (isset($group['rules']) AND empty($group['rules'])))
156 {
157 continue;
158 }
159
160 $validRules = [];
161
162 foreach ($group['rules'] as $rule)
163 {
164 // Make sure rule has a name.
165 if (!isset($rule['name']) OR (isset($rule['name']) AND empty($rule['name'])))
166 {
167 continue;
168 }
169
170 // Rule is invalid if both value and params properties are empty
171 if (!isset($rule['value']) && !isset($rule['params']))
172 {
173 continue;
174 }
175
176 if (isset($rule['value']) && is_array($rule['value']) && empty($rule['value']))
177 {
178 continue;
179 }
180
181 // Skip disabled rules
182 if (isset($rule['enabled']) && !(bool) $rule['enabled'])
183 {
184 continue;
185 }
186
187 // We don't need this property.
188 unset($rule['enabled']);
189
190 // Prepare rule value if necessary
191 if (isset($rule['value']))
192 {
193 $rule['value'] = self::prepareRepeaterValue($rule['value']);
194 }
195
196 // Verify operator
197 if (!isset($rule['operator']) OR (isset($rule['operator']) && empty($rule['operator'])))
198 {
199 $rule['operator'] = isset($rule['params']['operator']) ? $rule['params']['operator'] : '';
200 }
201
202 $validRules[] = $rule;
203 }
204
205 if (count($validRules) > 0)
206 {
207 $group['rules'] = $validRules;
208
209 if (!isset($group['matching_method']) OR (isset($group['matching_method']) AND empty($group['matching_method'])))
210 {
211 $group['matching_method'] = 'all';
212 }
213
214 unset($group['enabled']);
215 $rules_[] = $group;
216 }
217 }
218
219 return $rules_;
220 }
221
222 /**
223 * Parse the value of the FPF Repeater Input field.
224 *
225 * @param array $selection
226 *
227 * @return mixed
228 */
229 public static function prepareRepeaterValue($selection)
230 {
231 // Only proceed when we have an array of arrays selection.
232 if (!is_array($selection))
233 {
234 return $selection;
235 }
236
237 $new_selection = [];
238
239 foreach ($selection as $value)
240 {
241 /**
242 * We expect a `value` key for Repeater fields or a key,value pair
243 * for plain arrays.
244 */
245 if (!isset($value['value']))
246 {
247 $new_selection[] = $value;
248 continue;
249 }
250
251 // value must not be empty
252 if (empty(trim($value['value'])))
253 {
254 continue;
255 }
256
257 $new_selection[] = count($value) === 1 ? $value['value'] : $value;
258 }
259
260 return $new_selection;
261 }
262 }