PluginProbe
Bit Form – Contact Form, Payment Forms, Multi Step Forms, Calculator & Custom Form Builder / 2.15.3
Bit Form – Contact Form, Payment Forms, Multi Step Forms, Calculator & Custom Form Builder v2.15.3
3.3.1 V-3.3.0 3.2.2 3.2.1 3.2.0 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 V3.0.3 V3.0.2 -3.0.1 V_3.0.0 1.1.1 1.1.8 1.2 1.3 1.4 1.4.18 1.5.2 1.9 2.0 2.10.0 2.10.1 All 138 releases
← All changes | includes/Core/WorkFlow/Helper.php +46 -318 3.2.22.15.3 View file →
@@ -2,13 +2,11 @@
2 2
3 3 namespace BitCode\BitForm\Core\WorkFlow;
4 4
5 5 use BitCode\BitForm\Core\Integration\IntegrationHandler;
6 -use BitCode\BitForm\Core\Messages\EmailTemplateHandler;
7 6 use BitCode\BitForm\Core\Messages\SuccessMessageHandler;
8 7 use BitCode\BitForm\Core\Util\FieldValueHandler;
9 8 use BitCode\BitForm\Core\Util\SmartTags;
10 -use BitCode\BitForm\Core\Util\Utilities;
11 9
12 10 final class Helper
13 11 {
14 12 public static function getFieldData($fields)
@@ -15,12 +13,11 @@
15 13 {
16 14 $fieldData = [];
17 15
18 16 foreach ($fields as $fieldKey => $fieldDetail) {
19 - $value = isset($fieldDetail->val) ? $fieldDetail->val : (isset($fieldDetail->defaultValue) ? $fieldDetail->defaultValue : '');
20 17 $fieldData[$fieldKey] = [
21 18 'key' => $fieldKey,
22 - 'value' => $value,
19 + 'value' => empty($fieldDetail->val) ? '' : $fieldDetail->val,
23 20 'type' => $fieldDetail->typ,
24 21 ];
25 22 if (isset($fieldDetail->mul)) {
26 23 $fieldData[$fieldKey] =
@@ -57,11 +54,11 @@
57 54 }
58 55 return $fieldData;
59 56 }
60 57
61 - public static function replaceFieldWithValue($stringToReplaceField, $fieldValues, $evalMathExpr = true, $formID = null, $stripShortcodesFromValues = false)
58 + public static function replaceFieldWithValue($stringToReplaceField, $fieldValues, $evalMathExpr = true)
62 59 {
63 - $stringToReplaceField = FieldValueHandler::replaceFieldWithValue($stringToReplaceField, $fieldValues, $formID, $stripShortcodesFromValues);
60 + $stringToReplaceField = FieldValueHandler::replaceFieldWithValue($stringToReplaceField, $fieldValues);
64 61 if ($evalMathExpr) {
65 62 return self::evalMathExpression($stringToReplaceField);
66 63 }
67 64 return $stringToReplaceField;
@@ -66,60 +63,42 @@
66 63 }
67 64 return $stringToReplaceField;
68 65 }
69 66
70 - public static function setDefaultSubmitConfirmation($confirmationType, $fieldValue, $formId, $logID = 0, $workFlowRun = null)
67 + public static function setDefaultSubmitConfirmation($confirmationType, $fieldValue, $formId, $logID = 0)
71 68 {
72 69 $messageId = 0;
73 70 $returnableData = null;
74 - $afterSubmit = null;
75 - $msgDuration = null;
71 + return [
72 + 'msg_id' => $messageId,
73 + 'confirmation' => $returnableData,
74 + ];
76 75 $integrationHandler = new IntegrationHandler($formId);
77 - $conditionalActionIds = self::getDefaultSubmitExcludedActionIds($formId, $workFlowRun);
78 76 switch ($confirmationType) {
79 77 case 'successMsg':
80 - // Standalone confirmation: show the first ENABLED success message without requiring a workflow.
81 - $successMessageHandler = new SuccessMessageHandler($formId);
78 + $successMessageHandler
79 + = new SuccessMessageHandler($formId);
82 80 $successMessage = $successMessageHandler->getAllMessage();
83 - if (!is_wp_error($successMessage) && !empty($successMessage)) {
84 - foreach ($successMessage as $msg) {
85 - $msgConfig = Utilities::jsonObj($msg->message_config);
86 - if (
87 - isset($msgConfig->status) && empty($msgConfig->status)
88 - || isset($conditionalActionIds['successMsg'][(string) $msg->id])
89 - ) {
90 - continue;
91 - }
92 - $returnableData = self::replaceFieldWithValue($msg->message_content, $fieldValue, true, null, true);
93 - $messageId = $msg->id;
94 - if (isset($msgConfig->afterSubmit)) {
95 - $afterSubmit = $msgConfig->afterSubmit;
96 - }
97 - if (!empty($msgConfig->autoHide)) {
98 - $msgDuration = abs(floatval($msgConfig->duration ?? 0) * 1000);
99 - }
100 - break;
101 - }
81 + if (!is_wp_error($successMessage) && !empty($successMessage) && count($successMessage) > 0) {
82 + $returnableData = self::replaceFieldWithValue($successMessage[0]->message_content, $fieldValue);
83 + $messageId = $successMessage[0]->id;
102 84 }
103 85 break;
104 86 case 'redirectPage':
105 - $redirectPages = $integrationHandler->getAllIntegration('form', 'redirectPage', 1);
106 - if (!is_wp_error($redirectPages) && !empty($redirectPages)) {
107 - foreach ($redirectPages as $redirectPage) {
108 - if (isset($conditionalActionIds['redirectPage'][(string) $redirectPage->id])) {
109 - continue;
110 - }
111 - $url = Utilities::jsonObj($redirectPage->integration_details ?? '')->url ?? '';
112 - if (!empty($url)) {
113 - $url = self::replaceFieldWithValue($url, $fieldValue);
114 - }
115 - $returnableData = empty($url) ? '' : esc_url_raw($url);
116 - break;
87 + $redirectPage = $integrationHandler->getAllIntegration('form', 'redirectPage');
88 + if (!is_wp_error($redirectPage) && !empty($redirectPage) && count($redirectPage) > 0) {
89 + $url = json_decode($redirectPage[0]->integration_details)->url;
90 + if (!empty($url)) {
91 + $url = self::replaceFieldWithValue($url, $fieldValue);
117 92 }
93 + $returnableData = empty($url) ? '' : esc_url_raw($url);
118 94 }
119 95 break;
120 96 case 'webHooks':
121 - // Default redirect/webhook remain workflow-driven for now (revisited in the Redirect/Integration phases).
97 + $webHooks = $integrationHandler->getAllIntegration('form', 'webHooks');
98 + if (!is_wp_error($webHooks) && !empty($webHooks) && 1 === count($webHooks)) {
99 + $returnableData = ["{\"id\":{$webHooks[0]->id}}"];
100 + }
122 101 break;
123 102 default:
124 103 break;
125 104 }
@@ -126,195 +105,27 @@
126 105
127 106 return [
128 107 'msg_id' => $messageId,
129 108 'confirmation' => $returnableData,
130 - 'afterSubmit' => $afterSubmit,
131 - 'msg_duration' => $msgDuration,
132 109 ];
133 110 }
134 111
135 - private static function getDefaultSubmitExcludedActionIds($formId, $workFlowRun = null)
112 + public static function calculte($firstOperand, $secondOperand, $operator)
136 113 {
137 - $actionIds = [
138 - 'successMsg' => [],
139 - 'redirectPage' => [],
140 - 'mailNotify' => [],
141 - 'integrations' => [],
142 - ];
143 - $filteredActionIds = apply_filters(
144 - 'bitform_default_submit_confirmation_excluded_action_ids',
145 - $actionIds,
146 - $formId,
147 - $workFlowRun
148 - );
149 -
150 - return is_array($filteredActionIds) ? $filteredActionIds : $actionIds;
151 - }
152 -
153 - public static function getDefaultMailNotifications($formId, $workFlowRun = null)
154 - {
155 - $mailData = [];
156 - $emailTemplateHandler = new EmailTemplateHandler($formId);
157 - $templates = $emailTemplateHandler->getAllTemplate();
158 - if (empty($templates) || is_wp_error($templates)) {
159 - return $mailData;
114 + switch ($operator) {
115 + case '+':
116 + return $firstOperand + $secondOperand;
117 + case '-':
118 + return $firstOperand - $secondOperand;
119 + case '*':
120 + return $firstOperand * $secondOperand;
121 + case '/':
122 + return $firstOperand / $secondOperand;
123 + case '^':
124 + return $firstOperand ** $secondOperand;
160 125 }
161 - $excludedActionIds = self::getDefaultSubmitExcludedActionIds($formId, $workFlowRun);
162 - $arrayFields = ['to', 'cc', 'bcc', 'replyto', 'attachment', 'mediaAttachment', 'pdfIds'];
163 - foreach ($templates as $template) {
164 - $status = isset($template->status) ? (int) $template->status : 1;
165 - if (
166 - 1 !== $status
167 - || isset($excludedActionIds['mailNotify'][(string) $template->id])
168 - ) {
169 - continue;
170 - }
171 - $config = json_decode($template->config);
172 - $details = new \stdClass();
173 - $details->id = wp_json_encode(['id' => (string) $template->id]);
174 - foreach (['to', 'from', 'from_name', 'cc', 'bcc', 'replyto', 'attachment', 'mediaAttachment', 'pdfId', 'pdfIds'] as $key) {
175 - $details->$key = isset($config->$key) ? $config->$key : (in_array($key, $arrayFields, true) ? [] : '');
176 - }
177 - $mailData[] = $details;
178 - }
179 - return $mailData;
180 126 }
181 127
182 - public static function getDefaultIntegrations($formId, $workFlowRun = null)
183 - {
184 - $integrationIds = [];
185 - $integrationHandler = new IntegrationHandler($formId);
186 - $allIntegrations = $integrationHandler->getAllIntegration('form', null, 1);
187 - if (empty($allIntegrations) || is_wp_error($allIntegrations)) {
188 - return $integrationIds;
189 - }
190 - $excludedActionIds = self::getDefaultSubmitExcludedActionIds($formId, $workFlowRun);
191 - foreach ($allIntegrations as $integration) {
192 - if (
193 - 'redirectPage' === $integration->integration_type
194 - || isset($excludedActionIds['integrations'][(string) $integration->id])
195 - ) {
196 - continue;
197 - }
198 - // triggerData['integrations'] is a list of GROUPS; each group is an array of JSON id strings
199 - // (Integrations::executeIntegrations requires is_array() with string members). Wrap each id.
200 - $integrationIds[] = [wp_json_encode(['id' => (string) $integration->id])];
201 - }
202 - return $integrationIds;
203 - }
204 -
205 - /**
206 - * Free implementation of the default-submit exclusion filter: any message / redirect / email /
207 - * integration referenced by a classic/basic onsubmit workflow success action is workflow-gated,
208 - * so it must NOT be default-executed (Pro adds the advanced-CL ids separately). Registered in Hooks.
209 - */
210 - public static function workflowReferencedActionIds($actionIds, $formId, $workFlowRun = null)
211 - {
212 - static $cache = [];
213 -
214 - $actionIds = is_array($actionIds) ? $actionIds : [];
215 - foreach (['successMsg', 'redirectPage', 'mailNotify', 'integrations'] as $bucket) {
216 - if (empty($actionIds[$bucket]) || !is_array($actionIds[$bucket])) {
217 - $actionIds[$bucket] = [];
218 - }
219 - }
220 -
221 - $cacheKey = (string) $formId . ':' . (string) $workFlowRun;
222 - if (!isset($cache[$cacheKey])) {
223 - $workFlow = new WorkFlow($formId);
224 - $rows = $workFlow->getWorkFlow(['create_edit', $workFlowRun ?? 'create'], ['onsubmit'], null, 'workflow_order');
225 - $cache[$cacheKey] = self::collectReferencedActionIds(is_wp_error($rows) ? [] : $rows);
226 - }
227 -
228 - foreach ($cache[$cacheKey] as $bucket => $ids) {
229 - $actionIds[$bucket] = $actionIds[$bucket] + $ids;
230 - }
231 - return $actionIds;
232 - }
233 -
234 - /**
235 - * Extract the message / redirect / email / integration ids referenced by workflow-row success
236 - * actions, grouped into the four exclusion buckets. Shared by the runtime default-submit filter
237 - * and the one-time orphan-deactivation migration (SubmitActionFallback).
238 - *
239 - * @param array $rows workflow rows each having a ->workflow_condition JSON string
240 - *
241 - * @return array{successMsg:array,redirectPage:array,mailNotify:array,integrations:array}
242 - */
243 - public static function collectReferencedActionIds($rows)
244 - {
245 - $referenced = ['successMsg' => [], 'redirectPage' => [], 'mailNotify' => [], 'integrations' => []];
246 - if (empty($rows) || !is_array($rows)) {
247 - return $referenced;
248 - }
249 - foreach ($rows as $row) {
250 - $conditions = json_decode($row->workflow_condition ?? '');
251 - if (empty($conditions) || !is_array($conditions)) {
252 - continue;
253 - }
254 - foreach ($conditions as $condition) {
255 - if (empty($condition->actions->success)) {
256 - continue;
257 - }
258 - foreach ($condition->actions->success as $success) {
259 - if (empty($success->type) || empty($success->details->id)) {
260 - continue;
261 - }
262 - $bucket = self::actionExclusionBucket($success->type);
263 - if (null === $bucket) {
264 - continue;
265 - }
266 - foreach (self::extractActionIds($success->details->id) as $id) {
267 - $referenced[$bucket][$id] = true;
268 - }
269 - }
270 - }
271 - }
272 - return $referenced;
273 - }
274 -
275 - private static function actionExclusionBucket($type)
276 - {
277 - switch ($type) {
278 - case 'successMsg':
279 - return 'successMsg';
280 - case 'redirectPage':
281 - return 'redirectPage';
282 - case 'mailNotify':
283 - return 'mailNotify';
284 - case 'integ':
285 - case 'webHooks':
286 - return 'integrations';
287 - default:
288 - return null;
289 - }
290 - }
291 -
292 - private static function extractActionIds($detailId)
293 - {
294 - $ids = [];
295 - $items = is_array($detailId) ? $detailId : [$detailId];
296 - foreach ($items as $item) {
297 - if (!is_string($item)) {
298 - continue;
299 - }
300 - $decoded = json_decode($item);
301 - if (isset($decoded->id)) {
302 - $ids[] = (string) $decoded->id;
303 - }
304 - }
305 - return $ids;
306 - }
307 -
308 - /**
309 - * @deprecated misspelled duplicate of calculate(); kept because it is public API. Same
310 - * divide-by-zero guard so an external caller cannot fatal either.
311 - */
312 - public static function calculte($firstOperand, $secondOperand, $operator)
313 - {
314 - return self::calculate($firstOperand, $secondOperand, $operator);
315 - }
316 -
317 128 public static function filterMailContentType()
318 129 {
319 130 return 'text/html';
320 131 }
@@ -321,26 +132,11 @@
321 132
322 133 public static function evalMathExpression($stringWithFieldValue)
323 134 {
324 135 $mathExpr = $stringWithFieldValue;
325 - if (empty($mathExpr) || !\is_scalar($mathExpr)) {
136 + if (empty($mathExpr)) {
326 137 return $stringWithFieldValue;
327 138 }
328 - $mathExpr = (string) $mathExpr;
329 -
330 - // The operand/operator checks below only look at \w+ runs and operator runs, so any other
331 - // character was invisible to them. A quoted date ('2020-10-10') therefore passed as a
332 - // subtraction chain and its quotes later surfaced as a bogus operator token. Require the whole
333 - // string to be made of things a formula can contain.
334 - if (1 !== preg_match('#^[0-9.+\-*/^()\[\]{}\s]+$#', $mathExpr)) {
335 - return $stringWithFieldValue;
336 - }
337 -
338 - // A bare date is not a subtraction: 2020-10-10 must stay a date, not become 2000.
339 - if (1 === preg_match('/^\s*\d{4}-\d{1,2}-\d{1,2}\s*$/', $mathExpr)) {
340 - return $stringWithFieldValue;
341 - }
342 -
343 139 preg_match_all('/[\+\-\*\/\s]+/', $mathExpr, $isMathExpr);
344 140 if (empty($isMathExpr[0])) {
345 141 return $stringWithFieldValue;
346 142 }
@@ -362,9 +158,9 @@
362 158 $mathExpr = str_replace(' ', '', $mathExpr);
363 159 $mathExpr = preg_replace('/\{|\[|\(/', '(', $mathExpr);
364 160 $mathExpr = preg_replace('/\}|\]/', ')', $mathExpr);
365 161 $calculated = self::infixToPostfixEvalute($mathExpr);
366 - if (!is_null($calculated) && isset($calculated[0])) {
162 + if (!is_null($calculated)) {
367 163 return (string) $calculated[0];
368 164 }
369 165
370 166 return (string) $stringWithFieldValue;
@@ -388,18 +184,10 @@
388 184 }
389 185 if ('(' === $token) {
390 186 $operatorStack[] = $token;
391 187 } elseif (')' === $token) {
392 - // An unbalanced ')' used to read $operatorStack[-1] and warn on every iteration; treat
393 - // the expression as non-arithmetic instead.
394 - if (empty($operatorStack)) {
395 - return null;
396 - }
397 188 while ('(' !== $operatorStack[count($operatorStack) - 1]) {
398 189 $outputQueue[] = array_pop($operatorStack);
399 - if (empty($operatorStack)) {
400 - return null;
401 - }
402 190 if ('(' === $operatorStack[count($operatorStack) - 1]) {
403 191 array_pop($operatorStack);
404 192 break;
405 193 }
@@ -428,22 +216,11 @@
428 216 if (is_numeric($value)) {
429 217 $resultStack[] = $value;
430 218 continue;
431 219 }
432 - // A token that is neither a number nor a real operator means the input was never an
433 - // expression — e.g. a quoted date whose quotes accumulated into a token like "'2020".
434 - // Bail out so evalMathExpression() returns the caller's string untouched; pushing the
435 - // failure onto the stack would end up blanking that string.
436 - if (!\in_array($value, ['+', '-', '*', '/', '^'], true) || count($resultStack) < 2) {
437 - return null;
438 - }
439 220 $secondOperand = array_pop($resultStack);
440 221 $firstOperand = array_pop($resultStack);
441 - $calculated = self::calculate($firstOperand, $secondOperand, $value);
442 - if (\is_null($calculated)) {
443 - return null;
444 - }
445 - $resultStack[] = $calculated;
222 + $resultStack[] = self::calculate($firstOperand, $secondOperand, $value);
446 223 }
447 224 return $resultStack;
448 225 }
449 226
@@ -459,66 +236,17 @@
459 236
460 237 return isset($precedence[$operator]) ? $precedence[$operator] : 0;
461 238 }
462 239
463 - /**
464 - * Apply one arithmetic operator.
465 - *
466 - * @param mixed $firstOperand
467 - * @param mixed $secondOperand
468 - * @param string $operator
469 - *
470 - * @return float|int|null null on unknown operator, non-numeric operand, or division by zero
471 - */
472 240 public static function calculate($firstOperand, $secondOperand, $operator)
473 241 {
474 - if (!is_numeric($firstOperand) || !is_numeric($secondOperand)) {
475 - return null;
476 - }
477 - $firstOperand = $firstOperand + 0;
478 - $secondOperand = $secondOperand + 0;
242 + $calculated = [
243 + '+' => $firstOperand + $secondOperand,
244 + '-' => $firstOperand - $secondOperand,
245 + '*' => $firstOperand * $secondOperand,
246 + '/' => $firstOperand / $secondOperand,
247 + '^' => $firstOperand ** $secondOperand,
248 + ];
479 249
480 - switch ($operator) {
481 - case '+':
482 - return $firstOperand + $secondOperand;
483 - case '-':
484 - return $firstOperand - $secondOperand;
485 - case '*':
486 - return $firstOperand * $secondOperand;
487 - case '/':
488 - return 0 == $secondOperand ? null : $firstOperand / $secondOperand;
489 - case '^':
490 - return $firstOperand ** $secondOperand;
491 - }
492 -
493 - return null;
494 - }
495 -
496 - /**
497 - * Recursively sets a nested property in a given object.
498 - *
499 - * This function takes an object, a string path representing nested properties
500 - * (e.g., "fk->valid->hide"), and a value to assign. It ensures that all
501 - * intermediate properties exist as objects before setting the final value.
502 - *
503 - * @param object $object The main object where properties should be set.
504 - * @param string $path The nested property path, with keys separated by "->".
505 - * @param mixed $value The value to assign to the final property.
506 - *
507 - * @return void
508 - */
509 - public static function setNestedProperty(&$object, $path, $value)
510 - {
511 - $keys = explode('->', $path);
512 - $key = array_shift($keys);
513 -
514 - if (!isset($object->$key) || !is_object($object->$key)) {
515 - $object->$key = new \stdClass();
516 - }
517 -
518 - if (!empty($keys)) {
519 - self::setNestedProperty($object->$key, implode('->', $keys), $value);
520 - } else {
521 - $object->$key = $value;
522 - }
250 + return isset($calculated[$operator]) ? $calculated[$operator] : '';
523 251 }
524 252 }