getAllIntegration('wp_user_auth', 'wp_auth', 1);
if (!is_wp_error($existResetInteg) && count($existResetInteg) > 0) {
if ('reset' === $existResetInteg[0]->integration_name) {
$user = get_userdata($userID);
if ($user) {
$validKey = check_password_reset_key($token, $user->user_login);
if (is_wp_error($validKey)) {
echo "
This password reset token is invalid.
";
exit();
}
} else {
echo "Invalid User!!
";
exit();
}
}
}
}
private function getJSFileSrc($postId)
{
$formUpdateVersion = get_option('bitform_form_update_version');
$formScriptSrc = BITFORMS_UPLOAD_BASE_URL . "/form-scripts/$postId/bitform-js-$postId.js?bfv=$formUpdateVersion";
return $formScriptSrc;
}
public function generateJs($formID = null, $entryID = null, $formType = null)
{
// return true;
$isFormPreview = get_transient('bitform_form_preview');
if ($isFormPreview && !$formID) {
delete_transient('bitform_form_preview');
return;
}
$frontendScriptGenObj = new FrontEndScriptGenerator();
$isPageBuilder = FrontendHelpers::checkIsPageBuilder($_SERVER);
$bfFrontendFormIds = FrontendHelpers::$bfFrontendFormIds;
if ($isPageBuilder || empty($bfFrontendFormIds)) {
return;
}
// for unique fields ids in the same form (e.g. multiple forms in the same page)
$allFields = [];
$formContents = [];
$contentIds = [];
$formIDs = [];
$previewMode = 'classic';
$postId = '';
$formUpdateVersion = get_option('bitform_form_update_version');
if ($formID) {
$formIDs[] = $formID;
$FrontendFormManager = FrontendFormManager::getInstance($formID, 1);
$formInfo = $FrontendFormManager->getFormInfo();
$FormIdentifier = esc_js($FrontendFormManager->getFormIdentifier());
$formContent = $FrontendFormManager->getFormContentWithValue($this->getValuesFromQueryParams());
$formContent->formId = $formID;
$formContents[] = $formContent;
$workFlowRunType = $entryID ? 'edit' : 'create';
$fields = $formContent->fields;
if ($entryID) {
$fields = $this->setFieldsValue($fields, $formID, $entryID);
}
$fields = $this->triggerWorkflowOnLoad($formID, 1, $fields, $workFlowRunType);
array_push($contentIds, $FormIdentifier);
foreach ($fields as $fk => $field) {
$allFields[$field->typ][] = ['fk' => $fk, 'field' => $field, 'formID' => $formID, 'contentId' => $FormIdentifier];
}
//Generate JS file for conversational form
if (!empty($formInfo->conversationalSettings->enable) && $formInfo->conversationalSettings->enable) {
$frontendScriptGenObj->generateJsFile([$formContent], $allFields, [$FormIdentifier], $formID, [$formID], 'conversational');
}
$previewMode = 'preview';
$postId = $formID;
} else {
global $post;
if (!is_object($post) && !isset($post->ID)) {
return;
}
$bfFrontendFormIds = FrontendHelpers::$bfFrontendFormIds;
$bfUniqFormIds = FrontendHelpers::getAllUniqFormIdsInPage();
$formIDs = $bfUniqFormIds;
$regenerateScriptFlag = $this->regenerateScriptChecker($bfUniqFormIds);
$postId = $post->ID;
if (!$regenerateScriptFlag) {
$regenerateScriptFlag = $this->deleteUnusedFormPageIds($postId, $bfUniqFormIds);
}
$isJsGenerating = get_option('bitforms_frontend_js_generating');
if (!$regenerateScriptFlag && !$isJsGenerating && !empty($formIDs)) {
wp_enqueue_script('bit-form-all-script-test', $this->getJSFileSrc($postId), [], $formUpdateVersion, true);
return;
}
foreach ($bfFrontendFormIds as $index => $formId) {
$shortCodeCounter = $index + 1;
$FrontendFormManager = FrontendFormManager::getInstance($formId, $shortCodeCounter);
$formInfo = $FrontendFormManager->getFormInfo();
$FormIdentifier = esc_js($FrontendFormManager->getFormIdentifier());
$formContent = $FrontendFormManager->getFormContentWithValue($this->getValuesFromQueryParams());
$formContent->formId = $formId;
$formContents[] = $formContent;
$fields = $this->triggerWorkflowOnLoad($formId, $shortCodeCounter, $formContent->fields);
$contentIds[] = $FormIdentifier;
$formFields = []; // indivisual form fields array for conversational view
foreach ($fields as $fk => $field) {
$fieldArr = ['fk' => $fk, 'field' => $field, 'formID' => $formId, 'contentId' => $FormIdentifier];
$allFields[$field->typ][] = $fieldArr;
$formFields[$field->typ][] = $fieldArr;
}
//Generate JS file for conversational form
if (!empty($formInfo->conversationalSettings->enable) && $formInfo->conversationalSettings->enable) {
$frontendScriptGenObj->generateJsFile([$formContent], $formFields, [$FormIdentifier], $formId, [$formId], 'conversational');
}
}
}
if (empty($formIDs)) {
return;
}
$frontendScriptGenObj->generateJsFile($formContents, $allFields, $contentIds, $postId, $formIDs, $previewMode);
if ('preview' === $previewMode) {
return;
}
wp_enqueue_script('bit-form-all-script-test', $this->getJSFileSrc($postId), [], $formUpdateVersion, true);
}
private function deleteUnusedFormPageIds($postId, $formIDs)
{
global $post;
if (!is_object($post) && !isset($post->ID)) {
return;
}
$postId = $post->ID;
$formModel = new FormModel();
$forms = $formModel->get(
['id', 'generated_script_page_ids']
);
$regenerateScriptFlag = false;
foreach ($forms as $form) {
$formId = $form->id;
$generatedScriptPageIdsDecoded = json_decode($form->generated_script_page_ids, true);
$generatedScriptPageIds = is_array($generatedScriptPageIdsDecoded) ? array_keys($generatedScriptPageIdsDecoded) : [];
if (!empty($generatedScriptPageIds) && !in_array($formId, $formIDs) && in_array($postId, $generatedScriptPageIds)) {
unset($generatedScriptPageIdsDecoded[$postId]);
if (empty($generatedScriptPageIdsDecoded)) {
$generatedScriptPageIdsDecoded = new \stdClass();
}
$regenerateScriptFlag = true;
$formModel->update(['generated_script_page_ids' => wp_json_encode($generatedScriptPageIdsDecoded)], ['id' => $formId]);
}
}
if ($regenerateScriptFlag) {
$formUpdateVersion = get_option('bitform_form_update_version');
if (!$formUpdateVersion) {
$formUpdateVersion = 1;
} else {
$formUpdateVersion = (int) $formUpdateVersion + 1;
}
update_option('bitform_form_update_version', $formUpdateVersion);
}
return $regenerateScriptFlag;
}
private function regenerateScriptChecker($formsIds)
{
global $post;
if (!is_a($post, 'WP_Post') && !isset($post->ID)) {
return;
}
$postId = $post->ID;
$regenerateScriptFlag = false;
$formModel = new FormModel();
foreach ($formsIds as $formId) {
$formInstance = FormManager::getInstance($formId);
if (!$formInstance->isExist()) {
continue;
}
$generatedPages = $formInstance->getFormData('generated_script_page_ids');
if (empty($generatedPages)) {
$regenerateScriptFlag = true;
} elseif (is_object($generatedPages) && (!isset($generatedPages->{$postId}) || (isset($generatedPages->{$postId}) && false === $generatedPages->{$postId}))) {
$regenerateScriptFlag = true;
}
if (!$regenerateScriptFlag) {
continue;
}
if (!is_object($generatedPages)) {
$generatedPages = (object) [];
}
$generatedPages->{$postId} = true;
$formModel->update(
[
'generated_script_page_ids' => \wp_json_encode($generatedPages)
],
[
'id' => $formId,
]
);
}
return $regenerateScriptFlag;
}
private function addInlineScript($code, $handle = '', $position = 'after')
{
$scriptHandle = !empty($handle) ? $handle : 'bf-inline-script';
$formUpdateVersion = get_option('bitform_form_update_version');
if (!wp_script_is($scriptHandle)) {
wp_register_script($scriptHandle, '', [], $formUpdateVersion, true);
wp_enqueue_script($scriptHandle);
}
wp_add_inline_script($scriptHandle, $code, $position);
}
private function addInlineStyle($code, $handle = '')
{
$styleHandle = !empty($handle) ? $handle : 'bf-inline-style';
$formUpdateVersion = get_option('bitform_form_update_version');
if (!wp_style_is($styleHandle)) {
wp_register_style($styleHandle, '', [], $formUpdateVersion);
wp_enqueue_style($styleHandle);
}
wp_add_inline_style($styleHandle, $code);
}
private function triggerWorkflowOnLoad($formID, $shortCodeCounter, $fields, $workFlowRunType = 'create')
{
$FrontendFormManager = new FrontendFormManager($formID, $shortCodeCounter);
$previousValue = $this->getValuesFromQueryParams();
$formContent = $FrontendFormManager->getFormContentWithValue($previousValue);
if (!empty($formContent->workFlowExist)) {
$workFlowRunHelper = new WorkFlow($formID);
if (!empty($formContent->workFlowExist->onload)) {
$workFlowreturnedOnLoad = $workFlowRunHelper->executeOnLoad(
$workFlowRunType,
$fields
);
if (!empty($workFlowreturnedOnLoad['fields'])) {
return $workFlowreturnedOnLoad['fields'];
}
}
}
return $fields;
}
private function executeOnUserInput($formID, $shortCodeCounter, $workFlowRunType = 'create')
{
$FrontendFormManager = FrontendFormManager::getInstance($formID, $shortCodeCounter);
$previousValue = $this->getValuesFromQueryParams();
$formContent = $FrontendFormManager->getFormContentWithValue($previousValue);
$customCodesExist = strpos(FrontEndScriptGenerator::getCustomCodes($formID)['JavaScript'], 'bfVars');
if ($customCodesExist || (!empty($formContent->workFlowExist) && !empty($formContent->workFlowExist->oninput))) {
$workFlowRunHelper = new WorkFlow($formID);
return $workFlowRunHelper->executeOnUserInput($workFlowRunType);
}
}
private function getValuesFromQueryParams()
{
// Read-only: query string parsed to pre-fill form fields. Values are sanitized per field before use.
$queryParamsValue = [];
if (isset($_SERVER['QUERY_STRING']) && !empty($_SERVER['QUERY_STRING'])) {
$reqField = wp_unslash($_SERVER['QUERY_STRING']);
foreach (explode('&', $reqField) as $keyValue) {
if (false !== strpos($keyValue, '=')) {
list($field, $value) = explode('=', $keyValue, 2);
if (!trim($value)) {
continue;
}
$field = sanitize_text_field(urldecode($field));
if (!empty($field)) {
$queryParamsValue[$field][] = sanitize_text_field(urldecode($value));
}
}
}
}
return $queryParamsValue;
}
public function handleFrontendRenderRequest($atts)
{
$formType = isset($atts['type']) ? $atts['type'] : 'classic';
$formPreview = isset($atts['form_preview']) ? $atts['form_preview'] : false;
if (isset($atts['form_id'])) {
$formID = intval($atts['form_id']);
}
if (isset($atts['entry_id'])) {
$entryId = intval($atts['entry_id']);
// Read-only: entry ID from query string for shortcode render. No state mutation.
} elseif (isset($_GET['bf_entry_id']) && !is_array($_GET['bf_entry_id'])) {
$entryId = intval(sanitize_text_field(wp_unslash($_GET['bf_entry_id'])));
} else {
$entryId = false;
}
if (isset($atts['id'])) {
$atts = shortcode_atts(['id' => 0], $atts);
$formID = intval($atts['id']);
}
if (!$formID) {
return __('Form ID cannot be empty', 'bit-form');
}
if (!$this->isExist($formID)) {
/* translators: %s: form ID */
return sprintf(__('#%s no. Form doesn\'t exists', 'bit-form'), $formID);
}
// Add-ons may detect whether the current visitor is resuming an abandoned entry.
$isAbandoned = (bool) apply_filters('bitform_is_abandoned_entry', false, $formID, $entryId, $atts);
FrontendHelpers::setBfFrontendFormIds($formID);
$bfFrontendFormIds = FrontendHelpers::$bfFrontendFormIds;
$shortCodeCounter = count($bfFrontendFormIds);
$FrontendFormManager = FrontendFormManager::getInstance($formID, $shortCodeCounter);
if (!$FrontendFormManager->checkStatus()) {
/* translators: %s: form ID */
return sprintf(__('#%s no. Form is not active', 'bit-form'), $formID);
}
ob_start();
$this->loadAssets($formID, $formType);
$font = $FrontendFormManager->getFont();
if ($font && !$formPreview) {
wp_enqueue_style('bf-google-font', $font, '1.0.0', true);
}
// Read-only: password reset token from URL for display-time validation. No state written until form is submitted.
if (!empty($_GET['token']) && !empty($_GET['id'])) {
$this->validPassowordResetToken(sanitize_text_field(wp_unslash($_GET['token'])), sanitize_text_field(wp_unslash($_GET['id'])), $formID);
}
$previousValue = $this->getValuesFromQueryParams();
$errorMessages = []; // delete
$FormIdentifier = esc_js($FrontendFormManager->getFormIdentifier());
$nonce = $FrontendFormManager->getFormToken();
$file = count($FrontendFormManager->getUploadFields()) > 0 ? $FrontendFormManager->getUploadFields() : false;
$FrontendFormManager->setViewCount();
$formContent = $FrontendFormManager->getFormContentWithValue($previousValue);
$fields = $formContent->fields;
$layout = $formContent->layout;
$nestedLayout = isset($formContent->nestedLayout) ? $formContent->nestedLayout : (object) [];
$buttons = !empty($formContent->buttons) ? $formContent->buttons : '';
$additional = $formContent->additional;
// $workFlowRunType = $entryId ? 'edit' : 'create';
if ($entryId && (FrontendHelpers::is_current_user_can_access($formID, 'entryEditAccess'))) {
$workFlowRunType = 'edit';
$adminFormHandler = new AdminFormHandler();
$getEntry = $adminFormHandler->getSingleEntry($formID, $entryId);
if (FrontendHelpers::is_current_user_can_access($formID, 'entryEditAccess', '', $getEntry->__user_id)) {
$fields = $this->setFieldsValue($fields, $formID, $entryId);
} elseif (!$isAbandoned) {
$entryId = false;
$workFlowRunType = 'create';
}
} else {
$entryId = false;
$workFlowRunType = 'create';
}
// if ($entryId) {
// $fields = $this->setFieldsValue($fields, $formID, $entryId);
// }
$fields = apply_filters('bitform_filter_before_workflow_onload_fields', $fields, $formID);
$fields = $this->triggerWorkflowOnLoad($formID, $shortCodeCounter, $fields, $workFlowRunType);
$fields = apply_filters('bitform_filter_after_workflow_onload_fields', $fields, $formID);
do_action('bitform_onload_fields', $fields, $formID);
$workFlowreturnedOnUserInput = $this->executeOnUserInput($formID, $shortCodeCounter, $workFlowRunType);
// test for form before remove
$noLabelFieldTypes = ['decision-box', 'gdpr', 'html', 'shortcode', 'button', 'paypal', 'razorpay', 'recaptcha', 'turnstile', 'hcaptcha', 'stripe', 'spacer'];
foreach ($fields as $fldKey => $field) {
if (!in_array($field->typ, $noLabelFieldTypes) && isset($field->lbl)) {
$lblReplaceToBackslash = str_replace('$_bf_$', '\\', $field->lbl);
$fields->{$fldKey}->lbl = FieldValueHandler::replaceSmartTagWithValue($lblReplaceToBackslash);
}
}
$fieldsKey = $FrontendFormManager->getFieldsKey();
$captchaV3Settings = $FrontendFormManager->getCaptchaV3Settings();
if ($FrontendFormManager->getCaptchaSettings() || $captchaV3Settings || $FrontendFormManager->getTurnstileSettings() || $FrontendFormManager->isFieldTypeExist('hcaptcha')) {
$integrationHandler = new IntegrationHandler(0);
$allFormIntegrations = $integrationHandler->getAllIntegration('app');
if (!is_wp_error($allFormIntegrations)) {
foreach ($allFormIntegrations as $integration) {
if (
$FrontendFormManager->getCaptchaSettings()
&& !is_null($integration->integration_type)
&& 'gReCaptcha' === $integration->integration_type
) {
$integrationDetails = Utilities::jsonObj($integration->integration_details);
if ($integrationDetails) {
$integrationDetails->id = $integration->id;
$reCAPTCHA = $integrationDetails;
$reCAPTCHAVersion = 'v2';
}
}
if (
$FrontendFormManager->getTurnstileSettings()
&& !is_null($integration->integration_type)
&& 'turnstileCaptcha' === $integration->integration_type
) {
$integrationDetails = Utilities::jsonObj($integration->integration_details);
$turnstileSiteKey = $integrationDetails->siteKey ?? '';
}
if (
$FrontendFormManager->isFieldTypeExist('hcaptcha')
&& !is_null($integration->integration_type)
&& 'hcaptcha' === $integration->integration_type
) {
$integrationDetails = Utilities::jsonObj($integration->integration_details);
$hCaptchaSiteKey = $integrationDetails->siteKey ?? '';
}
if ($captchaV3Settings) {
if (!is_null($integration->integration_type) && 'gReCaptchaV3' === $integration->integration_type) {
$integrationDetails = Utilities::jsonObj($integration->integration_details);
if ($integrationDetails) {
$integrationDetails->id = $integration->id;
$reCAPTCHA = $integrationDetails;
$reCAPTCHAVersion = 'v3';
}
}
}
}
}
}
if ($captchaV3Settings && !empty($reCAPTCHA->siteKey)) {
// DANGER: no matter what, DONT CHANGE THE SCRIPT ID OF THIS SCRIPT
$scriptId = BITFORMS_PREFIX . 'recaptcha';
// External Google reCAPTCHA script; version managed by URL query param. Loaded in header because
// standalone form views do not render wp_footer(), making footer enqueue unreliable.
wp_enqueue_script($scriptId, "https://www.google.com/recaptcha/api.js?render={$reCAPTCHA->siteKey}", [], null, false);
}
$configs = [
'bf_separator' => BITFORMS_BF_SEPARATOR,
];
// check if fields has paypal or razorpay
$paymentFields = ['paypal', 'razorpay', 'stripe'];
$paymentFieldData = [];
foreach ($fields as $key => $field) {
if (in_array($field->typ, $paymentFields)) {
$paymentFieldData[$key] = $field;
}
}
if (!empty($paymentFieldData)) {
$integrationHandler = new IntegrationHandler(0);
foreach ($paymentFieldData as $fldKey => $fldData) {
$paymentIntegration = $integrationHandler->getAIntegration($fldData->payIntegID);
if (is_wp_error($paymentIntegration)) {
continue;
}
$paymentIntegrationRow = Utilities::firstRow($paymentIntegration);
if ('paypal' === $fldData->typ) {
$integrationDetails = Utilities::jsonObj($paymentIntegrationRow->integration_details ?? '');
$clientID = $integrationDetails->clientID ?? '';
$fields->{$fldKey}->clientId = $clientID;
} elseif ('razorpay' === $fldData->typ) {
$integrationDetails = Utilities::jsonObj($paymentIntegrationRow->integration_details ?? '');
$clientID = $integrationDetails->apiKey ?? '';
$fields->{$fldKey}->clientId = $clientID;
} elseif ('stripe' === $fldData->typ) {
$integrationDetails = Utilities::jsonObj($paymentIntegrationRow->integration_details ?? '');
$publishableKey = $integrationDetails->publishableKey ?? '';
$fields->{$fldKey}->publishableKey = $publishableKey;
}
}
}
$bitFormFrontArr = [
'ajaxURL' => admin_url('admin-ajax.php'),
'nonce' => $nonce,
'version' => BITFORMS_VERSION,
'layout' => $layout,
'nestedLayout' => $nestedLayout,
'fields' => $fields,
'buttons' => $buttons,
'fieldsKey' => $fieldsKey,
'file' => $file,
'configs' => $configs,
'formId' => $formID,
'appID' => "bitforms_{$formID}",
'GCLID' => $FrontendFormManager->isGCLIDEnabled(),
'assetUrl' => BITFORMS_ASSET_URI,
'onfieldCondition' => !empty($workFlowreturnedOnUserInput['onfield_input_conditions']) ? $workFlowreturnedOnUserInput['onfield_input_conditions'] : false,
'smartTags' => $this->buildFrontendSmartTags($formID, $workFlowreturnedOnUserInput, $fields),
'paymentCallbackUrl' => get_rest_url() . 'bitform/v1/payments/razorpay',
'gRecaptchaSiteKey' => !empty($reCAPTCHA->siteKey) ? $reCAPTCHA->siteKey : null,
'gRecaptchaVersion' => !empty($reCAPTCHAVersion) ? $reCAPTCHAVersion : null,
'turnstileSiteKey' => !empty($turnstileSiteKey) ? $turnstileSiteKey : null,
'hCaptchaSiteKey' => !empty($hCaptchaSiteKey) ? $hCaptchaSiteKey : null,
];
if ($entryId) {
$bitFormFrontArr['entryId'] = $entryId;
}
if (isset($additional->enabled->validateFocusLost)) {
$bitFormFrontArr['validateFocusLost'] = true;
}
if (!empty($isAbandoned)) {
$bitFormFrontArr['oldValues'] = $this->getFieldsValue($formID, $isAbandoned);
if (empty($entryId)) {
$bitFormFrontArr['entryId'] = $entryId;
}
}
$formInfo = $FrontendFormManager->getFormInfo();
$bitFormFrontArr['formName'] = $formInfo->formName ?? '';
if (is_array($layout) && count($layout) > 1) {
$multiStepSettings = isset($formInfo->multiStepSettings) ? $formInfo->multiStepSettings : null;
$newTempSettings = (object) [
'validateOnStepChange' => isset($multiStepSettings->validateOnStepChange) ? $multiStepSettings->validateOnStepChange : false,
'maintainStepHistory' => isset($multiStepSettings->maintainStepHistory) ? $multiStepSettings->maintainStepHistory : false,
'saveProgress' => isset($multiStepSettings->saveProgress) ? $multiStepSettings->saveProgress : false,
'showPercentage' => isset($multiStepSettings->progressSettings->showPercentage) ? $multiStepSettings->progressSettings->showPercentage : false,
];
$bitFormFrontArr['formInfo'] = (object) [
'multiStepSettings' => $newTempSettings
];
}
if (Helpers::property_exists_nested($formInfo, 'conversationalSettings->enable', true)) {
if (!isset($bitFormFrontArr['formInfo'])) {
$bitFormFrontArr['formInfo'] = new \stdClass();
}
$bitFormFrontArr['formInfo']->conversationalSettings = $formInfo->conversationalSettings;
}
$formAbandonmentSettings = $FrontendFormManager->getFormAbandonmentSettings();
if (Helpers::property_exists_nested($formAbandonmentSettings, 'active', true)) {
$bitFormFrontArr['formSettings'] = (object)[
'formAbandonment' => $formAbandonmentSettings
];
}
$layout = wp_json_encode($layout);
$buttons = wp_json_encode($buttons);
$frontArr = wp_json_encode($bitFormFrontArr);
$bfGlobals = sprintf('
if(!window.bf_globals) {
window.bf_globals = {}
} if(!window.bf_globals.%1$s) {
window.bf_globals.%1$s = {}
}
if(document.getElementById("%1$s")) {
window.bf_globals.%1$s = {
...window.bf_globals.%1$s,
...%2$s
};
}', $FormIdentifier, $frontArr);
if ('conversational' === $formType
&& isset($formContent->formInfo->conversationalSettings->enable)
&& $formContent->formInfo->conversationalSettings->enable) {
$html = $FrontendFormManager->conversationalFormView($fields, $file, $errorMessages);
} else {
$html = $FrontendFormManager->formView($fields, $file, $errorMessages);
}
// if form preview then return html otherwise echo with output buffer
if ($formPreview) {
ob_clean();
$formViewObject = new \stdClass();
$formViewObject->html = $html;
$formViewObject->font = $font;
$formViewObject->bfGlobals = $bfGlobals;
$formViewObject->formContent = $formContent;
return $formViewObject;
}
$bfGlobalsHandle = 'bitform-bf-globals-' . sanitize_key($FormIdentifier);
$this->addInlineScript($bfGlobals, $bfGlobalsHandle, 'after');
$this->emitShowPickerBridge();
echo wp_kses(trim($html), EscapingHelper::getFormAllowedHtml($formContent));
return ob_get_clean();
}
/**
* Build the smart-tag map exposed to the browser in window.bf_globals[formId].smartTags.
*
* Security: the legacy code shipped the ENTIRE ~43-tag map to every visitor, leaking
* PII (admin/user/author email) and freezing per-visitor request data (IP, time,
* browser, referer) into cacheable HTML. We now emit ONLY tags that are (a) actually
* referenced by this form's client-evaluated surfaces — conditional logic, payment
* notes, admin custom JS — AND (b) flagged frontend-safe in the registry (static/post
* context only). Sensitive (identity) and request/visitor tags are never emitted; they
* resolve server-side at submit time instead.
*
* @param int|string $formID
* @param mixed $workflowConditions on-field input conditions (client-evaluated)
* @param mixed $fields form fields object (carries payment notes, etc.)
* @return array
*/
private function buildFrontendSmartTags($formID, $workflowConditions, $fields)
{
// Haystack = only surfaces the browser actually evaluates against smartTags.
$haystack = wp_json_encode($workflowConditions) . ' ' . wp_json_encode($fields);
$customJs = FrontEndScriptGenerator::getCustomCodes($formID)['JavaScript'];
if (is_string($customJs) && '' !== $customJs) {
$haystack .= ' ' . $customJs;
}
$ctx = SmartTags::getPostUserData();
$frontendSmartTags = [];
$referenced = [];
foreach (SmartTags::smartTagFieldKeys() as $key) {
if (!SmartTagRegistry::isFrontendExposable($key)) {
continue; // identity / request / param tags never travel to the browser
}
// Match '${' . key prefix so keys containing spaces/slashes/commas are handled.
if (false !== strpos($haystack, '${' . $key)) {
$referenced[] = $key;
$frontendSmartTags[$key] = SmartTagRegistry::resolve($key, $ctx);
}
}
/**
* Escape hatch: a site that genuinely needs an extra tag client-side can opt it
* back in explicitly here, rather than core shipping everything by default.
*
* @param array $frontendSmartTags resolved frontend-safe smart tags
* @param int|string $formID
* @param string[] $referenced keys detected in client surfaces
*/
return apply_filters('bitform_frontend_smarttags', $frontendSmartTags, $formID, $referenced);
}
/**
* Delegated listener that opens the native picker on date/time inputs marked
* with data-bf-show-picker. Replaces the legacy hardcoded onclick attribute.
* Registered as inline script once per request via wp_add_inline_script so
* the markup never travels through wp_kses().
*/
private function emitShowPickerBridge()
{
static $emitted = false;
if ($emitted) {
return;
}
$emitted = true;
$code = 'if(!window.__bfShowPickerBound){window.__bfShowPickerBound=true;document.addEventListener("click",function(e){var t=e.target;if(t&&t.matches&&t.matches("input[data-bf-show-picker=\"1\"]")&&typeof t.showPicker==="function"){try{t.showPicker();}catch(_){}}});}';
$this->addInlineScript($code, 'bitform-show-picker-bridge', 'after');
}
private function isExist($formID)
{
$formModel = new FormModel();
$form = $formModel->get(
[
'id'
],
[
'id' => $formID,
]
);
if (!is_wp_error($form)) {
return true;
}
return false;
}
private function getFieldsValue($formID, $entryID)
{
$FrontendFormManager = FrontendFormManager::getInstance($formID, 1);
$formEntryModel = new FormEntryMetaModel();
$metaValues = $formEntryModel->get(
[
'meta_key',
'meta_value'
],
[
'bitforms_form_entry_id' => $entryID,
]
);
$formFields = $FrontendFormManager->getFields();
$fldsData = (object) [];
if (!is_wp_error($metaValues)) {
foreach ($metaValues as $metaValue) {
$metaKey = $metaValue->meta_key;
$metaVal = $metaValue->meta_value;
// if meta value is array then convert to string
if (preg_match('/^\[.*\]$/', $metaVal)) {
$metaVal = json_decode($metaVal);
//check is it array of objects
if (is_array($metaVal) && is_object($metaVal[0])) {
$metaVal = $metaValue->meta_value;
} else {
$metaVal = implode(BITFORMS_BF_SEPARATOR, $metaVal);
}
}
if (!isset($fldsData->{$metaKey})) {
$fldsData->{$metaKey} = '';
}
$fldsData->{$metaKey} = $metaVal;
if (isset($formFields[$metaKey]['type']) && in_array($formFields[$metaKey]['type'], ['file-up', 'advanced-file-up'])) {
$fldsData->{$metaKey} = $metaValue->meta_value;
}
}
}
return $fldsData;
}
public function setFieldsValue($fields, $formID, $entryID)
{
$formEntryModel = new FormEntryMetaModel();
$metaValues = $formEntryModel->get(
[
'meta_key',
'meta_value'
],
[
'bitforms_form_entry_id' => $entryID,
]
);
if (!is_wp_error($metaValues)) {
$urlQuery = wp_parse_url(FileDownloadProvider::getBaseDownloadURL(), PHP_URL_QUERY);
$baseDLURL = FileDownloadProvider::getBaseDownloadURL();
$baseDLURL = empty($urlQuery) ? $baseDLURL . '?' : $baseDLURL . '&';
$baseDLURL .= "formID={$formID}&entryID={$entryID}";
foreach ($fields as $field) {
if ('file-up' === $field->typ || 'advanced-file-up' === $field->typ) {
if (!isset($field->config)) {
$field->config = (object) [];
} elseif (is_array($field->config)) {
$field->config = (object) $field->config;
}
$field->config->baseDLURL = $baseDLURL;
}
}
foreach ($metaValues as $metaValue) {
$metaKey = $metaValue->meta_key;
$metaVal = $metaValue->meta_value;
// if meta value is array then convert to string
if (preg_match('/^\[.*\]$/', $metaVal)) {
$metaVal = json_decode($metaVal);
//check is it array of objects
if (is_array($metaVal) && is_object($metaVal[0])) {
$metaVal = $metaValue->meta_value;
} else {
$metaVal = implode(BITFORMS_BF_SEPARATOR, $metaVal);
}
}
if (property_exists($fields, $metaKey)) {
$fields->{$metaKey}->val = $metaVal;
if ('file-up' === $fields->{$metaKey}->typ || 'advanced-file-up' === $fields->{$metaKey}->typ) {
$fields->{$metaKey}->val = $metaValue->meta_value;
$fields->{$metaKey}->config->oldFiles = $metaValue->meta_value;
}
}
}
}
return $fields;
}
public function loadAssets($formID = 0, $fromType = 'classic')
{
$bfUniqFormIds = FrontendHelpers::getAllFormIdsInPage();
$isPageBuilder = FrontendHelpers::$isPageBuilder;
$bfMultipleFormsExists = $isPageBuilder ? true : count($bfUniqFormIds) > 1;
if (!empty($formID)) {
$formIds = [$formID];
} else {
$formIds = $bfUniqFormIds;
}
foreach ($formIds as $formID) {
global $bitform_dequeued_styles;
if (is_array($bitform_dequeued_styles) && in_array($formID, $bitform_dequeued_styles)) {
continue;
}
if ($bfMultipleFormsExists) {
$newFormId = $formID . '-formid';
} else {
$newFormId = $formID;
}
$formUpdateVersion = get_option('bitform_form_update_version');
if (!wp_style_is('bitform-style-' . $newFormId) && is_readable(BITFORMS_CONTENT_DIR . '/form-styles/bitform-' . $newFormId . '.css')) {
wp_enqueue_style(
'bitform-style-' . $newFormId,
BITFORMS_UPLOAD_BASE_URL . "/form-styles/bitform-{$newFormId}.css",
[],
$formUpdateVersion
);
if ($isPageBuilder) {
$formStyle = file_get_contents(BITFORMS_CONTENT_DIR . '/form-styles/bitform-' . $newFormId . '.css');
echo '';
}
}
if (!wp_style_is('bitform-style-custom-' . $formID) && is_readable(BITFORMS_CONTENT_DIR . '/form-styles/bitform-custom-' . $formID . '.css')) {
wp_enqueue_style(
'bitform-style-custom-' . $formID,
BITFORMS_UPLOAD_BASE_URL . "/form-styles/bitform-custom-{$formID}.css",
[],
$formUpdateVersion
);
if ($isPageBuilder) {
$formStyle = file_get_contents(BITFORMS_CONTENT_DIR . '/form-styles/bitform-custom-' . $formID . '.css');
echo '';
}
}
// load conversational form css
if ('conversational' === $fromType) {
if (!wp_style_is('bitform-conversational-style-' . $formID) &&
is_readable(BITFORMS_CONTENT_DIR . "/form-styles/bitform-conversational-{$formID}.css")) {
wp_enqueue_style(
'bitform-conversational-style',
BITFORMS_UPLOAD_BASE_URL . "/form-styles/bitform-conversational-{$formID}.css",
[],
$formUpdateVersion
);
}
}
}
}
}