# bit-form/2.0/includes/Frontend/Form/FrontendFormHandler.php

Bit Form – Contact Form, Payment Forms, Multi Step Forms, Calculator &amp; Custom Form Builder, version 2.0. 476 lines.

- Page: https://pluginprobe.com/plugins/bit-form/2.0/code/includes/Frontend/Form/FrontendFormHandler.php
- Raw: https://pluginprobe.com/plugins/bit-form/2.0/raw/includes/Frontend/Form/FrontendFormHandler.php
- Modified: 2023-02-28T14:03:48+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/bit-form/2.0/code/includes/Frontend/Form/FrontendFormHandler.php#L10-L20`.

```php
<?php

namespace BitCode\BitForm\Frontend\Form;

use BitCode\BitForm\Admin\Form\FrontEndScriptGenerator;
use BitCode\BitForm\Core\Database\FormModel;
use BitCode\BitForm\Core\Form\FormManager;
use BitCode\BitForm\Core\Integration\IntegrationHandler;
use BitCode\BitForm\Core\Util\FieldValueHandler;
use BitCode\BitForm\Core\Util\FrontendHelpers;
use BitCode\BitForm\Core\WorkFlow\WorkFlow;

final class FrontendFormHandler {
  public function __construct() {
    add_action('wp_enqueue_scripts', [$this, 'loadAssets']);
    add_action('wp_footer', [$this, 'generateJS']);
    add_shortcode('bitform', [$this, 'handleFrontendRenderRequest']);
  }

  private function validPassowordResetToken($token, $userID, $formId) {
    $existResetInteg = (new IntegrationHandler($formId))->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 "<div id='bf-resp' style='display:grid;justify-content:center;color:#860000;'>This password reset token is invalid.</div>";
            exit();
          }
        } else {
          echo "<div id='bf-resp' style='display:grid;justify-content:center;color:#860000;'>Invalid User!!</div>";
          exit();
        }
      }
    }
  }

  private function getJSFileSrc($postId) {
    $formUpdateVersion = get_option('bit-form_form_update_version');
    $formScriptSrc = BITFORMS_UPLOAD_BASE_URL . "/form-scripts/$postId/bitform-js-$postId.js?bfv=$formUpdateVersion";

    return $formScriptSrc;
  }

  public function generateJs($formID = null) {
    $isFormPreview = get_transient('bitform_form_preview');
    if ($isFormPreview && !$formID) {
      delete_transient('bitform_form_preview');
      return;
    }
    FrontendHelpers::isPageBuilder();
    global $isPageBuilder;
    if ($isPageBuilder) {
      return;
    }
    // for unique fields ids in the same form (e.g. multiple forms in the same page)
    $allFields = [];
    $formContents = [];
    $contentIds = [];
    $formIDs = [];
    $preview = false;
    $postId = '';

    if ($formID) {
      $formIDs[] = $formID;
      $FrontendFormManager = new FrontendFormManager($formID, 1);
      $FormIdentifier = esc_js($FrontendFormManager->getFormIdentifier());
      $formContent = $FrontendFormManager->getFormContentWithValue($this->getValuesFromQueryParams());
      $formContents[] = $formContent;
      $fields = $this->triggerWorkflowOnLoad($formID, 1, $formContent->fields);
      array_push($contentIds, $FormIdentifier);
      foreach ($fields as $fk => $field) {
        $allFields[$field->typ][] = ['fk' => $fk, 'field' => $field, 'formID' => $formID, 'contentId' => $FormIdentifier];
      }
      $preview = true;
      $postId = $formID;
    } else {
      global $post;
      if (!is_object($post) && !isset($post->ID)) {
        return;
      }
      FrontendHelpers::handleBfFormIdsSession();
      global $bfFrontendFormIds;
      $bfUniqFormIds = array_unique($bfFrontendFormIds);

      $regenerateScriptFlag = $this->regenerateScriptChecker($bfUniqFormIds);
      $postId = $post->ID;
      if (!$regenerateScriptFlag) {
        $regenerateScriptFlag = $this->deleteUnusedFormPageIds($postId, $bfUniqFormIds);
      }
      $isJsGenerating = get_option('bitforms_frontend_js_generating');
      if (!$regenerateScriptFlag && !$isJsGenerating) {
        wp_enqueue_script('bit-form-all-script-test', $this->getJSFileSrc($postId), [], '', true);
        return;
      }

      $formIDs = $bfUniqFormIds;

      foreach ($bfFrontendFormIds as $index => $formId) {
        $shortCodeCounter = $index + 1;
        $FrontendFormManager = new FrontendFormManager($formId, $shortCodeCounter);
        $FormIdentifier = esc_js($FrontendFormManager->getFormIdentifier());
        $formContent = $FrontendFormManager->getFormContentWithValue($this->getValuesFromQueryParams());
        $formContents[] = $formContent;
        $fields = $this->triggerWorkflowOnLoad($formId, $shortCodeCounter, $formContent->fields);
        array_push($contentIds, $FormIdentifier);
        foreach ($fields as $fk => $field) {
          $allFields[$field->typ][] = ['fk' => $fk, 'field' => $field, 'formID' => $formId, 'contentId' => $FormIdentifier];
        }
      }
    }
    (new FrontEndScriptGenerator())->generateJsFile($formContents, $allFields, $contentIds, $postId, $formIDs, $preview);
    wp_enqueue_script('bit-form-all-script-test', $this->getJSFileSrc($postId), [], '', 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]);
        $regenerateScriptFlag = true;
        $formModel->update(['generated_script_page_ids' => wp_json_encode($generatedScriptPageIdsDecoded)], ['id' => $formId]);
      }
    }
    return $regenerateScriptFlag;
  }

  private function regenerateScriptChecker($formsIds) {
    global $post;
    if (!is_object($post) && !isset($post->ID)) {
      return;
    }
    $postId = $post->ID;
    $regenerateScriptFlag = false;
    $formModel = new FormModel();
    foreach ($formsIds as $formId) {
      $formInstance = new FormManager($formId);
      $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;
      }

      $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';
    if (!wp_script_is($scriptHandle)) {
      wp_register_script($scriptHandle, '', [], '', true);
      wp_enqueue_script($scriptHandle);
    }
    wp_add_inline_script($scriptHandle, $code, $position);
  }

  private function addInlineStyle($code, $handle = '') {
    $styleHandle = !empty($handle) ? $handle : 'bf-inline-style';
    if (!wp_style_is($styleHandle)) {
      wp_register_style($styleHandle, '', [], '', true);
      wp_enqueue_style($styleHandle);
    }
    wp_add_inline_style($styleHandle, $code);
  }

  private function triggerWorkflowOnLoad($formID, $shortCodeCounter, $fields) {
    $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(
          'create',
          $fields
        );

        if (!empty($workFlowreturnedOnLoad['fields'])) {
          return $workFlowreturnedOnLoad['fields'];
        }
      }
    }

    return $fields;
  }

  private function executeOnUserInput($formID, $shortCodeCounter, $fields) {
    $FrontendFormManager = new FrontendFormManager($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('create', $fields);
    }
  }

  private function getValuesFromQueryParams() {
    $reqField = $_SERVER['QUERY_STRING'];
    $queryParamsValue = [];
    if (!empty($reqField)) {
      foreach (explode('&', $reqField) as $keyValue) {
        // $pattern = '/([a-zA-Z0-9])([a-zA-Z])\=+/';
        $pattern = '/([^.]+)=(.*?)([^.]+)/';
        $matches = preg_match($pattern, $keyValue, $matchFormat);
        if ($matches) {
          list($field, $value) = explode('=', $keyValue, 2);

          if (!trim($value)) {
            continue;
          }

          $queryParamsValue[$field][] = sanitize_text_field(urldecode($value));
        }
      }
    }

    return $queryParamsValue;
  }

  public function handleFrontendRenderRequest($atts, $formPreview = false) {
    static $shortCodeCounter = 0;
    $shortCodeCounter += 1;

    if ($formPreview) {
      // when $formPreview is true, it means that the atts is the form id
      $formID = $atts;
    } else {
      $atts = shortcode_atts(['id' => 0], $atts);
      $formID = intval($atts['id']);
    }

    if (!$formID) {
      return __('Form ID cannot be empty', 'bit-form');
    }

    if (!$this->isExist($formID)) {
      return sprintf(__('#%s no. Form doesn\'t exists', 'bit-form'), $formID);
    }
    FrontendHelpers::handleBfFormIdsSession($formID);
    $FrontendFormManager = new FrontendFormManager($formID, $shortCodeCounter);

    $font = $FrontendFormManager->getFont();

    if ($font && !$formPreview) {
      wp_enqueue_style('google-font', $font, '1.0.0', true);
    }

    if (!empty($_GET['token']) && !empty($_GET['id'])) {
      $this->validPassowordResetToken($_GET['token'], $_GET['id'], $formID);
    }

    $previousValue = $this->getValuesFromQueryParams();
    $errorMessages = []; // delete
    $FormIdentifier = esc_js($FrontendFormManager->getFormIdentifier());
    $nonce = $FrontendFormManager->getFormToken();
    $file = count($FrontendFormManager->getUploadFields()) > 0 ? $FrontendFormManager->getUploadFields() : false;

    if ($FrontendFormManager->checkStatus()) {
      $FrontendFormManager->setViewCount();

      $formContent = $FrontendFormManager->getFormContentWithValue($previousValue);
      $fields = $formContent->fields;
      $layout = $formContent->layout;
      $buttons = !empty($formContent->buttons) ? $formContent->buttons : '';
      $additional = $formContent->additional;

      $fields = $this->triggerWorkflowOnLoad($formID, $shortCodeCounter, $fields);
      $workFlowreturnedOnUserInput = $this->executeOnUserInput($formID, $shortCodeCounter, $fields);

      // only for form not preview
      if (!wp_style_is('bitform-style' . $formID)) {
        $this->loadAssets(true, $formID, $file);
      }

      // test for form before remove
      $noLabel = ['decision-box', 'html', 'button', 'paypal', 'razorpay', 'recaptcha'];
      $newFields = json_decode(json_encode($fields), true);
      foreach ($newFields as $fldKey => $field) {
        if (!in_array($field['typ'], $noLabel) && isset($field['lbl'])) {
          $lblReplaceToBackslash = str_replace('$_bf_$', '\\', $field['lbl']);
          $newFields[$fldKey]['lbl'] = FieldValueHandler::replaceSmartTagWithValue($lblReplaceToBackslash);
        }
      }
      $fieldsKey = $FrontendFormManager->getFieldsKey();

      $captchaV3Settings = $FrontendFormManager->getCaptchaV3Settings();
      if ($FrontendFormManager->getCaptchaSettings() || $captchaV3Settings) {
        $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 = json_decode($integration->integration_details);
              $integrationDetails->id = $integration->id;
              $reCAPTCHA = $integrationDetails;
              $reCAPTCHAVersion = 'v2';
            }

            if ($captchaV3Settings) {
              if (!is_null($integration->integration_type) && 'gReCaptchaV3' === $integration->integration_type) {
                $integrationDetails = json_decode($integration->integration_details);
                $integrationDetails->id = $integration->id;
                $reCAPTCHA = $integrationDetails;
                $reCAPTCHAVersion = 'v3';
              }
            }
          }
        }
      }

      $configs = [
        'bf_separator' => BITFORMS_BF_SEPARATOR,
      ];

      $bitFormFrontArr = [
        'ajaxURL'                        => admin_url('admin-ajax.php'),
        'nonce'                          => $nonce,
        'version'                        => BITFORMS_VERSION,
        'layout'                         => $layout,
        'fields'                         => $newFields,
        'buttons'                        => $buttons,
        'fieldsKey'                      => $fieldsKey,
        'file'                           => $file,
        'configs'                        => $configs,
        'formId'                         => $formID,
        'GCLID'                          => $FrontendFormManager->isGCLIDEnabled(),
        'assetUrl'                       => BITFORMS_ASSET_URI,
        'onfieldCondition'               => !empty($workFlowreturnedOnUserInput['onfield_input_conditions']) ? $workFlowreturnedOnUserInput['onfield_input_conditions'] : false,
        'smartTags'                      => !empty($workFlowreturnedOnUserInput['smart_tags']) ? $workFlowreturnedOnUserInput['smart_tags'] : [],
        'paymentCallbackUrl'             => get_rest_url() . 'bitform/v1/payments/razorpay',
        'gRecaptchaSiteKey'              => !empty($reCAPTCHA->siteKey) ? $reCAPTCHA->siteKey : null,
        'gRecaptchaVersion'              => !empty($reCAPTCHAVersion) ? $reCAPTCHAVersion : null,
      ];

      if (isset($additional->enabled->validateFocusLost)) {
        $bitFormFrontArr['validateFocusLost'] = true;
      }

      $bitFormsFront = apply_filters(
        'bitforms_localized_script',
        $bitFormFrontArr
      );

      $fields = \json_encode($fields);
      $layout = \json_encode($layout);
      $buttons = \json_encode($buttons);
      $frontArr = json_encode($bitFormFrontArr);

      $bfGlobals = "if(!window.bf_globals) { 
        window.bf_globals = {} 
      } if(!window.bf_globals.{$FormIdentifier}) { 
        window.bf_globals.{$FormIdentifier} = {} 
      }
      window.bf_globals.{$FormIdentifier} = {...window.bf_globals.{$FormIdentifier}, ...{$frontArr}};";
      $this->addInlineScript($bfGlobals, 'bit-form-all-script', 'before');

      $html = '';

      FrontendHelpers::isPageBuilder();
      global $isPageBuilder;
      if ($isPageBuilder) {
        $newFormId = $formID . '-formid';
        $formStyles = file_get_contents(BITFORMS_CONTENT_DIR . '/form-styles/bitform-' . $newFormId . '.css');
        $html .= '<style>' . $formStyles . '</style>';
      }
      $html .= $FrontendFormManager->formView($fields, $file, $errorMessages);
      // if form preview then return html otherwise echo with output buffer
      if ($formPreview) {
        $formViewObject = new \stdClass();
        $formViewObject->html = $html;
        $formViewObject->font = $font;
        $formViewObject->bfGlobals = $bfGlobals;
        return $formViewObject;
      }

      ob_start();
      echo trim($html);
      return ob_get_clean();
    }
  }

  private function isExist($formID) {
    $formModel = new FormModel();
    $form = $formModel->get(
      [
        'id'
      ],
      [
        'id' => $formID,
      ]
    );
    if (!is_wp_error($form)) {
      return true;
    }
    return false;
  }

  public function loadAssets($recheck = false, $formID = 0, $isFileExists = false) {
    FrontendHelpers::getFormIdsFromPost();
    FrontendHelpers::isPageBuilder();
    global $bfUniqFormIds;
    global $bfMultipleFormsExists;

    if ($formID) {
      $formIds = [$formID];
      if (count($bfUniqFormIds) > 1) {
        $bfMultipleFormsExists = true;
      }
    } else {
      $formIds = $bfUniqFormIds;
    }

    foreach ($formIds as $formID) {
      if ($bfMultipleFormsExists) {
        $newFormId = $formID . '-formid';
      } else {
        $newFormId = $formID;
      }
      if (is_readable(BITFORMS_CONTENT_DIR . '/form-styles/bitform-' . $newFormId . '.css')) {
        $styleModifyTime = filemtime(BITFORMS_CONTENT_DIR . '/form-styles/bitform-' . $newFormId . '.css');
        wp_register_style(
          'bitform-style' . $formID,
          BITFORMS_UPLOAD_BASE_URL . '/form-styles/bitform-' . $newFormId . '.css',
          [],
          $styleModifyTime,
          'all'
        );
        wp_enqueue_style('bitform-style' . $formID);
      }
      if (is_readable(BITFORMS_CONTENT_DIR . '/form-styles/bitform-custom-' . $newFormId . '.css')) {
        $styleModifyTime = filemtime(BITFORMS_CONTENT_DIR . '/form-styles/bitform-custom-' . $newFormId . '.css');
        wp_register_style(
          'bitform-style-custom-' . $formID,
          BITFORMS_UPLOAD_BASE_URL . '/form-styles/bitform-custom-' . $newFormId . '.css',
          [],
          $styleModifyTime,
          'all'
        );
        wp_enqueue_style('bitform-style-custom-' . $formID);
      }
    }
  }
}

```
