PluginProbe
Bit Form – Contact Form, Payment Forms, Multi Step Forms, Calculator & Custom Form Builder / 2.21.4
Bit Form – Contact Form, Payment Forms, Multi Step Forms, Calculator & Custom Form Builder v2.21.4
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 2.10.2 All 137 releases
← All changes | includes/Admin/Form/FrontEndScriptGenerator.php +170 -92 3.2.22.21.4 View file →
@@ -1,14 +1,21 @@
1 1 <?php
2 2
3 3 namespace BitCode\BitForm\Admin\Form;
4 4
5 -if (!defined('ABSPATH')) {
6 - exit;
7 -}
8 -
5 +use BitCode\BitForm\Admin\Form\InitJs\HCaptcha;
6 +use BitCode\BitForm\Admin\Form\InitJs\Paypal;
7 +use BitCode\BitForm\Admin\Form\InitJs\Razorpay;
8 +use BitCode\BitForm\Admin\Form\InitJs\Recaptcha;
9 +use BitCode\BitForm\Admin\Form\InitJs\RecaptchaV3;
10 +use BitCode\BitForm\Admin\Form\InitJs\ScriptLoader;
11 +use BitCode\BitForm\Admin\Form\InitJs\Stripe;
12 +use BitCode\BitForm\Admin\Form\InitJs\Turnstile;
9 13 use BitCode\BitForm\Core\Util\FileHandler;
10 14 use BitCode\BitForm\Core\Util\Log;
15 +use BitCode\BitForm\Core\Util\Utilities;
16 +use BitCode\BitForm\Core\WorkFlow\WorkFlowHandler;
17 +use BitCode\BitFormPro\Admin\FormSettings\FormAbandonment;
11 18 use WP_Error;
12 19
13 20 class FrontEndScriptGenerator
14 21 {
@@ -30,10 +37,11 @@
30 37
31 38 private static function generateBfGlobalObjJS($contentIds = [])
32 39 {
33 40 $contentidArray = wp_json_encode($contentIds);
34 - return ' if(!window.bf_globals){ window.bf_globals = {};}
35 - ' . $contentidArray . '.forEach(function(contentId){
41 + return <<<GLOBALOBJ
42 + if(!window.bf_globals){ window.bf_globals = {};}
43 + $contentidArray.forEach(function(contentId){
36 44 const form = document.getElementById(contentId);
37 45 if(!form){
38 46 delete window.bf_globals[contentId];
39 47 return;
@@ -44,14 +52,15 @@
44 52 window.bf_globals[contentId].inits = {};
45 53 window.bf_globals[contentId].contentId = contentId;
46 54 }
47 55
48 - });';
56 + });
57 +GLOBALOBJ;
49 58 }
50 59
51 60 private static function isValidationNeeded($fldData)
52 61 {
53 - $validationsToCheck = ['valid->req', 'valid->regexr', 'mn', 'mx', 'opt', 'err->invalid->show', 'err->notVerified->show'];
62 + $validationsToCheck = ['valid->req', 'valid->regexr', 'mn', 'mx', 'opt', 'err->invalid->show'];
54 63 foreach ($validationsToCheck as $property) {
55 64 $needValidation = Helpers::property_exists_nested($fldData, $property);
56 65 if ($needValidation) {
57 66 return true;
@@ -85,11 +94,8 @@
85 94
86 95 // for hidden Field when cache plugin on
87 96 $this->jsHiddenFieldScript();
88 97
89 - // for recaptcha v3 (form-level setting)
90 - $this->jsRecaptchaV3Scripts();
91 -
92 98 // for form abandonment scripts
93 99 $this->jsFormAbandonmentScripts();
94 100
95 101 // multi step form scripts
@@ -139,24 +145,55 @@
139 145 }
140 146
141 147 private function jsFormAbandonmentScripts()
142 148 {
143 - /**
144 - * Add-ons can inject required script files here.
145 - *
146 - * @param array $files Array of file arrays: ['priority' => int, 'filename' => string]
147 - * @param array $formContents
148 - * @param array $fields
149 - */
150 - $files = apply_filters('bitform_form_abandonment_script_files', [], $this->_formContents, $this->_fields);
151 - if (empty($files) || !is_array($files)) {
149 + if (!Utilities::isPro() || !class_exists('\BitCode\BitFormPro\Admin\FormSettings\FormAbandonment')) {
152 150 return;
153 151 }
154 - foreach ($files as $jsFile) {
155 - if (!empty($jsFile['filename']) && !empty($jsFile['priority'])) {
156 - $this->addScriptInLoadedScriptsList($jsFile);
152 + // check if any of the form has form abandonment enabled
153 + $allFiles = [];
154 + foreach ($this->_formContents as $formContent) {
155 + $formAbandonmentSettings = FormAbandonment::getFormAbandonmentSettings($formContent->formId);
156 + if (!empty($formAbandonmentSettings->saveFormDraft)) {
157 + $neededFiles = ScriptFilePriorityManager::formAbandonmentNeededFiles('autoSave');
158 + $allFiles = array_merge($allFiles, $neededFiles);
159 + break;
157 160 }
161 +
162 + $workflowHandler = new WorkFlowHandler($formContent->formId);
163 + $allWorkflows = $workflowHandler->getAllworkFlow();
164 + foreach ($allWorkflows as $workflow) {
165 + foreach ($workflow['conditions'] as $cond) {
166 + if (!empty($cond->actions) && !empty($cond->actions->fields)) {
167 + foreach ($cond->actions->fields as $fldAction) {
168 + if (empty($fldAction->field) || empty($fldAction->action)) {
169 + continue;
170 + }
171 + if ('_bf_form' === $fldAction->field && 'save_draft' === $fldAction->action) {
172 + $neededFiles = ScriptFilePriorityManager::formAbandonmentNeededFiles();
173 + $allFiles = array_merge($allFiles, $neededFiles);
174 + }
175 + }
176 + }
177 + }
178 + }
158 179 }
180 + if (isset($this->_fields['button'])) {
181 + foreach ($this->_fields['button'] as $button) {
182 + if ('save-draft' === $button['field']->btnTyp) {
183 + $neededFiles = ScriptFilePriorityManager::formAbandonmentNeededFiles();
184 + $allFiles = array_merge($allFiles, $neededFiles);
185 + break;
186 + }
187 + }
188 + }
189 + //
190 + if (empty($allFiles)) {
191 + return;
192 + }
193 + foreach ($allFiles as $jsFile) {
194 + $this->addScriptInLoadedScriptsList($jsFile);
195 + }
159 196 }
160 197
161 198 private function appendJs($script, $postId, $previewMode, $mode = 'a')
162 199 {
@@ -184,12 +221,22 @@
184 221
185 222 $script = '';
186 223 foreach ($this->_loadedScriptsList as $scriptFileArr) {
187 224 $fileNam = $scriptFileArr['filename'];
188 - $fileContent = self::getFileFromAssetsJs($fileNam);
189 - if ($fileContent) {
190 - $script .= $fileContent;
225 + if (!isset($scriptFileArr['scriptTyp']) || 'script' === $scriptFileArr['scriptTyp']) {
226 + if (self::getFileFromAssetsJs($fileNam)) {
227 + $script .= self::getFileFromAssetsJs($fileNam);
228 + continue;
229 + }
230 + continue;
191 231 }
232 + if ('custom' === $scriptFileArr['scriptTyp']) {
233 + $fileInstance = $scriptFileArr['source'] . $fileNam;
234 + if (!class_exists($fileInstance)) {
235 + continue;
236 + } // when class not found, skip load script
237 + $script .= $fileInstance::init($scriptFileArr['fk'], $scriptFileArr['field'], $scriptFileArr['contentId']);
238 + }
192 239 }
193 240 return $script;
194 241 }
195 242
@@ -197,12 +244,8 @@
197 244 {
198 245 foreach ($this->_fields as $flds) {
199 246 foreach ($flds as $fld) {
200 247 $fldData = $fld['field'];
201 - // Corrupt/partial form JSON can produce a null field or one without typ.
202 - if (!is_object($fldData)) {
203 - continue;
204 - }
205 248 // for validation js files
206 249 if (self::isValidationNeeded($fldData)) {
207 250 $validation = $this->_validationJsFilesNeeded['validation'];
208 251 $this->addScriptInLoadedScriptsList($validation);
@@ -254,9 +297,8 @@
254 297 }
255 298
256 299 private function jsFieldsNeededFile()
257 300 {
258 - $filePondPluginList = apply_filters('bitform_filepond_plugins_list', []);
259 301 foreach ($this->_fields as $typ => $flds) {
260 302 if (!array_key_exists($typ, $this->_jsFilesNeeded)) {
261 303 continue;
262 304 }
@@ -266,30 +308,26 @@
266 308 if ('advanced-file-up' === $typ) {
267 309 $configs = $fld['field']->config;
268 310 foreach ($configs as $configKey => $config) {
269 311 if ($configs->$configKey) {
270 - if (array_key_exists($configKey, $filePondPluginList)) {
271 - $this->addScriptInLoadedScriptsList($filePondPluginList[$configKey]);
312 + $filepondPlugin = ScriptFilePriorityManager::filePondPlugins($configKey);
313 + if ($filepondPlugin) {
314 + $this->addScriptInLoadedScriptsList($filepondPlugin);
272 315 }
273 316 }
274 317 }
275 318 }
276 319 foreach ($fldScriptArr as $scriptFile) {
277 - if (isset($scriptFile['paths']) && is_array($scriptFile['paths'])) {
278 - $pathMatched = false;
279 - foreach ($scriptFile['paths'] as $path) {
280 - if (Helpers::property_exists_nested($fld['field'], $path)) {
281 - $pathMatched = true;
282 - break;
283 - }
284 - }
285 - if (!$pathMatched) {
286 - continue;
287 - }
288 - } elseif (isset($scriptFile['path']) && !Helpers::property_exists_nested($fld['field'], $scriptFile['path'])) {
320 + if (!isset($scriptFile['scriptTyp'])) {
321 + $this->addScriptInLoadedScriptsList($scriptFile);
289 322 continue;
290 323 }
291 - $this->addScriptInLoadedScriptsList($scriptFile);
324 + if ('custom' === $scriptFile['scriptTyp'] && Helpers::property_exists_nested($fld['field'], $scriptFile['path'], true)) {
325 + $scriptFile['field'] = $fld['field'];
326 + $scriptFile['fk'] = $fld['fk'];
327 + $scriptFile['contentId'] = $fld['contentId'];
328 + $this->addScriptInLoadedScriptsList($scriptFile);
329 + }
292 330 }
293 331 }
294 332 }
295 333 }
@@ -369,9 +407,8 @@
369 407 return $customCodes;
370 408 }
371 409
372 410 private $fldContainersByType = [
373 - 'address' => '.__$fk__-parent-fld-wrp',
374 411 'select' => '.__$fk__-dpd-fld-wrp',
375 412 'country' => '.__$fk__-country-fld-wrp',
376 413 'currency' => '.__$fk__-currency-fld-wrp',
377 414 'phone-number' => '.__$fk__-phone-fld-wrp',
@@ -384,9 +421,8 @@
384 421 'mollie' => '.__$fk__-mollie-wrp',
385 422 'repeater' => '.__$fk__-rpt-fld-wrp',
386 423 'signature' => '.__$fk__-inp-fld-wrp',
387 424 'rating' => '.__$fk__-inp-fld-wrp',
388 - 'email-otp' => '.__$fk__-inp-fld-wrp',
389 425 'hcaptcha' => '.__$fk__-h-captcha-wrp',
390 426 'advanced-datetime' => '.__$fk__-advanced-datetime',
391 427 ];
392 428
@@ -391,9 +427,9 @@
391 427 ];
392 428
393 429 private function generateFieldConfigsJs()
394 430 {
395 - $customFlds = ['address', 'select', 'country', 'currency', 'phone-number', 'file-up', 'advanced-file-up', 'paypal', 'razorpay', 'stripe', 'mollie', 'recaptcha', 'repeater', 'signature', 'rating', 'turnstile', 'hcaptcha', 'advanced-datetime', 'email-otp'];
431 + $customFlds = ['select', 'country', 'currency', 'phone-number', 'file-up', 'advanced-file-up', 'paypal', 'razorpay', 'stripe', 'mollie', 'recaptcha', 'repeater', 'signature', 'rating', 'turnstile', 'hcaptcha', 'advanced-datetime'];
396 432 $allFieldTypes = array_keys($this->_fields);
397 433 $customFldsInForms = array_intersect($allFieldTypes, $customFlds);
398 434 $formContents = $this->_formContents;
399 435 $recaptchaV3Enabled = false;
@@ -415,10 +451,10 @@
415 451 }
416 452
417 453 $customFldConfigPaths = [];
418 454
419 - $allConfs = ScriptFilePriorityManager::getAllFldConfs();
420 455 foreach ($customFldsInForms as $customFldTyp) {
456 + $allConfs = ScriptFilePriorityManager::getAllFldConfs();
421 457 if (isset($allConfs[$customFldTyp])) {
422 458 $customFldConfigPaths[$customFldTyp] = $allConfs[$customFldTyp];
423 459 } else {
424 460 $customFldConfigPaths[$customFldTyp] = (object) [];
@@ -427,45 +463,103 @@
427 463
428 464 $customFldConfigPaths = wp_json_encode($customFldConfigPaths);
429 465 $containers = wp_json_encode($containers);
430 466
431 - $script = ' const customFldConfigPaths = ' . $customFldConfigPaths . ';
432 - const fldContainers = ' . $containers . ';
467 + $scriptLoaderFields = ['paypal', 'razorpay', 'stripe', 'recaptcha', 'turnstile', 'hcaptcha'];
468 + $scriptLoadedNeeded = array_intersect($scriptLoaderFields, $customFldsInForms) || $recaptchaV3Enabled;
469 + if ($scriptLoadedNeeded) {
470 + $scriptLoaderJs = ScriptLoader::init();
471 + } else {
472 + $scriptLoaderJs = '';
473 + }
474 +
475 + if (in_array('paypal', $customFldsInForms)) {
476 + $paypalInitJs = Paypal::init();
477 + } else {
478 + $paypalInitJs = '';
479 + }
480 +
481 + if (in_array('razorpay', $customFldsInForms)) {
482 + $razorpayInitJs = Razorpay::init();
483 + } else {
484 + $razorpayInitJs = '';
485 + }
486 +
487 + if (in_array('stripe', $customFldsInForms)) {
488 + $stripeInitJs = Stripe::init();
489 + } else {
490 + $stripeInitJs = '';
491 + }
492 +
493 + if (in_array('mollie', $customFldsInForms)) {
494 + $mollieInitJs = Stripe::init();
495 + } else {
496 + $mollieInitJs = '';
497 + }
498 +
499 + if (in_array('recaptcha', $customFldsInForms)) {
500 + $recaptchaInitJs = Recaptcha::init();
501 + } else {
502 + $recaptchaInitJs = '';
503 + }
504 +
505 + if (in_array('turnstile', $customFldsInForms)) {
506 + $turnstileInitJs = Turnstile::init();
507 + } else {
508 + $turnstileInitJs = '';
509 + }
510 +
511 + if (in_array('hcaptcha', $customFldsInForms)) {
512 + $hCaptchaInitJs = HCaptcha::init();
513 + } else {
514 + $hCaptchaInitJs = '';
515 + }
516 +
517 + if ($recaptchaV3Enabled) {
518 + $recaptchaV3InitJs = RecaptchaV3::init();
519 + } else {
520 + $recaptchaV3InitJs = '';
521 + }
522 +
523 + $script = <<<FIELDCONFIGJS
524 + const customFldConfigPaths = $customFldConfigPaths;
525 + const fldContainers = $containers;
433 526
527 + $scriptLoaderJs;
528 +
434 529 function initAllCustomFlds (formContentId = null) {
435 530 const allContendIds = formContentId ? [formContentId] : Object.keys(bf_globals);
436 531 allContendIds.forEach((contentId) => {
437 532 const contentData = bf_globals[contentId];
438 - if(!contentData?.inits) contentData.inits = {};
439 533 const flds = bf_globals[contentId]?.fields || {};
440 534 const fldKeys = Object.keys(flds).reverse();
441 535 fldKeys.forEach((fldKey) => {
442 536 const fldData = flds[fldKey];
443 537 const fldType = fldData.typ;
444 - if(fldType === \'paypal\') {
445 - initPaypalFld(contentId, fldKey, fldData, fldType);
446 - } else if(fldType === \'razorpay\') {
447 - initRazorpayFld(contentId, fldKey, fldType);
448 - } else if(fldType === \'recaptcha\') {
449 - initRecaptchaFld(contentId, fldKey, fldType);
450 - } else if(fldType === \'turnstile\') {
451 - initTurnstileFld(contentId, fldKey);
452 - } else if(fldType === \'hcaptcha\') {
453 - initHCaptchaFld(contentId, fldKey, fldType);
454 - } else if(fldType === \'stripe\' || fldType === \'mollie\') {
455 - initStripeFld(contentId, fldKey, fldType);
538 + if(fldType === 'paypal') {
539 + $paypalInitJs;
540 + } else if(fldType === 'razorpay') {
541 + $razorpayInitJs;
542 + } else if(fldType === 'recaptcha') {
543 + $recaptchaInitJs;
544 + } else if(fldType === 'turnstile') {
545 + $turnstileInitJs;
546 + } else if(fldType === 'hcaptcha') {
547 + $hCaptchaInitJs;
548 + } else if(fldType === 'stripe') {
549 + $stripeInitJs;
456 550 } else if (customFldConfigPaths[fldType]) {
457 551 contentData.inits[fldKey] = getFldInstance(contentId, fldKey, fldType);
458 552 }
459 553 });
460 - if(contentData.gRecaptchaVersion === \'v3\' && contentData.gRecaptchaSiteKey){
461 - initRecaptchaV3Fld(contentId, contentData);
554 + if(contentData.gRecaptchaVersion === 'v3' && contentData.gRecaptchaSiteKey){
555 + $recaptchaV3InitJs;
462 556 }
463 557 });
464 558 };
465 - function getFldInstance(contentId, fldKey, fldTyp, nestedSelector = \'\') {
466 - const fldClass = this[\'bit_\'+fldTyp.replace(/-/g, \'_\')+\'_field\'];
467 - const selector = \'#form-\'+contentId+\' \'+nestedSelector+fldContainers[fldTyp].replace("__$fk__", fldKey);
559 + function getFldInstance(contentId, fldKey, fldTyp, nestedSelector = '') {
560 + const fldClass = this['bit_'+fldTyp.replace(/-/g, '_')+'_field'];
561 + const selector = '#form-'+contentId+' '+nestedSelector+fldContainers[fldTyp].replace("__\$fk__", fldKey);
468 562 if(!fldClass || !bfSelect(selector)) return;
469 563 return new fldClass(selector, getFldConf(contentId, fldKey, fldTyp));
470 564 };
471 565 function getFldConf(contentId, fieldKey, fldTyp) {
@@ -486,13 +580,13 @@
486 580 } else {
487 581 value = getDataFromNestedPath(fldData, fldPath.path);
488 582 }
489 583 }
490 - if (!value && "val" in fldPath) {
584 + if (!value && fldPath.val) {
491 585 value = fldPath.val;
492 - if(typeof value === \'string\') {
586 + if(typeof value === 'string') {
493 587 Object.entries(varData).forEach(([key, val]) => {
494 - value = value.replace("__$"+key+"__", val);
588 + value = value.replace("__\$"+key+"__", val);
495 589 });
496 590 }
497 591 }
498 592 fldConf = setDataToNestedPath(fldConf, confPath, value);
@@ -518,9 +612,10 @@
518 612 current = current[k];
519 613 });
520 614 current[lastKey] = value;
521 615 return current;
522 - }';
616 + }
617 +FIELDCONFIGJS;
523 618
524 619 return $script;
525 620 }
526 621
@@ -558,29 +653,12 @@
558 653
559 654 private function jsHiddenFieldScript()
560 655 {
561 656 $appConfig = get_option('bitform_app_config');
562 - $cacheTokenEnabled = true;
563 - if (is_object($appConfig) && property_exists($appConfig, 'cache_plugin')) {
564 - $cacheTokenEnabled = (bool) $appConfig->cache_plugin;
565 - } elseif (is_array($appConfig) && array_key_exists('cache_plugin', $appConfig)) {
566 - $cacheTokenEnabled = (bool) $appConfig['cache_plugin'];
567 - }
568 - if ($cacheTokenEnabled) {
657 + if (Helpers::property_exists_nested($appConfig, 'cache_plugin', true)) {
569 658 $fileArr = ScriptFilePriorityManager::frontendScriptFile()['hidden-token-field'];
570 659 $this->addScriptInLoadedScriptsList($fileArr);
571 660 return;
572 - }
573 - }
574 -
575 - private function jsRecaptchaV3Scripts()
576 - {
577 - foreach ($this->_formContents as $content) {
578 - if (isset($content->additional->enabled->recaptchav3) && $content->additional->enabled->recaptchav3) {
579 - $this->addScriptInLoadedScriptsList(['priority' => 302, 'filename' => 'scriptLoader.min.js']);
580 - $this->addScriptInLoadedScriptsList(['priority' => 303, 'filename' => 'initRecaptchaV3Fld.min.js']);
581 - return;
582 - }
583 661 }
584 662 }
585 663
586 664 public function dd($data, $exit = false)