PluginProbe
Bit Form – Contact Form, Payment Forms, Multi Step Forms, Calculator & Custom Form Builder / 2.21.13
Bit Form – Contact Form, Payment Forms, Multi Step Forms, Calculator & Custom Form Builder v2.21.13
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
bit-form / includes / Frontend / Form / FrontendFormHandler.php

FrontendFormHandler.php in Bit Form – Contact Form, Payment Forms, Multi Step Forms, Calculator & Custom Form Builder 2.21.13, at includes/Frontend/Form/FrontendFormHandler.php

795 lines 31.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace BitCode\BitForm\Frontend\Form;
4
5 if (!defined('ABSPATH')) {
6 exit;
7 }
8
9 use BitCode\BitForm\Admin\Form\AdminFormHandler;
10 use BitCode\BitForm\Admin\Form\FrontEndScriptGenerator;
11 use BitCode\BitForm\Admin\Form\Helpers;
12 use BitCode\BitForm\Core\Database\FormEntryMetaModel;
13 use BitCode\BitForm\Core\Database\FormModel;
14 use BitCode\BitForm\Core\Form\FormManager;
15 use BitCode\BitForm\Core\Integration\IntegrationHandler;
16 use BitCode\BitForm\Core\Util\FieldValueHandler;
17 use BitCode\BitForm\Core\Util\FileDownloadProvider;
18 use BitCode\BitForm\Core\Util\FrontendHelpers;
19 use BitCode\BitForm\Core\Util\SmartTags;
20 use BitCode\BitForm\Core\Util\Utilities;
21 use BitCode\BitForm\Core\WorkFlow\WorkFlow;
22 use BitCode\BitFormPro\Admin\FormSettings\FormAbandonment;
23
24 final class FrontendFormHandler
25 {
26 public function __construct()
27 {
28 // before markup load - formids [], posts [1,2]
29 add_action('wp_enqueue_scripts', [$this, 'loadAssets']);
30 // markup loads - formids []
31 add_shortcode('bitform', [$this, 'handleFrontendRenderRequest']);
32 // after markup load - formids [1,35,3]
33 add_action('wp_footer', [$this, 'generateJS']);
34 }
35
36 private function validPassowordResetToken($token, $userID, $formId)
37 {
38 $existResetInteg = (new IntegrationHandler($formId))->getAllIntegration('wp_user_auth', 'wp_auth', 1);
39 if (!is_wp_error($existResetInteg) && count($existResetInteg) > 0) {
40 if ('reset' === $existResetInteg[0]->integration_name) {
41 $user = get_userdata($userID);
42 if ($user) {
43 $validKey = check_password_reset_key($token, $user->user_login);
44 if (is_wp_error($validKey)) {
45 echo "<div id='bf-resp' style='display:grid;justify-content:center;color:#860000;'>This password reset token is invalid.</div>";
46 exit();
47 }
48 } else {
49 echo "<div id='bf-resp' style='display:grid;justify-content:center;color:#860000;'>Invalid User!!</div>";
50 exit();
51 }
52 }
53 }
54 }
55
56 private function getJSFileSrc($postId)
57 {
58 $formUpdateVersion = get_option('bit-form_form_update_version');
59 $formScriptSrc = BITFORMS_UPLOAD_BASE_URL . "/form-scripts/$postId/bitform-js-$postId.js?bfv=$formUpdateVersion";
60
61 return $formScriptSrc;
62 }
63
64 public function generateJs($formID = null, $entryID = null, $formType = null)
65 {
66 // return true;
67 $isFormPreview = get_transient('bitform_form_preview');
68 if ($isFormPreview && !$formID) {
69 delete_transient('bitform_form_preview');
70 return;
71 }
72 $frontendScriptGenObj = new FrontEndScriptGenerator();
73 $isPageBuilder = FrontendHelpers::checkIsPageBuilder($_SERVER);
74 $bfFrontendFormIds = FrontendHelpers::$bfFrontendFormIds;
75 if ($isPageBuilder || empty($bfFrontendFormIds)) {
76 return;
77 }
78 // for unique fields ids in the same form (e.g. multiple forms in the same page)
79 $allFields = [];
80 $formContents = [];
81 $contentIds = [];
82 $formIDs = [];
83 $previewMode = 'classic';
84 $postId = '';
85
86 $formUpdateVersion = get_option('bit-form_form_update_version');
87 if ($formID) {
88 $formIDs[] = $formID;
89 $FrontendFormManager = FrontendFormManager::getInstance($formID, 1);
90 $formInfo = $FrontendFormManager->getFormInfo();
91 $FormIdentifier = esc_js($FrontendFormManager->getFormIdentifier());
92 $formContent = $FrontendFormManager->getFormContentWithValue($this->getValuesFromQueryParams());
93 $formContent->formId = $formID;
94 $formContents[] = $formContent;
95 $workFlowRunType = $entryID ? 'edit' : 'create';
96 $fields = $formContent->fields;
97 if ($entryID) {
98 $fields = $this->setFieldsValue($fields, $formID, $entryID);
99 }
100 $fields = $this->triggerWorkflowOnLoad($formID, 1, $fields, $workFlowRunType);
101 array_push($contentIds, $FormIdentifier);
102
103 foreach ($fields as $fk => $field) {
104 $allFields[$field->typ][] = ['fk' => $fk, 'field' => $field, 'formID' => $formID, 'contentId' => $FormIdentifier];
105 }
106 //Generate JS file for conversational form
107 if (!empty($formInfo->conversationalSettings->enable) && $formInfo->conversationalSettings->enable) {
108 $frontendScriptGenObj->generateJsFile([$formContent], $allFields, [$FormIdentifier], $formID, [$formID], 'conversational');
109 }
110 $previewMode = 'preview';
111 $postId = $formID;
112 } else {
113 global $post;
114 if (!is_object($post) && !isset($post->ID)) {
115 return;
116 }
117 $bfFrontendFormIds = FrontendHelpers::$bfFrontendFormIds;
118 $bfUniqFormIds = FrontendHelpers::getAllUniqFormIdsInPage();
119 $formIDs = $bfUniqFormIds;
120 $regenerateScriptFlag = $this->regenerateScriptChecker($bfUniqFormIds);
121
122 $postId = $post->ID;
123 if (!$regenerateScriptFlag) {
124 $regenerateScriptFlag = $this->deleteUnusedFormPageIds($postId, $bfUniqFormIds);
125 }
126 $isJsGenerating = get_option('bitforms_frontend_js_generating');
127 if (!$regenerateScriptFlag && !$isJsGenerating && !empty($formIDs)) {
128 wp_enqueue_script('bit-form-all-script-test', $this->getJSFileSrc($postId), [], $formUpdateVersion, true);
129 return;
130 }
131 foreach ($bfFrontendFormIds as $index => $formId) {
132 $shortCodeCounter = $index + 1;
133 $FrontendFormManager = FrontendFormManager::getInstance($formId, $shortCodeCounter);
134 $formInfo = $FrontendFormManager->getFormInfo();
135 $FormIdentifier = esc_js($FrontendFormManager->getFormIdentifier());
136 $formContent = $FrontendFormManager->getFormContentWithValue($this->getValuesFromQueryParams());
137 $formContent->formId = $formId;
138 $formContents[] = $formContent;
139 $fields = $this->triggerWorkflowOnLoad($formId, $shortCodeCounter, $formContent->fields);
140 $contentIds[] = $FormIdentifier;
141 $formFields = []; // indivisual form fields array for conversational view
142 foreach ($fields as $fk => $field) {
143 $fieldArr = ['fk' => $fk, 'field' => $field, 'formID' => $formId, 'contentId' => $FormIdentifier];
144 $allFields[$field->typ][] = $fieldArr;
145 $formFields[$field->typ][] = $fieldArr;
146 }
147 //Generate JS file for conversational form
148 if (!empty($formInfo->conversationalSettings->enable) && $formInfo->conversationalSettings->enable) {
149 $frontendScriptGenObj->generateJsFile([$formContent], $formFields, [$FormIdentifier], $formId, [$formId], 'conversational');
150 }
151 }
152 }
153 if (empty($formIDs)) {
154 return;
155 }
156
157 $frontendScriptGenObj->generateJsFile($formContents, $allFields, $contentIds, $postId, $formIDs, $previewMode);
158 wp_enqueue_script('bit-form-all-script-test', $this->getJSFileSrc($postId), [], $formUpdateVersion, true);
159 }
160
161 private function deleteUnusedFormPageIds($postId, $formIDs)
162 {
163 global $post;
164 if (!is_object($post) && !isset($post->ID)) {
165 return;
166 }
167 $postId = $post->ID;
168 $formModel = new FormModel();
169 $forms = $formModel->get(
170 ['id', 'generated_script_page_ids']
171 );
172 $regenerateScriptFlag = false;
173 foreach ($forms as $form) {
174 $formId = $form->id;
175 $generatedScriptPageIdsDecoded = json_decode($form->generated_script_page_ids, true);
176 $generatedScriptPageIds = is_array($generatedScriptPageIdsDecoded) ? array_keys($generatedScriptPageIdsDecoded) : [];
177 if (!empty($generatedScriptPageIds) && !in_array($formId, $formIDs) && in_array($postId, $generatedScriptPageIds)) {
178 unset($generatedScriptPageIdsDecoded[$postId]);
179 if (empty($generatedScriptPageIdsDecoded)) {
180 $generatedScriptPageIdsDecoded = new \stdClass();
181 }
182 $regenerateScriptFlag = true;
183 $formModel->update(['generated_script_page_ids' => wp_json_encode($generatedScriptPageIdsDecoded)], ['id' => $formId]);
184 }
185 }
186 if ($regenerateScriptFlag) {
187 $formUpdateVersion = get_option('bit-form_form_update_version');
188 if (!$formUpdateVersion) {
189 $formUpdateVersion = 1;
190 } else {
191 $formUpdateVersion = (int) $formUpdateVersion + 1;
192 }
193 update_option('bit-form_form_update_version', $formUpdateVersion);
194 }
195 return $regenerateScriptFlag;
196 }
197
198 private function regenerateScriptChecker($formsIds)
199 {
200 global $post;
201 if (!is_a($post, 'WP_Post') && !isset($post->ID)) {
202 return;
203 }
204 $postId = $post->ID;
205 $regenerateScriptFlag = false;
206 $formModel = new FormModel();
207 foreach ($formsIds as $formId) {
208 $formInstance = FormManager::getInstance($formId);
209 if (!$formInstance->isExist()) {
210 continue;
211 }
212 $generatedPages = $formInstance->getFormData('generated_script_page_ids');
213 if (empty($generatedPages)) {
214 $regenerateScriptFlag = true;
215 } elseif (is_object($generatedPages) && (!isset($generatedPages->{$postId}) || (isset($generatedPages->{$postId}) && false === $generatedPages->{$postId}))) {
216 $regenerateScriptFlag = true;
217 }
218 if (!$regenerateScriptFlag) {
219 continue;
220 }
221 if (!is_object($generatedPages)) {
222 $generatedPages = (object) [];
223 }
224 $generatedPages->{$postId} = true;
225 $formModel->update(
226 [
227 'generated_script_page_ids' => \wp_json_encode($generatedPages)
228 ],
229 [
230 'id' => $formId,
231 ]
232 );
233 }
234 return $regenerateScriptFlag;
235 }
236
237 private function addInlineScript($code, $handle = '', $position = 'after')
238 {
239 $scriptHandle = !empty($handle) ? $handle : 'bf-inline-script';
240 if (!wp_script_is($scriptHandle)) {
241 wp_register_script($scriptHandle, '', [], BITFORMS_VERSION, true);
242 wp_enqueue_script($scriptHandle);
243 }
244 wp_add_inline_script($scriptHandle, $code, $position);
245 }
246
247 private function addInlineStyle($code, $handle = '')
248 {
249 $styleHandle = !empty($handle) ? $handle : 'bf-inline-style';
250 if (!wp_style_is($styleHandle)) {
251 wp_register_style($styleHandle, '', [], BITFORMS_VERSION);
252 wp_enqueue_style($styleHandle);
253 }
254 wp_add_inline_style($styleHandle, $code);
255 }
256
257 private function triggerWorkflowOnLoad($formID, $shortCodeCounter, $fields, $workFlowRunType = 'create')
258 {
259 $FrontendFormManager = new FrontendFormManager($formID, $shortCodeCounter);
260 $previousValue = $this->getValuesFromQueryParams();
261 $formContent = $FrontendFormManager->getFormContentWithValue($previousValue);
262 if (!empty($formContent->workFlowExist)) {
263 $workFlowRunHelper = new WorkFlow($formID);
264 if (!empty($formContent->workFlowExist->onload)) {
265 $workFlowreturnedOnLoad = $workFlowRunHelper->executeOnLoad(
266 $workFlowRunType,
267 $fields
268 );
269
270 if (!empty($workFlowreturnedOnLoad['fields'])) {
271 return $workFlowreturnedOnLoad['fields'];
272 }
273 }
274 }
275
276 return $fields;
277 }
278
279 private function executeOnUserInput($formID, $shortCodeCounter, $fields)
280 {
281 $FrontendFormManager = FrontendFormManager::getInstance($formID, $shortCodeCounter);
282 $previousValue = $this->getValuesFromQueryParams();
283 $formContent = $FrontendFormManager->getFormContentWithValue($previousValue);
284 $customCodesExist = strpos(FrontEndScriptGenerator::getCustomCodes($formID)['JavaScript'], 'bfVars');
285 if ($customCodesExist || (!empty($formContent->workFlowExist) && !empty($formContent->workFlowExist->oninput))) {
286 $workFlowRunHelper = new WorkFlow($formID);
287 return $workFlowRunHelper->executeOnUserInput('create', $fields);
288 }
289 }
290
291 private function getValuesFromQueryParams()
292 {
293 $queryParamsValue = [];
294 if (isset($_SERVER['QUERY_STRING']) && !empty($_SERVER['QUERY_STRING'])) {
295 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- QUERY_STRING used with explode/urldecode; sanitize_text_field would break URL encoding
296 $reqField = wp_unslash($_SERVER['QUERY_STRING']);
297 foreach (explode('&', $reqField) as $keyValue) {
298 // $pattern = '/([a-zA-Z0-9])([a-zA-Z])\=+/';
299 $pattern = '/([^.]+)=(.*?)([^.]+)/';
300 $matches = preg_match($pattern, $keyValue, $matchFormat);
301 if ($matches) {
302 list($field, $value) = explode('=', $keyValue, 2);
303
304 if (!trim($value)) {
305 continue;
306 }
307
308 $queryParamsValue[$field][] = sanitize_text_field(urldecode($value));
309 }
310 }
311 }
312
313 return $queryParamsValue;
314 }
315
316 public function handleFrontendRenderRequest($atts)
317 {
318 $formType = isset($atts['type']) ? $atts['type'] : 'classic';
319 $formPreview = isset($atts['form_preview']) ? $atts['form_preview'] : false;
320 if (isset($atts['form_id'])) {
321 $formID = intval($atts['form_id']);
322 }
323 if (isset($atts['entry_id'])) {
324 $entryId = intval($atts['entry_id']);
325 } elseif (isset($_GET['bf_entry_id']) && !is_array($_GET['bf_entry_id'])) {
326 $entryId = intval(sanitize_text_field(wp_unslash($_GET['bf_entry_id'])));
327 } else {
328 $entryId = false;
329 }
330 if (isset($atts['id'])) {
331 $atts = shortcode_atts(['id' => 0], $atts);
332 $formID = intval($atts['id']);
333 }
334
335 if (!$formID) {
336 return __('Form ID cannot be empty', 'bit-form');
337 }
338
339 if (!$this->isExist($formID)) {
340 /* translators: %s: form ID */
341 return sprintf(__('#%s no. Form doesn\'t exists', 'bit-form'), $formID);
342 }
343
344 // check for abandoned form entry id
345 $isAbandoned = false;
346 if (empty($entryId) && Utilities::isPro() && class_exists('\BitCode\BitFormPro\Admin\FormSettings\FormAbandonment')) {
347 $FormAbandonment = new FormAbandonment($formID);
348 $isAbandoned = $FormAbandonment->checkAbandonedFormEntryId();
349 }
350
351 FrontendHelpers::setBfFrontendFormIds($formID);
352 $bfFrontendFormIds = FrontendHelpers::$bfFrontendFormIds;
353 $shortCodeCounter = count($bfFrontendFormIds);
354 $FrontendFormManager = FrontendFormManager::getInstance($formID, $shortCodeCounter);
355
356 if (!$FrontendFormManager->checkStatus()) {
357 /* translators: %s: form ID */
358 return sprintf(__('#%s no. Form is not active', 'bit-form'), $formID);
359 }
360 ob_start();
361 $this->loadAssets($formID, $formType);
362
363 $font = $FrontendFormManager->getFont();
364
365 if ($font && !$formPreview) {
366 wp_enqueue_style('bf-google-font', $font, '1.0.0', true);
367 }
368
369 if (!empty($_GET['token']) && !empty($_GET['id'])) {
370 $this->validPassowordResetToken(sanitize_text_field(wp_unslash($_GET['token'])), sanitize_text_field(wp_unslash($_GET['id'])), $formID);
371 }
372
373 $previousValue = $this->getValuesFromQueryParams();
374 $errorMessages = []; // delete
375 $FormIdentifier = esc_js($FrontendFormManager->getFormIdentifier());
376 $nonce = $FrontendFormManager->getFormToken();
377 $file = count($FrontendFormManager->getUploadFields()) > 0 ? $FrontendFormManager->getUploadFields() : false;
378
379 $FrontendFormManager->setViewCount();
380
381 $formContent = $FrontendFormManager->getFormContentWithValue($previousValue);
382 $fields = $formContent->fields;
383 $layout = $formContent->layout;
384 $nestedLayout = isset($formContent->nestedLayout) ? $formContent->nestedLayout : (object) [];
385 $buttons = !empty($formContent->buttons) ? $formContent->buttons : '';
386 $additional = $formContent->additional;
387
388 // $workFlowRunType = $entryId ? 'edit' : 'create';
389 if ($entryId && (FrontendHelpers::is_current_user_can_access($formID, 'entryEditAccess'))) {
390 $workFlowRunType = 'edit';
391 $adminFormHandler = new AdminFormHandler();
392 $getEntry = $adminFormHandler->getSingleEntry($formID, $entryId);
393 if (FrontendHelpers::is_current_user_can_access($formID, 'entryEditAccess', '', $getEntry->__user_id)) {
394 $fields = $this->setFieldsValue($fields, $formID, $entryId);
395 } elseif (!$isAbandoned) {
396 $entryId = false;
397 $workFlowRunType = 'create';
398 }
399 } else {
400 $entryId = false;
401 $workFlowRunType = 'create';
402 }
403
404 // if ($entryId) {
405 // $fields = $this->setFieldsValue($fields, $formID, $entryId);
406 // }
407
408 $fields = apply_filters('bitform_filter_before_workflow_onload_fields', $fields, $formID);
409 $fields = $this->triggerWorkflowOnLoad($formID, $shortCodeCounter, $fields, $workFlowRunType);
410 $fields = apply_filters('bitform_filter_after_workflow_onload_fields', $fields, $formID);
411 do_action('bitform_onload_fields', $fields, $formID);
412 $workFlowreturnedOnUserInput = $this->executeOnUserInput($formID, $shortCodeCounter, $fields);
413
414 // test for form before remove
415 $noLabelFieldTypes = ['decision-box', 'gdpr', 'html', 'shortcode', 'button', 'paypal', 'razorpay', 'recaptcha', 'turnstile', 'hcaptcha', 'stripe', 'spacer'];
416 foreach ($fields as $fldKey => $field) {
417 if (!in_array($field->typ, $noLabelFieldTypes) && isset($field->lbl)) {
418 $lblReplaceToBackslash = str_replace('$_bf_$', '\\', $field->lbl);
419 $fields->{$fldKey}->lbl = FieldValueHandler::replaceSmartTagWithValue($lblReplaceToBackslash);
420 }
421 }
422 $fieldsKey = $FrontendFormManager->getFieldsKey();
423
424 $captchaV3Settings = $FrontendFormManager->getCaptchaV3Settings();
425 if ($FrontendFormManager->getCaptchaSettings() || $captchaV3Settings || $FrontendFormManager->getTurnstileSettings() || $FrontendFormManager->isFieldTypeExist('hcaptcha')) {
426 $integrationHandler = new IntegrationHandler(0);
427 $allFormIntegrations = $integrationHandler->getAllIntegration('app');
428 if (!is_wp_error($allFormIntegrations)) {
429 foreach ($allFormIntegrations as $integration) {
430 if (
431 $FrontendFormManager->getCaptchaSettings()
432 && !is_null($integration->integration_type)
433 && 'gReCaptcha' === $integration->integration_type
434 ) {
435 $integrationDetails = json_decode($integration->integration_details);
436 $integrationDetails->id = $integration->id;
437 $reCAPTCHA = $integrationDetails;
438 $reCAPTCHAVersion = 'v2';
439 }
440
441 if (
442 $FrontendFormManager->getTurnstileSettings()
443 && !is_null($integration->integration_type)
444 && 'turnstileCaptcha' === $integration->integration_type
445 ) {
446 $integrationDetails = json_decode($integration->integration_details);
447 $turnstileSiteKey = $integrationDetails->siteKey;
448 }
449
450 if (
451 $FrontendFormManager->isFieldTypeExist('hcaptcha')
452 && !is_null($integration->integration_type)
453 && 'hcaptcha' === $integration->integration_type
454 ) {
455 $integrationDetails = json_decode($integration->integration_details);
456 $hCaptchaSiteKey = $integrationDetails->siteKey;
457 }
458
459 if ($captchaV3Settings) {
460 if (!is_null($integration->integration_type) && 'gReCaptchaV3' === $integration->integration_type) {
461 $integrationDetails = json_decode($integration->integration_details);
462 $integrationDetails->id = $integration->id;
463 $reCAPTCHA = $integrationDetails;
464 $reCAPTCHAVersion = 'v3';
465 }
466 }
467 }
468 }
469 }
470
471 if ($captchaV3Settings && !empty($reCAPTCHA->siteKey)) {
472 // DANGER: no matter what, DONT CHANGE THE SCRIPT ID OF THIS SCRIPT
473 $scriptId = BITFORMS_PREFIX . 'recaptcha';
474 // phpcs:ignore WordPress.WP.EnqueuedResourceParameters.MissingVersion, WordPress.WP.EnqueuedResourceParameters.NotInFooter -- External Google reCAPTCHA script; no version control available, must load in head.
475 wp_enqueue_script($scriptId, "https://www.google.com/recaptcha/api.js?render={$reCAPTCHA->siteKey}");
476 }
477
478 $configs = [
479 'bf_separator' => BITFORMS_BF_SEPARATOR,
480 ];
481
482 // check if fields has paypal or razorpay
483 $paymentFields = ['paypal', 'razorpay', 'stripe'];
484 $paymentFieldData = [];
485 foreach ($fields as $key => $field) {
486 if (in_array($field->typ, $paymentFields)) {
487 $paymentFieldData[$key] = $field;
488 }
489 }
490
491 if (!empty($paymentFieldData)) {
492 $integrationHandler = new IntegrationHandler(0);
493 foreach ($paymentFieldData as $fldKey => $fldData) {
494 $paymentIntegration = $integrationHandler->getAIntegration($fldData->payIntegID);
495 if (is_wp_error($paymentIntegration)) {
496 continue;
497 }
498 if ('paypal' === $fldData->typ) {
499 $integrationDetails = json_decode($paymentIntegration[0]->integration_details);
500 $clientID = $integrationDetails->clientID;
501 $fields->{$fldKey}->clientId = $clientID;
502 } elseif ('razorpay' === $fldData->typ) {
503 $integrationDetails = json_decode($paymentIntegration[0]->integration_details);
504 $clientID = $integrationDetails->apiKey;
505 $fields->{$fldKey}->clientId = $clientID;
506 } elseif ('stripe' === $fldData->typ) {
507 $integrationDetails = json_decode($paymentIntegration[0]->integration_details);
508 $publishableKey = $integrationDetails->publishableKey;
509 $fields->{$fldKey}->publishableKey = $publishableKey;
510 }
511 }
512 }
513
514 $bitFormFrontArr = [
515 'ajaxURL' => admin_url('admin-ajax.php'),
516 'nonce' => $nonce,
517 'version' => BITFORMS_VERSION,
518 'layout' => $layout,
519 'nestedLayout' => $nestedLayout,
520 'fields' => $fields,
521 'buttons' => $buttons,
522 'fieldsKey' => $fieldsKey,
523 'file' => $file,
524 'configs' => $configs,
525 'formId' => $formID,
526 'appID' => "bitforms_{$formID}",
527 'GCLID' => $FrontendFormManager->isGCLIDEnabled(),
528 'assetUrl' => BITFORMS_ASSET_URI,
529 'onfieldCondition' => !empty($workFlowreturnedOnUserInput['onfield_input_conditions']) ? $workFlowreturnedOnUserInput['onfield_input_conditions'] : false,
530 'smartTags' => SmartTags::smartTags(SmartTags::getPostUserData()),
531 'paymentCallbackUrl' => get_rest_url() . 'bitform/v1/payments/razorpay',
532 'gRecaptchaSiteKey' => !empty($reCAPTCHA->siteKey) ? $reCAPTCHA->siteKey : null,
533 'gRecaptchaVersion' => !empty($reCAPTCHAVersion) ? $reCAPTCHAVersion : null,
534 'turnstileSiteKey' => !empty($turnstileSiteKey) ? $turnstileSiteKey : null,
535 'hCaptchaSiteKey' => !empty($hCaptchaSiteKey) ? $hCaptchaSiteKey : null,
536 ];
537
538 if ($entryId) {
539 $bitFormFrontArr['entryId'] = $entryId;
540 }
541
542 if (isset($additional->enabled->validateFocusLost)) {
543 $bitFormFrontArr['validateFocusLost'] = true;
544 }
545
546 if (!empty($isAbandoned)) {
547 $bitFormFrontArr['oldValues'] = $this->getFieldsValue($formID, $isAbandoned);
548 if (empty($entryId)) {
549 $bitFormFrontArr['entryId'] = $isAbandoned;
550 }
551 }
552
553 $formInfo = $FrontendFormManager->getFormInfo();
554 $bitFormFrontArr['formName'] = $formInfo->formName ?? '';
555 if (is_array($layout) && count($layout) > 1) {
556 $multiStepSettings = isset($formInfo->multiStepSettings) ? $formInfo->multiStepSettings : null;
557 $newTempSettings = (object) [
558 'validateOnStepChange' => isset($multiStepSettings->validateOnStepChange) ? $multiStepSettings->validateOnStepChange : false,
559 'maintainStepHistory' => isset($multiStepSettings->maintainStepHistory) ? $multiStepSettings->maintainStepHistory : false,
560 'saveProgress' => isset($multiStepSettings->saveProgress) ? $multiStepSettings->saveProgress : false,
561 'showPercentage' => isset($multiStepSettings->progressSettings->showPercentage) ? $multiStepSettings->progressSettings->showPercentage : false,
562 ];
563 $bitFormFrontArr['formInfo'] = (object) [
564 'multiStepSettings' => $newTempSettings
565 ];
566 }
567
568 if (Helpers::property_exists_nested($formInfo, 'conversationalSettings->enable', true)) {
569 if (!isset($bitFormFrontArr['formInfo'])) {
570 $bitFormFrontArr['formInfo'] = new \stdClass();
571 }
572 $bitFormFrontArr['formInfo']->conversationalSettings = $formInfo->conversationalSettings;
573 }
574
575 $formAbandonmentSettings = $FrontendFormManager->getFormAbandonmentSettings();
576 if (Helpers::property_exists_nested($formAbandonmentSettings, 'active', true)) {
577 $bitFormFrontArr['formSettings'] = (object)[
578 'formAbandonment' => $formAbandonmentSettings
579 ];
580 }
581
582 $bitFormsFront = apply_filters(
583 'bitforms_localized_script',
584 $bitFormFrontArr
585 );
586
587 $layout = wp_json_encode($layout);
588 $buttons = wp_json_encode($buttons);
589 $frontArr = wp_json_encode($bitFormFrontArr);
590
591 $bfGlobals = sprintf('
592 if(!window.bf_globals) {
593 window.bf_globals = {}
594 } if(!window.bf_globals.%1$s) {
595 window.bf_globals.%1$s = {}
596 }
597 if(document.getElementById("%1$s")) {
598 window.bf_globals.%1$s = {
599 ...window.bf_globals.%1$s,
600 ...%2$s
601 };
602 }', $FormIdentifier, $frontArr);
603
604 if ('conversational' === $formType
605 && isset($formContent->formInfo->conversationalSettings->enable)
606 && $formContent->formInfo->conversationalSettings->enable) {
607 $html = $FrontendFormManager->conversationalFormView($fields, $file, $errorMessages);
608 } else {
609 $html = $FrontendFormManager->formView($fields, $file, $errorMessages);
610 }
611
612 // if form preview then return html otherwise echo with output buffer
613 if ($formPreview) {
614 ob_clean();
615 $formViewObject = new \stdClass();
616 $formViewObject->html = $html;
617 $formViewObject->font = $font;
618 $formViewObject->bfGlobals = $bfGlobals;
619 return $formViewObject;
620 }
621
622 ?>
623 <script id="bit-form-bf-globals-<?php echo esc_attr($FormIdentifier); ?>">
624 <?php
625 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- $bfGlobals contains wp_json_encode() output intended for JS context and is safe to output.
626 echo $bfGlobals; ?>
627 </script>
628 <?php
629 $inlineScript = ob_get_clean();
630 return $html . $inlineScript;
631 }
632
633 private function isExist($formID)
634 {
635 $formModel = new FormModel();
636 $form = $formModel->get(
637 [
638 'id'
639 ],
640 [
641 'id' => $formID,
642 ]
643 );
644 if (!is_wp_error($form)) {
645 return true;
646 }
647 return false;
648 }
649
650 private function getFieldsValue($formID, $entryID)
651 {
652 $FrontendFormManager = FrontendFormManager::getInstance($formID, 1);
653 $formEntryModel = new FormEntryMetaModel();
654 $metaValues = $formEntryModel->get(
655 [
656 'meta_key',
657 'meta_value'
658 ],
659 [
660 'bitforms_form_entry_id' => $entryID,
661 ]
662 );
663 $formFields = $FrontendFormManager->getFields();
664 $fldsData = (object) [];
665 if (!is_wp_error($metaValues)) {
666 foreach ($metaValues as $metaValue) {
667 $metaKey = $metaValue->meta_key;
668 $metaVal = $metaValue->meta_value;
669 // if meta value is array then convert to string
670 if (preg_match('/^\[.*\]$/', $metaVal)) {
671 $metaVal = json_decode($metaVal);
672 //check is it array of objects
673 if (is_array($metaVal) && is_object($metaVal[0])) {
674 $metaVal = $metaValue->meta_value;
675 } else {
676 $metaVal = implode(BITFORMS_BF_SEPARATOR, $metaVal);
677 }
678 }
679 if (!isset($fldsData->{$metaKey})) {
680 $fldsData->{$metaKey} = '';
681 }
682 $fldsData->{$metaKey} = $metaVal;
683 if (isset($formFields[$metaKey]['type']) && in_array($formFields[$metaKey]['type'], ['file-up', 'advanced-file-up'])) {
684 $fldsData->{$metaKey} = $metaValue->meta_value;
685 }
686 }
687 }
688
689 return $fldsData;
690 }
691
692 public function setFieldsValue($fields, $formID, $entryID)
693 {
694 $formEntryModel = new FormEntryMetaModel();
695 $metaValues = $formEntryModel->get(
696 [
697 'meta_key',
698 'meta_value'
699 ],
700 [
701 'bitforms_form_entry_id' => $entryID,
702 ]
703 );
704 if (!is_wp_error($metaValues)) {
705 foreach ($metaValues as $metaValue) {
706 $metaKey = $metaValue->meta_key;
707 $metaVal = $metaValue->meta_value;
708 // if meta value is array then convert to string
709 if (preg_match('/^\[.*\]$/', $metaVal)) {
710 $metaVal = json_decode($metaVal);
711 //check is it array of objects
712 if (is_array($metaVal) && is_object($metaVal[0])) {
713 $metaVal = $metaValue->meta_value;
714 } else {
715 $metaVal = implode(BITFORMS_BF_SEPARATOR, $metaVal);
716 }
717 }
718 if (property_exists($fields, $metaKey)) {
719 $fields->{$metaKey}->val = $metaVal;
720 if ('file-up' === $fields->{$metaKey}->typ || 'advanced-file-up' === $fields->{$metaKey}->typ) {
721 $fields->{$metaKey}->val = $metaValue->meta_value;
722 $fields->{$metaKey}->config->oldFiles = $metaValue->meta_value;
723 $urlQuery = wp_parse_url(FileDownloadProvider::getBaseDownloadURL(), PHP_URL_QUERY);
724 $baseDLURL = FileDownloadProvider::getBaseDownloadURL();
725 $baseDLURL = empty($urlQuery) ? $baseDLURL . '?' : $baseDLURL . '&';
726 $fields->{$metaKey}->config->baseDLURL = $baseDLURL . "formID={$formID}&entryID={$entryID}";
727 }
728 }
729 }
730 }
731 return $fields;
732 }
733
734 public function loadAssets($formID = 0, $fromType = 'classic')
735 {
736 $bfUniqFormIds = FrontendHelpers::getAllFormIdsInPage();
737 $isPageBuilder = FrontendHelpers::$isPageBuilder;
738 $bfMultipleFormsExists = $isPageBuilder ? true : count($bfUniqFormIds) > 1;
739
740 if (!empty($formID)) {
741 $formIds = [$formID];
742 } else {
743 $formIds = $bfUniqFormIds;
744 }
745 foreach ($formIds as $formID) {
746 global $bitform_dequeued_styles;
747 if (is_array($bitform_dequeued_styles) && in_array($formID, $bitform_dequeued_styles)) {
748 continue;
749 }
750 if ($bfMultipleFormsExists) {
751 $newFormId = $formID . '-formid';
752 } else {
753 $newFormId = $formID;
754 }
755 $formUpdateVersion = get_option('bit-form_form_update_version');
756 if (!wp_style_is('bitform-style-' . $newFormId) && is_readable(BITFORMS_CONTENT_DIR . '/form-styles/bitform-' . $newFormId . '.css')) {
757 wp_enqueue_style(
758 'bitform-style-' . $newFormId,
759 BITFORMS_UPLOAD_BASE_URL . "/form-styles/bitform-{$newFormId}.css",
760 [],
761 $formUpdateVersion
762 );
763 if ($isPageBuilder) {
764 $formStyle = file_get_contents(BITFORMS_CONTENT_DIR . '/form-styles/bitform-' . $newFormId . '.css');
765 echo '<style id="bitform-style-' . esc_attr((string) $newFormId) . '">' . $formStyle . '</style>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- CSS from admin-controlled file
766 }
767 }
768 if (!wp_style_is('bitform-style-custom-' . $formID) && is_readable(BITFORMS_CONTENT_DIR . '/form-styles/bitform-custom-' . $formID . '.css')) {
769 wp_enqueue_style(
770 'bitform-style-custom-' . $formID,
771 BITFORMS_UPLOAD_BASE_URL . "/form-styles/bitform-custom-{$formID}.css",
772 [],
773 $formUpdateVersion
774 );
775 if ($isPageBuilder) {
776 $formStyle = file_get_contents(BITFORMS_CONTENT_DIR . '/form-styles/bitform-custom-' . $formID . '.css');
777 echo '<style id="bitform-style-custom-' . esc_attr((string) $formID) . '">' . $formStyle . '</style>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- CSS from admin-controlled file
778 }
779 }
780 // load conversational form css
781 if ('conversational' === $fromType) {
782 if (!wp_style_is('bitform-conversational-style-' . $formID) &&
783 is_readable(BITFORMS_CONTENT_DIR . "/form-styles/bitform-conversational-{$formID}.css")) {
784 wp_enqueue_style(
785 'bitform-conversational-style',
786 BITFORMS_UPLOAD_BASE_URL . "/form-styles/bitform-conversational-{$formID}.css",
787 [],
788 $formUpdateVersion
789 );
790 }
791 }
792 }
793 }
794 }
795