PluginProbe
Bit Form – Contact Form, Payment Forms, Multi Step Forms, Calculator & Custom Form Builder / 3.2.2
Bit Form – Contact Form, Payment Forms, Multi Step Forms, Calculator & Custom Form Builder v3.2.2
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 / Admin / Form / AdminFormHandler.php

AdminFormHandler.php in Bit Form – Contact Form, Payment Forms, Multi Step Forms, Calculator & Custom Form Builder 3.2.2, at includes/Admin/Form/AdminFormHandler.php

3,062 lines 117.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Handle Form Create,Update,delete Operation
5 *
6 */
7
8 namespace BitCode\BitForm\Admin\Form;
9
10 use BitCode\BitForm\Admin\Form\Template\TemplateProvider;
11 use BitCode\BitForm\Core\Database\EmailTemplateModel;
12 use BitCode\BitForm\Core\Database\FormEntryLogModel;
13 use BitCode\BitForm\Core\Database\FormEntryMetaModel;
14 use BitCode\BitForm\Core\Database\FormEntryModel;
15 use BitCode\BitForm\Core\Database\FormModel;
16 use BitCode\BitForm\Core\Database\IntegrationModel;
17 use BitCode\BitForm\Core\Database\ReportsModel;
18 use BitCode\BitForm\Core\Database\SuccessMessageModel;
19 use BitCode\BitForm\Core\Database\WorkFlowModel;
20 use BitCode\BitForm\Core\Form\FormManager;
21 use BitCode\BitForm\Core\Integration\IntegrationHandler;
22 use BitCode\BitForm\Core\Messages\EmailTemplateHandler;
23 use BitCode\BitForm\Core\Messages\SuccessMessageHandler;
24 use BitCode\BitForm\Core\Migration\MigrationHelper;
25 use BitCode\BitForm\Core\Util\FileHandler;
26 use BitCode\BitForm\Core\Util\FormDuplicateHelper;
27 use BitCode\BitForm\Core\Util\HttpHelper;
28 use BitCode\BitForm\Core\Util\IpTool;
29 use BitCode\BitForm\Core\Util\Log;
30 use BitCode\BitForm\Core\Util\Utilities;
31 use BitCode\BitForm\Core\WorkFlow\WorkFlow;
32 use BitCode\BitForm\Core\WorkFlow\WorkFlowHandler;
33 use WP_Error;
34
35 class AdminFormHandler
36 {
37 private static $formModel;
38 private static $ipTool;
39
40 public function __construct()
41 {
42 static::$formModel = new FormModel();
43 static::$ipTool = new IpTool();
44 }
45
46 public function getTemplate($Request, $post)
47 {
48 $templateName = null;
49 $newFormId = null;
50 if (isset($post->template)) {
51 $templateName = $post->template;
52 $newFormId = $post->newFormId;
53 }
54
55 $templateProvider = new TemplateProvider();
56 $form_content_raw = $templateProvider->getTemplate($templateName, $newFormId);
57 if (!$form_content_raw) {
58 return new WP_Error('template_empty', __('Template not found, by this name: ', 'bit-form') . $templateName);
59 } else {
60 return wp_json_encode(
61 [
62 'id' => 0,
63 'form_content' => $form_content_raw,
64 ]
65 );
66 }
67 }
68
69 public function saveStyleSheet($styles, $sheetName)
70 {
71 $this->createFormStylesDirIfNotExists();
72
73 if (
74 file_exists(BITFORMS_CONTENT_DIR . DIRECTORY_SEPARATOR . 'form-styles')
75 && wp_is_writable(BITFORMS_CONTENT_DIR . DIRECTORY_SEPARATOR . 'form-styles')
76 ) {
77 $filePath = BITFORMS_CONTENT_DIR . DIRECTORY_SEPARATOR . 'form-styles' . DIRECTORY_SEPARATOR . $sheetName;
78 return FileHandler::writeFile($filePath, $styles);
79 }
80 return false;
81 }
82
83 public function saveLayoutStyleSheet($layout, $sheetName, $lay_row_height = 43)
84 {
85 $md_width = 600;
86 $sm_width = 400;
87 $lg_styles = '';
88 $md_styles = '';
89 $sm_styles = '';
90 for ($i = 0; $i < count($layout->lg ?? []); $i++) {
91 $fld = $layout->lg[$i];
92
93 if ($fld->w < 10) {
94 $lay_row_height = 43;
95 } else {
96 $lay_row_height = 2;
97 }
98
99 $class = $fld->i;
100 $lg_g_r_s = $fld->y + 1;
101 $lg_g_c_s = $fld->x + 1;
102 $lg_g_r_e = 1 !== $fld->y ? $fld->h + ($fld->y + 1) : 1;
103 $lg_g_c_e = ($fld->x + 1) + $fld->w;
104 $lg_g_r_span = $lg_g_r_e - $lg_g_r_s;
105 $lg_g_c_span = $lg_g_c_e - $lg_g_c_s;
106 $lg_min_height = $fld->h * $lay_row_height . 'px;';
107
108 $lg_styles .= ".$class { grid-area: $lg_g_r_s / $lg_g_c_s / $lg_g_r_e / $lg_g_c_e ; -ms-grid-row: $lg_g_r_s; -ms-grid-row-span: $lg_g_r_span; -ms-grid-column: $lg_g_c_s; -ms-grid-column-span: $lg_g_c_span; min-height: $lg_min_height; }";
109
110 $fld = $layout->md[$i];
111
112 $class = $fld->i;
113 $md_g_r_s = $fld->y + 1;
114 $md_g_c_s = $fld->x + 1;
115 $md_g_r_e = 1 !== $fld->y ? $fld->h + ($fld->y + 1) : 1;
116 $md_g_c_e = ($fld->x + 1) + $fld->w;
117 $md_g_r_span = $lg_g_r_e - $md_g_r_s;
118 $md_g_c_span = $lg_g_c_e - $md_g_c_s;
119 $md_min_height = $fld->h * $lay_row_height . 'px;';
120
121 $md_styles .= ".$class { grid-area: $md_g_r_s / $md_g_c_s / $md_g_r_e / $md_g_c_e ; -ms-grid-row: $md_g_r_s; -ms-grid-row-span: $md_g_r_span; -ms-grid-column: $md_g_c_s; -ms-grid-column-span: $md_g_c_span; min-height: $md_min_height; }";
122
123 $fld = $layout->sm[$i];
124
125 $class = $fld->i;
126 $sm_g_r_s = $fld->y + 1;
127 $sm_g_c_s = $fld->x + 1;
128 $sm_g_r_e = 1 !== $fld->y ? $fld->h + ($fld->y + 1) : 1;
129 $sm_g_c_e = ($fld->x + 1) + $fld->w;
130 $sm_g_r_span = $sm_g_r_e - $sm_g_r_s;
131 $sm_g_c_span = $sm_g_c_e - $sm_g_c_s;
132 $sm_min_height = $fld->h * $lay_row_height . 'px;';
133
134 $sm_styles .= ".$class { grid-area: $sm_g_r_s / $sm_g_c_s / $sm_g_r_e / $sm_g_c_e ; -ms-grid-row: $sm_g_r_s; -ms-grid-row-span: $sm_g_r_span; -ms-grid-column: $sm_g_c_s; -ms-grid-column-span: $sm_g_c_span; min-height: $sm_min_height; }";
135 }
136 $formStyle = "._frm-g{
137 display: grid;
138 display: -ms-grid;
139 grid-template-columns: repeat( 6 , minmax( 30px , 1fr ));
140 -ms-grid-columns: minmax( 30px , 1fr ) minmax( 30px , 1fr ) minmax( 30px , 1fr ) minmax( 30px , 1fr ) minmax( 30px , 1fr ) minmax( 30px , 1fr );
141 }
142 {$lg_styles}
143 @media only screen and (max-width:{$md_width}px) {
144 ._frm-g {grid-template-columns: repeat( 4 , minmax( 30px , 1fr ));-ms-grid-columns: minmax( 30px , 1fr ) minmax( 30px , 1fr ) minmax( 30px , 1fr ) minmax( 30px , 1fr );}
145 {$md_styles}
146 }
147 @media only screen and (max-width:{$sm_width}px) {
148 ._frm-g {grid-template-columns: repeat( 2 , minmax( 30px , 1fr ));-ms-grid-columns: minmax( 30px , 1fr ) minmax( 30px , 1fr );}
149 {$sm_styles}
150 }";
151
152 $this->createFormStylesDirIfNotExists();
153
154 if (
155 file_exists(BITFORMS_CONTENT_DIR . DIRECTORY_SEPARATOR . 'form-styles')
156 && wp_is_writable(BITFORMS_CONTENT_DIR . DIRECTORY_SEPARATOR . 'form-styles')
157 ) {
158 $filePath = BITFORMS_CONTENT_DIR . DIRECTORY_SEPARATOR . 'form-styles' . DIRECTORY_SEPARATOR . $sheetName;
159 return FileHandler::writeFile($filePath, $formStyle);
160 }
161 return false;
162 }
163
164 public function createFormStylesDirIfNotExists()
165 {
166 if (!file_exists(BITFORMS_UPLOAD_DIR)) {
167 wp_mkdir_p(BITFORMS_UPLOAD_DIR);
168 }
169 if (!file_exists(BITFORMS_CONTENT_DIR . DIRECTORY_SEPARATOR . 'form-styles')) {
170 wp_mkdir_p(BITFORMS_CONTENT_DIR . DIRECTORY_SEPARATOR . 'form-styles');
171 }
172 }
173
174 private function pdfFontDownload($fontName)
175 {
176 if (class_exists('\BitCode\BitFormPro\Admin\AppSetting\Pdf')) {
177 \BitCode\BitFormPro\Admin\AppSetting\Pdf::getInstance()->fontsDownload($fontName);
178 }
179 return false;
180 }
181
182 public function createNewForm($Request, $post)
183 {
184 // wp_send_json_success($post);
185 // exit;
186 if (!isset($post->form_id) || '' === $post->form_id) {
187 return new WP_Error('empty_form', __('Error Occurred, Please Reload', 'bit-form'));
188 }
189
190 $formManager = new AdminFormManager($post->form_id);
191 if ($formManager->isExist()) {
192 return new WP_Error('empty_form', __('Error Occurred, Please Reload', 'bit-form'));
193 }
194
195 if (isset($post->formStyle) && $post->formStyle) {
196 $sheetName = 'bitform-' . $post->form_id . '.css';
197 $this->saveStyleSheet($post->formStyle, $sheetName);
198 }
199
200 if (isset($post->layoutChanged) && $post->layoutChanged) {
201 $sheetName = 'bitform-layout-' . $post->form_id . '.css';
202 $rowHeight = (int) $post->rowHeight;
203 $this->saveLayoutStyleSheet($post->layout, $sheetName, $rowHeight);
204 }
205
206 $fields = wp_unslash($post->fields);
207 $fields = Helpers::replaceFieldsDefaultErrorMsg($fields);
208 // $fields = $post->fields;
209 $layout = wp_unslash($post->layout);
210 $nestedLayout = isset($post->nestedLayouts) ? wp_unslash($post->nestedLayouts) : (object) [];
211 $formInfo = wp_unslash($post->formInfo);
212 $form_name = wp_unslash($post->form_name);
213 $form_name = strlen($form_name) > 50 ? substr($form_name, 0, 50) : $form_name;
214 $formSettings = (object) wp_unslash($post->formSettings);
215 $atomic_class_map = isset($post->atomicClassMap) ? wp_unslash($post->atomicClassMap) : [];
216 $breakpointSize = wp_unslash($post->breakpointSize);
217 $style = $post->style;
218 $themeVars = $post->themeVars;
219 $themeColors = $post->themeColors;
220 $staticStyles = $post->staticStyles;
221 $workFlows = wp_unslash($post->workFlows);
222 $additional = wp_unslash($post->additional);
223 $reports = !empty($post->reports) ? $post->reports : (object) [];
224 $builderSettings = (object) isset($post->builderSettings) ? wp_unslash($post->builderSettings) : [];
225
226 $mailTem = $formSettings->mailTem;
227 $pdfTem = $formSettings->pdfTem;
228 $integrations = $formSettings->integrations;
229 $formPermissions = $formSettings->formPermissions;
230
231 $user_details = static::$ipTool->getUserDetail();
232 if (empty($fields) || empty($layout)) {
233 return new WP_Error(
234 'empty_form',
235 __('Can not save empty form.', 'bit-form')
236 );
237 }
238 if (strlen($form_name) > 50) {
239 return new WP_Error(
240 'empty_form',
241 __('Form Name Should Be Within 50 Characters', 'bit-form')
242 );
243 }
244 // Guard: never persist orphan fields (in fields but in no layout) — they
245 // render nothing yet their validation rules block submission. Covers old
246 // clients and hand-edited imports (importAForm funnels through here).
247 $this->pruneOrphanFields($fields, $nestedLayout, $layout, null, $post);
248 $form_content = [
249 'fields' => $fields,
250 'layout' => $layout,
251 'nestedLayout' => $nestedLayout,
252 'formInfo' => $formInfo,
253 ];
254
255 /* if (!empty($formSettings->submitBtn)) {
256 $form_content = array_merge($form_content, array('buttons' => $formSettings->submitBtn));
257 } */
258 if (!empty($formSettings->theme)) {
259 $form_content = array_merge($form_content, ['theme' => $formSettings->theme]);
260 }
261
262 if (!empty($formSettings->formPermissions)) {
263 $form_content = array_merge($form_content, ['formPermissions' => $formSettings->formPermissions]);
264 }
265
266 if (!empty($additional)) {
267 $form_content = array_merge($form_content, ['additional' => $additional]);
268 }
269 if (!empty($workFlows)) {
270 $workflows = is_string($workFlows) ? json_decode($workFlows) : $workFlows;
271 $workFlowExist = [];
272 foreach ($workflows as $index => $workFlow) {
273 if (in_array($workFlow->action_type, ['always', 'onload'])) {
274 $workFlowExist['onload'] = true;
275 }
276 if ('oninput' === $workFlow->action_type || ('always' === $workFlow->action_type && 'cond' === $workFlow->action_behaviour)) {
277 $workFlowExist['oninput'] = true;
278 }
279 }
280 $form_content = array_merge($form_content, ['workFlowExist' => $workFlowExist]);
281 }
282 $form_content = \wp_json_encode($form_content);
283
284 $builder_helper_state = (object) [
285 'style' => $style,
286 'staticStyles' => $staticStyles,
287 'breakpointSize' => $breakpointSize,
288 'themeVars' => $themeVars,
289 'themeColors' => $themeColors,
290 'builderSettings' => $builderSettings
291 ];
292 $atomic_class_map = \wp_json_encode($atomic_class_map);
293 $fdata = [
294 'id' => $post->form_id,
295 'form_content' => $form_content,
296 'builder_helper_state' => \wp_json_encode($builder_helper_state),
297 'atomic_class_map' => $atomic_class_map,
298 'generated_script_page_ids' => \wp_json_encode((object) []),
299 'user_id' => $user_details['id'],
300 'user_ip' => $user_details['ip'],
301 'user_device' => $user_details['device'],
302 'status' => 1,
303 'form_name' => $form_name,
304 'created_at' => $user_details['time'],
305 'updated_at' => $user_details['time'],
306 ];
307
308 $save_status = static::$formModel->insert($fdata);
309
310 if (is_wp_error($save_status)) {
311 return $save_status;
312 } elseif (!$save_status) {
313 return false;
314 } else {
315 FileHandler::createIndexFile(BITFORMS_UPLOAD_DIR . "/$save_status");
316 $formID = $save_status;
317 do_action('bitform_admin_form_changed');
318 $integartionIDForWorkflow = [];
319 // Confiramtion Message [start]
320 if (!empty($formSettings->confirmation->type->successMsg)) {
321 $successMessages = $formSettings->confirmation->type->successMsg;
322 $successMessageHandler = new SuccessMessageHandler($formID, $user_details);
323 foreach ($successMessages as $messageKey => $messageDetail) {
324 $savedID = $successMessageHandler->saveMessage($messageDetail);
325 if ($savedID) {
326 $msgIdx = empty($messageDetail->id) ? $messageKey : wp_json_encode(['id' => $messageDetail->id]);
327 $integartionIDForWorkflow['successMsg'][$msgIdx] = $savedID;
328 if (!empty($messageDetail->clRef)) {
329 $integartionIDForWorkflow['confirmationCLRef'][$messageDetail->clRef] = $savedID;
330 }
331 $messageDetail->id = $savedID;
332 $style = $this->updateSuccessMessageClassName($style, $messageKey, $savedID);
333 $atomic_class_map = $this->updateSuccessMessageClassName($atomic_class_map, $messageKey, $savedID);
334 }
335 }
336 $builder_helper_state = (object) [
337 'style' => $style,
338 'breakpointSize' => $breakpointSize,
339 'themeVars' => $themeVars,
340 'themeColors' => $themeColors,
341 'builderSettings' => $builderSettings
342 ];
343 $update_status = static::$formModel->update(
344 [
345 'builder_helper_state' => \wp_json_encode($builder_helper_state),
346 'atomic_class_map' => $atomic_class_map,
347 ],
348 [
349 'id' => $formID,
350 ]
351 );
352 if (is_wp_error($update_status)) {
353 return $update_status;
354 }
355 unset($formSettings->confirmation->type->successMsg);
356 }
357 // return $formSettings;
358 // Confiramtion Message [end] */
359 // Email Template [start]
360 if (!empty($mailTem)) {
361 $emailTemplateHandler
362 = new EmailTemplateHandler($formID, $user_details);
363 foreach ($mailTem as $templateKey => $templateDetail) {
364 $savedID = $emailTemplateHandler->saveTemplate($templateDetail);
365 if ($savedID && !is_wp_error($savedID)) {
366 $tempIdx = empty($templateDetail->id) ? $templateKey : wp_json_encode(['id' => $templateDetail->id]);
367 $integartionIDForWorkflow['mailNotify'][$tempIdx] = $savedID;
368 if (!empty($templateDetail->clRef)) {
369 $integartionIDForWorkflow['emailCLRef'][$templateDetail->clRef] = $savedID;
370 }
371 // return the new id (and drop the temp ref) so the frontend reconciles the template
372 $templateDetail->id = $savedID;
373 unset($templateDetail->clRef);
374 }
375 }
376 }
377 // Email Template [end] */
378
379 // PDF Template [start]
380 if (!empty($pdfTem) && class_exists('\BitCode\BitFormPro\Core\Messages\PdfTemplateHandler')) {
381 $pdfTemplateHandler = new \BitCode\BitFormPro\Core\Messages\PdfTemplateHandler($formID);
382 $workFlowString = '';
383 if (!empty($workFlows)) {
384 $workFlowString = wp_json_encode($workFlows);
385 }
386 foreach ($pdfTem as $templateDetail) {
387 $savedID = $pdfTemplateHandler->save($templateDetail);
388
389 $pdfSetting = $templateDetail->setting;
390
391 if (isset($pdfSetting->font->name) && !empty($pdfSetting->font->name)) {
392 $this->pdfFontDownload($pdfSetting->font->name);
393 }
394 if (!empty($workFlowString)) {
395 $workFlowString = str_replace('"pdfId":"{\"id\":\"' . $templateDetail->id . '\"}"', '"pdfId":"{\"id\":\"' . $savedID . '\"}"', $workFlowString);
396 // Multi-PDF: remap ids inside "pdfIds":[...] segments only — email-template ids use
397 // the same {\"id\":N} token shape, so a global replace would corrupt them.
398 $workFlowString = preg_replace_callback(
399 '/"pdfIds":\[[^\]]*\]/',
400 function ($matches) use ($templateDetail, $savedID) {
401 return str_replace('{\"id\":\"' . $templateDetail->id . '\"}', '{\"id\":\"' . $savedID . '\"}', $matches[0]);
402 },
403 $workFlowString
404 );
405 }
406 }
407 if (!empty($workFlowString) && !empty($workFlows)) {
408 $workFlows = json_decode($workFlowString);
409 }
410 }
411 // PDF Template [end] */
412 //Integration [start] */
413 $integrationHandler = new IntegrationHandler($formID, $user_details);
414 if (!empty($formSettings->confirmation->type)) {
415 $allIntegrations = $formSettings->confirmation->type;
416 foreach ($allIntegrations as $integrationType => $integrationGroup) {
417 foreach ($integrationGroup as $singleIntegrationKey => $singleIntegrationDetail) {
418 $integrationStatus = isset($singleIntegrationDetail->status) ? (int) $singleIntegrationDetail->status : 1;
419 // Inline-CL temp ref for a brand-new redirect (reconciled to the real id for workflow rows).
420 $clRef = isset($singleIntegrationDetail->clRef) ? $singleIntegrationDetail->clRef : null;
421 if (is_object($singleIntegrationDetail)) {
422 unset($singleIntegrationDetail->status, $singleIntegrationDetail->clRef);
423 }
424 if (empty($singleIntegrationDetail->details)) {
425 $integrationName = $singleIntegrationDetail->title;
426 unset($singleIntegrationDetail->title, $singleIntegrationDetail->id);
427
428 $integrationDetails = !is_string($singleIntegrationDetail) ?
429 wp_json_encode($singleIntegrationDetail) : $singleIntegrationDetail;
430 } else {
431 $integrationName = $singleIntegrationDetail->title;
432 $integrationDetails = !is_string($singleIntegrationDetail->details) ?
433 wp_json_encode($singleIntegrationDetail->details) : $singleIntegrationDetail->details;
434 }
435 $savedID = $integrationHandler->saveIntegration($integrationName, $integrationType, $integrationDetails, 'form', $integrationStatus);
436 $integIdx = empty($singleIntegrationDetail->id) ? $savedID : wp_json_encode(['id' => $singleIntegrationDetail->id]);
437 $integartionIDForWorkflow[$integrationType][$integIdx] = $savedID;
438 if (!empty($clRef) && 'redirectPage' === $integrationType) {
439 $integartionIDForWorkflow['redirectCLRef'][$clRef] = $savedID;
440 }
441 }
442 }
443 }
444 if (isset($formSettings->formAbandonment)) {
445 $formAbandonment = $formSettings->formAbandonment;
446
447 $integrationName = 'formAbandonment';
448 $integrationType = 'formAbandonment';
449 $abandonmentIntegDetails = wp_json_encode($formAbandonment);
450 $integrationHandler->saveIntegration($integrationName, $integrationType, $abandonmentIntegDetails, 'formAbandonment');
451 }
452 if (!empty($integrations)) {
453 foreach ($integrations as $singleIntegrationKey => $singleIntegrationDetail) {
454 $integrationName = $singleIntegrationDetail->name;
455 unset($singleIntegrationDetail->name);
456 $integrationType = $singleIntegrationDetail->type;
457 unset($singleIntegrationDetail->type);
458 $singleIntegrationDetailID = empty($singleIntegrationDetail->id) ? null : $singleIntegrationDetail->id;
459 unset($singleIntegrationDetail->id);
460 // Inline-CL temp ref for a brand-new integration (reconciled to the real id for workflow rows).
461 $clRef = isset($singleIntegrationDetail->__bf_cl_ref) ? $singleIntegrationDetail->__bf_cl_ref : null;
462 unset($singleIntegrationDetail->__bf_cl_ref);
463 if (empty($singleIntegrationDetail->details)) {
464 $integrationDetails = !is_string($singleIntegrationDetail) ?
465 wp_json_encode($singleIntegrationDetail) : $singleIntegrationDetail;
466 } else {
467 $integrationDetails = !is_string($singleIntegrationDetail->details) ?
468 wp_json_encode($singleIntegrationDetail->details) : $singleIntegrationDetail->details;
469 }
470 $savedID = $integrationHandler->saveIntegration($integrationName, $integrationType, $integrationDetails, 'form');
471 $integIdx = empty($singleIntegrationDetailID) ? $singleIntegrationKey : wp_json_encode(['id' => $singleIntegrationDetailID]);
472 $integartionIDForWorkflow['integ'][$integIdx] = $savedID;
473 if (!empty($clRef) && !is_wp_error($savedID)) {
474 $integartionIDForWorkflow['integrationCLRef'][$clRef] = $savedID;
475 }
476 }
477 }
478 //Integrations [end]
479 //wrokFlows [start]
480 if (!empty($workFlows)) {
481 $workFlowHandler = new WorkFlowHandler($formID, $user_details);
482
483 foreach ($workFlows as $index => $workFlow) {
484 $savedID = $workFlowHandler->saveworkFlow($workFlow, $integartionIDForWorkflow, $index);
485 $newData['workflow'] = 1;
486 }
487
488 // $workflowCount = count($workFlows);
489 // while ($workflowCount) {
490 // $workFlow = $workFlows[--$workflowCount];
491 // $savedID = $workFlowHandler->saveworkFlow($workFlow, $integartionIDForWorkflow);
492 // $newData['workflow'] = 1;
493 // }
494 }
495 //wrokFlows [end]
496 $details = [
497 'report_name' => __('All Entries', 'bit-form'),
498 'hiddenColumns' => ['__user_id', '__user_ip', '__referer', '__user_device', '__created_at', '__updated_at'],
499 'pageSize' => 10,
500 'sortBy' => [],
501 'filters' => [],
502 'globalFilter' => '',
503 'order' => []
504 ];
505 $defaultReport = [
506 'type' => 'table',
507 'category' => 'form',
508 'context' => $formID,
509 'details' => wp_json_encode($details),
510 'isDefault' => (bool) 1,
511 'user_id' => $user_details['id'],
512 'user_ip' => $user_details['ip'],
513 'user_device' => $user_details['device'],
514 'created_at' => $user_details['time'],
515 'updated_at' => $user_details['time'],
516 ];
517 $reportsModel = new ReportsModel();
518 $saveReportId = $reportsModel->insert($defaultReport);
519
520 // }
521 $updated_data = $this->getAForm(['id' => $save_status], null);
522 if (!is_wp_error($saveReportId) && isset($updated_data['form_content'])) {
523 $updated_data['form_content']['report_id'] = $saveReportId;
524 $updated_data['form_content']['is_default'] = 1;
525 }
526 $updated_data['message'] = __('Form Saved successfully', 'bit-form');
527
528 return $updated_data;
529 }
530 }
531
532 public function updateForm($Request, $post)
533 {
534 // return ['checked dta'=>$post];
535 $formId = $post->id;
536 // get the builder_helper_state from the form
537 $builder_helper_state = self::$formModel->get(['builder_helper_state'], ['id' => $formId]);
538 $builder_helper_state = (!is_wp_error($builder_helper_state) && 1 === count($builder_helper_state) && isset($builder_helper_state[0]->builder_helper_state)) ? $builder_helper_state[0]->builder_helper_state : '{}';
539 $builder_helper_state = json_decode($builder_helper_state);
540 if (property_exists($post, 'breakpointSize')) {
541 $builder_helper_state->breakpointSize = $post->breakpointSize;
542 }
543 if (property_exists($post, 'style')) {
544 $builder_helper_state->style = $post->style;
545 }
546 if (property_exists($post, 'staticStyles')) {
547 $builder_helper_state->staticStyles = $post->staticStyles;
548 }
549 if (property_exists($post, 'themeVars')) {
550 $builder_helper_state->themeVars = $post->themeVars;
551 }
552 if (property_exists($post, 'themeColors')) {
553 $builder_helper_state->themeColors = $post->themeColors;
554 }
555 if (property_exists($post, 'builderSettings')) {
556 $builder_helper_state->builderSettings = $post->builderSettings;
557 }
558 if (property_exists($post, 'atomicClassMap')) {
559 $atomic_class_map = \wp_json_encode((object) $post->atomicClassMap);
560 }
561
562 if (property_exists($post, 'fields') && null !== $post->fields && property_exists($post, 'layout') && $post->layout) {
563 $fields = wp_unslash($post->fields);
564 $fields = Helpers::replaceFieldsDefaultErrorMsg($fields);
565 $layout = wp_unslash($post->layout);
566 $nestedLayout = wp_unslash($post->nestedLayouts);
567 $formInfo = wp_unslash($post->formInfo);
568 $formID = wp_unslash($post->id);
569 $form_name = wp_unslash($post->form_name);
570 $formSettings = wp_unslash($post->formSettings);
571 $workFlows = wp_unslash($post->workFlows);
572 $additional = wp_unslash($post->additional);
573 $reports = wp_unslash($post->currentReport);
574 }
575
576 $mailTem = $formSettings->mailTem;
577 $pdfTem = isset($formSettings->pdfTem) ? $formSettings->pdfTem : [];
578 $integrations = $formSettings->integrations;
579
580 $user_details = static::$ipTool->getUserDetail();
581
582 if (empty($fields) || empty($layout) || is_null($formID)) {
583 return new WP_Error('empty_form', 'Can not update empty form.');
584 }
585
586 // Guard: never persist orphan fields (see createNewForm). Fail closed.
587 $this->pruneOrphanFields($fields, $nestedLayout, $layout, $formID, $post);
588
589 $form_content = [
590 'fields' => $fields,
591 'layout' => $layout,
592 'nestedLayout' => $nestedLayout,
593 'formInfo' => $formInfo,
594 ];
595
596 if (isset($post->report_id)) {
597 $form_content['report_id'] = wp_unslash($post->report_id);
598 }
599
600 /* if (!empty($formSettings->submitBtn)) {
601 $form_content = array_merge($form_content, array('buttons' => $formSettings->submitBtn));
602 } */
603 if (!empty($formSettings->theme)) {
604 $form_content = array_merge($form_content, ['theme' => $formSettings->theme]);
605 }
606
607 if (!empty($formSettings->formPermissions)) {
608 $form_content = array_merge($form_content, ['formPermissions' => $formSettings->formPermissions]);
609 }
610 if (!empty($additional)) {
611 $form_content = array_merge($form_content, ['additional' => $additional]);
612 }
613 $integartionIDForWorkflow = [];
614 $newData['settingConfiramation'] = 0;
615 $newData['integation'] = 0;
616 $newData['mailTemplate'] = 0;
617 $newData['workflow'] = 0;
618 $newData['reports'] = 0;
619 $newData['pdfTemplate'] = 0;
620 // Confiramtion Message [start]
621 if (!empty($formSettings->confirmation->type->successMsg)) {
622 $successMessages = $formSettings->confirmation->type->successMsg;
623 $successMessageHandler
624 = new SuccessMessageHandler($formID, $user_details);
625 foreach ($successMessages as $messageKey => $messageDetail) {
626 if (empty($messageDetail->id)) {
627 $savedID = $successMessageHandler->saveMessage($messageDetail);
628 if ($savedID) {
629 $newData['settingConfiramation'] = 1;
630 $integartionIDForWorkflow['successMsg'][$messageKey] = $savedID;
631 if (!empty($messageDetail->clRef)) {
632 $integartionIDForWorkflow['confirmationCLRef'][$messageDetail->clRef] = $savedID;
633 }
634 $messageDetail->id = $savedID;
635 $builder_helper_state->style = $this->updateSuccessMessageClassName($builder_helper_state->style, $messageKey, $savedID);
636 if (isset($atomic_class_map)) {
637 $atomic_class_map = $this->updateSuccessMessageClassName($atomic_class_map, $messageKey, $savedID);
638 }
639 }
640 } else {
641 $successMessageHandler->updateMessage($messageDetail);
642 }
643 }
644 unset($formSettings->confirmation->type->successMsg);
645 }
646 // return $formSettings;
647 // Confirmation Message [end] */
648 // Email Template [start]
649 if (!empty($mailTem)) {
650 $emailTemplateHandler
651 = new EmailTemplateHandler($formID, $user_details);
652 foreach ($mailTem as $templateKey => $templateDetail) {
653 if (empty($templateDetail->id)) {
654 $savedID = $emailTemplateHandler->saveTemplate($templateDetail);
655 if (is_wp_error($savedID) && 'result_empty' === $savedID->get_error_code()) {
656 $newData['mailTemplate'] = 2;
657 } else {
658 $newData['mailTemplate'] = 1;
659 $integartionIDForWorkflow['mailTem'][$templateKey] = $savedID;
660 if (!empty($templateDetail->clRef)) {
661 $integartionIDForWorkflow['emailCLRef'][$templateDetail->clRef] = $savedID;
662 }
663 // return the new id (and drop the temp ref) so the frontend reconciles the template
664 $templateDetail->id = $savedID;
665 unset($templateDetail->clRef);
666 }
667 } else {
668 $updated = $emailTemplateHandler->updateTemplate($templateDetail);
669 if (is_wp_error($updated) && 'db_error' === $updated->get_error_code()) {
670 $newData['mailTemplate'] = 2;
671 } elseif (0 === $newData['mailTemplate']) {
672 $newData['mailTemplate'] = 1;
673 }
674 }
675 }
676 }
677 // return $formSettings;
678 // Email Template [end] */
679 if (!empty($pdfTem) && class_exists('\BitCode\BitFormPro\Core\Messages\PdfTemplateHandler')) {
680 $pdfTemplateHandler = new \BitCode\BitFormPro\Core\Messages\PdfTemplateHandler($formID);
681
682 foreach ($pdfTem as $templateKey => $templateDetail) {
683 if (isset($templateDetail->setting->font->name)) {
684 $this->pdfFontDownload($templateDetail->setting->font->name);
685 }
686
687 $savedID = $pdfTemplateHandler->saveOrUpdate($templateDetail);
688 if (is_wp_error($savedID) && 'result_empty' === $savedID->get_error_code()) {
689 $newData['pdfTemplate'] = 2;
690 } else {
691 $newData['pdfTemplate'] = 1;
692 $integartionIDForWorkflow['pdfTem'][$templateKey] = $savedID;
693 }
694 }
695 }
696 //Integration [start] */
697 $integrationHandler = new IntegrationHandler($formID, $user_details);
698 if (!empty($formSettings->confirmation->type)) {
699 $allIntegrations = $formSettings->confirmation->type;
700 foreach ($allIntegrations as $integrationType => $integrationGroup) {
701 foreach ($integrationGroup as $singleIntegrationKey => $singleIntegrationDetail) {
702 // Redirect (and webhook) enable/disable toggle persists to the integration status column.
703 $integrationStatus = isset($singleIntegrationDetail->status) ? (int) $singleIntegrationDetail->status : 1;
704 // Inline-CL temp ref for a brand-new redirect (reconciled to the real id for workflow rows).
705 $clRef = isset($singleIntegrationDetail->clRef) ? $singleIntegrationDetail->clRef : null;
706 if (is_object($singleIntegrationDetail)) {
707 unset($singleIntegrationDetail->status, $singleIntegrationDetail->clRef);
708 }
709 if (empty($singleIntegrationDetail->details)) {
710 $integrationName = $singleIntegrationDetail->title;
711 unset($singleIntegrationDetail->title);
712 $singleIntegrationDetailID = empty($singleIntegrationDetail->id) ? null : $singleIntegrationDetail->id;
713 unset($singleIntegrationDetail->id);
714 $integrationDetails = !is_string($singleIntegrationDetail) ?
715 wp_json_encode($singleIntegrationDetail) : $singleIntegrationDetail;
716 } else {
717 $singleIntegrationDetailID = empty($singleIntegrationDetail->id) ? null : $singleIntegrationDetail->id;
718 unset($singleIntegrationDetail->id);
719 $integrationName = $singleIntegrationDetail->title;
720 $integrationDetails = !is_string($singleIntegrationDetail->details) ?
721 wp_json_encode($singleIntegrationDetail->details) : $singleIntegrationDetail->details;
722 }
723 if (empty($singleIntegrationDetailID)) {
724 $savedID = $integrationHandler->saveIntegration($integrationName, $integrationType, $integrationDetails, 'form', $integrationStatus);
725 $newData['settingConfiramation'] = 1;
726 $integartionIDForWorkflow[$integrationType][$singleIntegrationKey] = $savedID;
727 if (!empty($clRef) && 'redirectPage' === $integrationType) {
728 $integartionIDForWorkflow['redirectCLRef'][$clRef] = $savedID;
729 }
730 } else {
731 $integrationHandler->updateIntegration($singleIntegrationDetailID, $integrationName, $integrationType, $integrationDetails, 'form', $integrationStatus);
732 }
733 }
734 }
735 }
736 if (!empty($integrations)) {
737 foreach ($integrations as $singleIntegrationKey => $singleIntegrationDetail) {
738 $integrationName = $singleIntegrationDetail->name;
739 unset($singleIntegrationDetail->name);
740 $integrationType = $singleIntegrationDetail->type;
741 unset($singleIntegrationDetail->type);
742 $singleIntegrationDetailID = empty($singleIntegrationDetail->id) ? null : $singleIntegrationDetail->id;
743 unset($singleIntegrationDetail->id);
744 // Inline-CL temp ref for a brand-new integration (reconciled to the real id for workflow rows).
745 $clRef = isset($singleIntegrationDetail->__bf_cl_ref) ? $singleIntegrationDetail->__bf_cl_ref : null;
746 unset($singleIntegrationDetail->__bf_cl_ref);
747 if (empty($singleIntegrationDetail->details)) {
748 $integrationDetails = !is_string($singleIntegrationDetail) ?
749 wp_json_encode($singleIntegrationDetail) : $singleIntegrationDetail;
750 } else {
751 $integrationDetails = !is_string($singleIntegrationDetail->details) ?
752 wp_json_encode($singleIntegrationDetail->details) : $singleIntegrationDetail->details;
753 }
754 if (empty($singleIntegrationDetailID)) {
755 $savedID = $integrationHandler->saveIntegration($integrationName, $integrationType, $integrationDetails, 'form');
756 $integartionIDForWorkflow[$integrationType][$singleIntegrationKey] = $savedID;
757 if (!empty($clRef) && !is_wp_error($savedID)) {
758 $integartionIDForWorkflow['integrationCLRef'][$clRef] = $savedID;
759 }
760 if (is_wp_error($savedID) && 'result_empty' !== $savedID->get_error_code()) {
761 $newData['integation'] = 2;
762 } else {
763 $newData['integation'] = 1;
764 }
765 } else {
766 $integrationHandler->updateIntegration($singleIntegrationDetailID, $integrationName, $integrationType, $integrationDetails, 'form');
767 }
768 }
769 }
770 //Integrations [end]
771 //workFlows [start] */
772 $workFlowExist = [];
773 if (!empty($workFlows)) {
774 $workFlowHandler = new WorkFlowHandler($formID, $user_details);
775 // foreach ($workFlows as $workFlowIndex => $workFlow) {
776 $workflows = is_string($workFlows) ? json_decode($workFlows) : $workFlows;
777
778 foreach ($workflows as $index => $workFlow) {
779 if (in_array($workFlow->action_type, ['always', 'onload'])) {
780 $workFlowExist['onload'] = true;
781 }
782 if ('oninput' === $workFlow->action_type || ('always' === $workFlow->action_type && 'cond' === $workFlow->action_behaviour)) {
783 $workFlowExist['oninput'] = true;
784 }
785 // $integartionIDForWorkflow = apply_filters('bitform_filter_integration_id', $workFlow, $formID, $index);
786 if (empty($workFlow->id)) {
787 $savedID = $workFlowHandler->saveworkFlow($workFlow, $integartionIDForWorkflow, $index);
788 if (is_wp_error($savedID) && 'result_empty' !== $savedID->get_error_code()) {
789 $newData['workflow'] = 2;
790 } else {
791 $newData['workflow'] = 1;
792 }
793 } else {
794 $newData = $workFlowHandler->updateworkFlow($workFlow->id, $workFlow, $integartionIDForWorkflow, $index, $newData);
795 }
796 }
797 }
798 $form_content = array_merge($form_content, ['workFlowExist' => $workFlowExist]);
799 //wrokFlows [end]
800 //reports [start] */
801 if (!empty($reports)) {
802 $reportsModel = new ReportsModel();
803 $fieldNames = [];
804 foreach ($fields as $key => $field) {
805 if (!empty($field->lbl)) {
806 // $name = preg_replace('/[\`\~\!\@\#\$\'\.\s\?\+\-\*\&\|\/\\\!]/', '_', $field->lbl);
807 $fieldNames["$key"] = $field->lbl;
808 }
809 }
810
811 $fieldNames['__user_id'] = __('User', 'bit-form');
812 $fieldNames['__user_ip'] = __('IP address', 'bit-form');
813 // $fieldNames['__user_location'] = __('');
814 $fieldNames['__referer'] = __('Refer URL', 'bit-form');
815 $fieldNames['__user_device'] = __('Device', 'bit-form');
816 $fieldNames['__created_at'] = __('Created Time', 'bit-form');
817 $fieldNames['__updated_at'] = __('Modified Time', 'bit-form');
818
819 $reportIsDefault = null;
820 // The client posts currentReport as {} whenever its report atom has not resolved yet. That
821 // is an empty stdClass, which empty() above treats as non-empty, so we reach here with
822 // nothing to save — and writing the validated result would replace the stored report's
823 // column order, hidden columns, page size and name with an empty list. Leave the row alone.
824 if (isset($form_content['report_id']) && ReportsModel::isValidatableReport($reports)) {
825 $validDateReport = $reportsModel->validateReportFields($reports, $fieldNames);
826 if (isset($reports->isDefault)) {
827 $reportIsDefault = $reports->isDefault;
828 } else {
829 $reportIsDefault = 0;
830 }
831
832 $reportsModel->update(
833 [
834 'type' => 'table',
835 'category' => 'form',
836 'context' => $formID,
837 'details' => is_string($validDateReport) ? $validDateReport : wp_json_encode($validDateReport),
838 'isDefault' => (int) $reportIsDefault,
839 'user_id' => $user_details['id'],
840 'user_ip' => $user_details['ip'],
841 'user_device' => $user_details['device'],
842 'updated_at' => $user_details['time'],
843 ],
844 [
845 'id' => $form_content['report_id'],
846 ]
847 );
848 }
849 }
850 //reports [end]
851 //form abandonment [start]
852 if (!empty($formSettings->formAbandonment)) {
853 $formAbandonment = $formSettings->formAbandonment;
854 // search for existing form abandonment in integration table
855 $abandonmentInteg = $integrationHandler->getAllIntegration('formAbandonment', 'formAbandonment');
856 if (!is_wp_error($abandonmentInteg) && !empty($abandonmentInteg)) {
857 $abandonmentInteg = $abandonmentInteg[0];
858 }
859 if (isset($abandonmentInteg->id)) {
860 $abandonmentIntegID = $abandonmentInteg->id;
861 $abandonmentIntegDetails = wp_json_encode($formAbandonment);
862 $integrationHandler->updateIntegration($abandonmentIntegID, 'formAbandonment', 'formAbandonment', $abandonmentIntegDetails, 'formAbandonment');
863 } else {
864 $abandonmentIntegDetails = wp_json_encode($formAbandonment);
865 $integrationHandler->saveIntegration('formAbandonment', 'formAbandonment', $abandonmentIntegDetails, 'formAbandonment');
866 }
867 }
868 //form abandonment [end]
869 $form_content = wp_json_encode($form_content);
870 $updateData = [
871 'form_name' => $form_name,
872 'form_content' => $form_content,
873 'user_id' => $user_details['id'],
874 'user_ip' => $user_details['ip'],
875 'builder_helper_state' => \wp_json_encode((object) $builder_helper_state),
876 'generated_script_page_ids' => \wp_json_encode((object) []),
877 'user_device' => $user_details['device'],
878 'updated_at' => $user_details['time'],
879 ];
880 if (isset($atomic_class_map)) {
881 $updateData['atomic_class_map'] = $atomic_class_map;
882 }
883 $formUpdateVersion = get_option('bitform_form_update_version');
884 if (!$formUpdateVersion) {
885 $formUpdateVersion = 1;
886 } else {
887 $formUpdateVersion = (int) $formUpdateVersion + 1;
888 }
889 update_option('bitform_form_update_version', $formUpdateVersion);
890 do_action('bitform_admin_form_changed');
891
892 $update_status = static::$formModel->update(
893 $updateData,
894 [
895 'id' => $formID,
896 ]
897 );
898 if (is_wp_error($update_status)) {
899 return $update_status;
900 } elseif (!$update_status) {
901 return new WP_Error('empty_form', __('Form update failed.', 'bit-form'));
902 } else {
903 if (isset($post->deletedFldKey) && is_array($post->deletedFldKey)) {
904 $this->setEmptyMetaValue($post->deletedFldKey);
905 unset($post->deletedFldKey);
906 }
907
908 $updated_data = $this->getAForm(['id' => $formID], null);
909
910 if (0 === $newData['settingConfiramation'] && 0 === $newData['mailTemplate'] && 0 === $newData['integation'] && 0 === $newData['pdfTemplate']) {
911 unset($updated_data['formSettings']);
912 }
913 if (0 === $newData['integation']) {
914 unset($updated_data['integrations']);
915 } elseif (2 === $newData['integation']) {
916 $errorIN = '';
917 $errorIN .= empty($errorIN) ? 'integation' : ', integation';
918 }
919 if (0 === $newData['mailTemplate']) {
920 unset($updated_data['mailTem']);
921 } elseif (2 === $newData['mailTemplate']) {
922 $errorIN .= empty($errorIN) ? 'mailTemplate' : ', mailTemplate';
923 }
924 if (0 === $newData['pdfTemplate']) {
925 unset($updated_data['pdfTem']);
926 } elseif (2 === $newData['pdfTemplate']) {
927 $errorIN .= empty($errorIN) ? 'pdfTemplate' : ', pdfTemplate';
928 }
929 if (0 === $newData['workflow']) {
930 unset($updated_data['workFlows']);
931 } elseif (2 === $newData['workflow']) {
932 $errorIN .= empty($errorIN) ? 'workflow' : ', workflow';
933 }
934 if (2 === $newData['reports']) {
935 $errorIN .= empty($errorIN) ? 'reports' : ', reports';
936 }
937 if (!empty($errorIN)) {
938 /* translators: %s: comma-separated list of areas where error occurred */
939 $updated_data['message'] = sprintf(__('Error Occured in saving %s', 'bit-form'), $errorIN);
940 return new WP_Error('Form update Error.', $updated_data);
941 }
942 if (null !== $reportIsDefault) {
943 $updated_data['form_content']['is_default'] = $reportIsDefault;
944 }
945 $updated_data['message'] = __('Form updated successfully.', 'bit-form');
946 return $updated_data;
947 }
948 }
949
950 /**
951 * Drop orphan fields (present in `fields` but in no layout) from form_content
952 * before persisting, and remove now-childless nestedLayout entries.
953 *
954 * Entry meta is NEVER touched here — only explicit user deletes clear meta
955 * (see setEmptyMetaValue). Fail closed: an unusable/partial layout, or a
956 * client that flagged a failed pre-save layout sync (->skipOrphanPrune),
957 * prunes nothing. Pruned keys are logged, never silently dropped.
958 *
959 * @param object|array $fields by ref; orphan keys removed
960 * @param object|null $nestedLayout by ref; stale container entries removed
961 * @param array|object $layout raw layout (single or multi-step)
962 * @param int|string|null $formID for logging ('new' when absent)
963 * @param object $post raw request; honors ->skipOrphanPrune
964 */
965 private function pruneOrphanFields(&$fields, &$nestedLayout, $layout, $formID, $post)
966 {
967 $formLabel = $formID ? $formID : 'new';
968 if (isset($post->skipOrphanPrune) && $post->skipOrphanPrune) {
969 Log::debug_log('Bit Form: orphan prune skipped (client reported failed layout sync). FormID=' . $formLabel);
970 return;
971 }
972 $orphanFldKeys = FormManager::computeOrphanFieldKeys($layout, $nestedLayout, $fields);
973 // null = unusable/partial layout (fail closed); [] = nothing to prune
974 if (!is_array($orphanFldKeys) || empty($orphanFldKeys)) {
975 return;
976 }
977 Log::debug_log('Bit Form: pruning orphan fields (absent from every layout). FormID=' . $formLabel . ' keys=' . implode(',', $orphanFldKeys));
978 foreach ($orphanFldKeys as $orphanKey) {
979 if (is_object($fields)) {
980 unset($fields->{$orphanKey});
981 } elseif (is_array($fields)) {
982 unset($fields[$orphanKey]);
983 }
984 }
985 // prune stale nestedLayout entries — containers that no longer exist in fields
986 if (is_object($nestedLayout)) {
987 foreach (array_keys(get_object_vars($nestedLayout)) as $nKey) {
988 $parentExists = is_object($fields) ? isset($fields->{$nKey}) : isset($fields[$nKey]);
989 if (!$parentExists) {
990 unset($nestedLayout->{$nKey});
991 }
992 }
993 }
994 }
995
996 public function setEmptyMetaValue($fieldkeys)
997 {
998 global $wpdb;
999 // Placeholders and arguments built dynamically from $fieldkeys; count matches at runtime.
1000 $placeholders = implode(',', array_fill(0, \count($fieldkeys), '%s'));
1001 $wpdb->query($wpdb->prepare(
1002 "UPDATE `{$wpdb->prefix}bitforms_form_entrymeta` SET meta_value = %s WHERE meta_key IN ($placeholders)",
1003 '',
1004 ...$fieldkeys
1005 ));
1006 }
1007
1008 public function changeFormStatus($Request, $post)
1009 {
1010 if (isset($Request['status']) && $Request['id']) {
1011 $status = sanitize_text_field(wp_unslash($Request['status']));
1012 $id = absint(wp_unslash($Request['id']));
1013 } else {
1014 $status = wp_unslash($post->status);
1015 $id = wp_unslash($post->id);
1016 }
1017 $user_details = static::$ipTool->getUserDetail();
1018 // return $post->fields;
1019 $status = 'true' === $status || true === $status ? true : false;
1020 if (!is_bool($status) || is_null($id)) {
1021 // echo $status;
1022 return new WP_Error('status_change', __('Form status change failed.', 'bit-form'));
1023 }
1024 $update_status = static::$formModel->update(
1025 [
1026 'user_id' => $user_details['id'],
1027 'user_ip' => $user_details['ip'],
1028 'user_device' => $user_details['device'],
1029 'status' => $status ? 1 : 0,
1030 'updated_at' => $user_details['time'],
1031 ],
1032 [
1033 'id' => $id,
1034 ]
1035 );
1036 if (is_wp_error($update_status)) {
1037 return $update_status;
1038 } elseif (!$update_status) {
1039 return false;
1040 } else {
1041 return __('Form status changed successfully', 'bit-form');
1042 }
1043 }
1044
1045 public function changeBulkFormStatus($Request, $post)
1046 {
1047 if (isset($Request['status']) && $Request['formID']) {
1048 $status = sanitize_text_field(wp_unslash($Request['status']));
1049 $formID = array_map('absint', wp_unslash($Request['formID']));
1050 } else {
1051 $status = wp_unslash($post->status);
1052 $formID = wp_unslash($post->formID);
1053 }
1054 $user_details = static::$ipTool->getUserDetail();
1055 // return $post->fields;
1056 $status = 'true' === $status || true === $status ? true : false;
1057 if (!is_bool($status) || is_null($formID) || !is_array($formID)) {
1058 // echo $status;
1059 return new WP_Error('status_change', __('Form status change failed.', 'bit-form'));
1060 }
1061 $update_status = static::$formModel->bulkUpdate(
1062 [
1063 'user_id' => $user_details['id'],
1064 'user_ip' => $user_details['ip'],
1065 'user_device' => $user_details['device'],
1066 'status' => $status ? 1 : 0,
1067 'updated_at' => $user_details['time'],
1068 ],
1069 [
1070 'id' => $formID,
1071 ]
1072 );
1073 if (is_wp_error($update_status)) {
1074 return $update_status;
1075 } elseif (!$update_status) {
1076 return false;
1077 } else {
1078 return __('Form status changed successfully', 'bit-form');
1079 }
1080 }
1081
1082 public function getAllForm()
1083 {
1084 global $wpdb;
1085
1086 // Direct query: table name interpolation only (no user input). $wpdb->prepare() cannot parameterize table names.
1087 $allForms = $wpdb->get_results("SELECT forms.id,forms.entries as fm_entries,forms.form_name,forms.status,forms.views,forms.created_at,COUNT(entries.id) as entries
1088 FROM `{$wpdb->prefix}bitforms_form` as forms
1089 LEFT JOIN `{$wpdb->prefix}bitforms_form_entries` as entries ON forms.id = entries.form_id
1090 GROUP BY forms.id");
1091
1092 if (is_wp_error($allForms)) {
1093 return $allForms;
1094 } elseif (!$allForms) {
1095 return [];
1096 } else {
1097 return $allForms;
1098 }
1099 }
1100
1101 public function getAForm($Request, $post)
1102 {
1103 if (!empty($Request['id'])) {
1104 $formID = absint(wp_unslash($Request['id']));
1105 } else {
1106 $formID = wp_unslash($post->id);
1107 }
1108 // return $post->fields;
1109 if (is_null($formID)) {
1110 return new WP_Error('empty_form', __('Form id is empty.', 'bit-form'));
1111 }
1112 $formManager = new AdminFormManager($formID);
1113 if (!$formManager->isExist()) {
1114 return new WP_Error('not_exists', __('Form is not exists.', 'bit-form'));
1115 }
1116 $form_content = $formManager->getFormContent();
1117 $helper_states = $formManager->getFormHelperStates();
1118 if ($formManager->isExist()) {
1119 $form_content_arr = [
1120 'layout' => $form_content->layout,
1121 'nestedLayout' => !empty($form_content->nestedLayout) ? $form_content->nestedLayout : (object) [],
1122 'formInfo' => !empty($form_content->formInfo) ? $form_content->formInfo : (object) ['formName' => $formManager->getFormName()],
1123 'fields' => $form_content->fields,
1124 'form_name' => $formManager->getFormName(),
1125 'workFlowExist' => isset($form_content->workFlowExist) ? $form_content->workFlowExist : [],
1126 'report_id' => isset($form_content->report_id) ? $form_content->report_id : null
1127 ];
1128 $successMessageHandler
1129 = new SuccessMessageHandler($formID);
1130 $successMessages = $successMessageHandler->getAllMessage();
1131 if (!is_wp_error($successMessages)) {
1132 foreach ($successMessages as $sucessMessagekey => $sucessMessagevalue) {
1133 $sucessMessagevalue->message_config = json_decode($sucessMessagevalue->message_config);
1134 $allConfirmation['type']['successMsg'][$sucessMessagekey] =
1135 [
1136 'id' => $sucessMessagevalue->id,
1137 'title' => $sucessMessagevalue->message_title,
1138 'msg' => $sucessMessagevalue->message_content,
1139 'config' => $sucessMessagevalue->message_config,
1140 ];
1141 }
1142 }
1143 $emailTemplateHandler
1144 = new EmailTemplateHandler($formID);
1145 $emailTemplates = $emailTemplateHandler->getAllTemplate();
1146 if (!is_wp_error($emailTemplates)) {
1147 foreach ($emailTemplates as $emailTemplatekey => $emailTemplatevalue) {
1148 $mailTem[] =
1149 [
1150 'id' => $emailTemplatevalue->id,
1151 'title' => $emailTemplatevalue->title,
1152 'sub' => $emailTemplatevalue->sub,
1153 'body' => $emailTemplatevalue->body,
1154 'status' => isset($emailTemplatevalue->status) ? (int) $emailTemplatevalue->status : 1,
1155 'config' => !empty($emailTemplatevalue->config) ? json_decode($emailTemplatevalue->config) : (object) [],
1156 ];
1157 }
1158 }
1159 // get all pdf template
1160 if (class_exists('\BitCode\BitFormPro\Core\Messages\PdfTemplateHandler')) {
1161 $pdfTemplateHandler = new \BitCode\BitFormPro\Core\Messages\PdfTemplateHandler($formID);
1162 $pdfTemplates = $pdfTemplateHandler->getAll();
1163
1164 if (!is_wp_error($pdfTemplates)) {
1165 foreach ($pdfTemplates as $value) {
1166 $pdfTem[] =
1167 [
1168 'id' => $value->id,
1169 'title' => $value->title,
1170 'setting' => json_decode($value->setting),
1171 'pdf_config' => !empty($value->pdf_config) ? json_decode($value->pdf_config) : (object) [
1172 'status' => 1,
1173 'header' => '',
1174 'footer' => '',
1175 ],
1176 'body' => $value->body,
1177 ];
1178 }
1179 }
1180 }
1181
1182 $integrationHandler = new IntegrationHandler($formID);
1183 $formIntegrations = $integrationHandler->getAllIntegration('form');
1184 if (!is_wp_error($formIntegrations)) {
1185 foreach ($formIntegrations as $integrationkey => $integrationValue) {
1186 if ('redirectPage' === $integrationValue->integration_type || 'webHooks' === $integrationValue->integration_type) {
1187 $integrationData = [
1188 'id' => $integrationValue->id,
1189 'title' => $integrationValue->integration_name,
1190 'status' => isset($integrationValue->status) ? (int) $integrationValue->status : 1,
1191 ];
1192 if (!empty($integrationValue->integration_details)) {
1193 $integration_details = (array) json_decode($integrationValue->integration_details);
1194 $integrationData = array_merge($integration_details, $integrationData);
1195 } else {
1196 $integration_details = [
1197 'url' => '',
1198 ];
1199 $integrationData = array_merge($integrationData, $integration_details);
1200 }
1201 $allConfirmation['type'][$integrationValue->integration_type][]
1202 = $integrationData;
1203 } else {
1204 $integrationData = [
1205 'id' => $integrationValue->id,
1206 'name' => $integrationValue->integration_name,
1207 'type' => $integrationValue->integration_type,
1208 ];
1209 $integrations[] = array_merge(
1210 $integrationData,
1211 is_string($integrationValue->integration_details) ?
1212 (array) json_decode($integrationValue->integration_details) :
1213 $integrationValue->integration_details
1214 );
1215 }
1216 }
1217 }
1218
1219 // get form abandonment integration if exist
1220 $formAbandonmentInteg = $integrationHandler->getAllIntegration('formAbandonment', 'formAbandonment');
1221 if (!is_wp_error($formAbandonmentInteg) && !empty($formAbandonmentInteg)) {
1222 $formAbandonmentInteg = $formAbandonmentInteg[0];
1223 if (!empty($formAbandonmentInteg->integration_details)) {
1224 $formAbandonment = json_decode($formAbandonmentInteg->integration_details);
1225 } else {
1226 $formAbandonment = (object) [];
1227 }
1228 } else {
1229 $formAbandonment = (object) [];
1230 }
1231
1232 $settingsContent = [
1233 'formName' => $formManager->getFormName(),
1234 'theme' => isset($form_content->theme) ? $form_content->theme : 'default',
1235 'formPermissions' => isset($form_content->formPermissions) ? $form_content->formPermissions : (object) [],
1236 // 'submitBtn' => $form_content->buttons,
1237 ];
1238
1239 if (!empty($allConfirmation)) {
1240 $confirmation = [
1241 'confirmation' => $allConfirmation,
1242 ];
1243 } else {
1244 $confirmation = [
1245 'confirmation' => ['type' => []],
1246 ];
1247 }
1248 $settingsContent = array_merge($settingsContent, $confirmation);
1249 if (!empty($integrations)) {
1250 $settingsContent = array_merge(
1251 $settingsContent,
1252 [
1253 'integrations' => $integrations,
1254 ]
1255 );
1256 } else {
1257 $settingsContent = array_merge(
1258 $settingsContent,
1259 [
1260 'integrations' => []
1261 ]
1262 );
1263 }
1264
1265 if (!empty($mailTem)) {
1266 $settingsContent = array_merge(
1267 $settingsContent,
1268 [
1269 'mailTem' => $mailTem,
1270 ]
1271 );
1272 } else {
1273 $settingsContent = array_merge(
1274 $settingsContent,
1275 [
1276 'mailTem' => []
1277 ]
1278 );
1279 }
1280
1281 if (!empty($pdfTem)) {
1282 $settingsContent = array_merge(
1283 $settingsContent,
1284 [
1285 'pdfTem' => $pdfTem,
1286 ]
1287 );
1288 } else {
1289 $settingsContent = array_merge(
1290 $settingsContent,
1291 [
1292 'pdfTem' => [],
1293 ]
1294 );
1295 }
1296
1297 if (!empty($formAbandonment)) {
1298 $settingsContent = array_merge(
1299 $settingsContent,
1300 [
1301 'formAbandonment' => $formAbandonment,
1302 ]
1303 );
1304 } else {
1305 $settingsContent = array_merge(
1306 $settingsContent,
1307 [
1308 'formAbandonment' => (object) [],
1309 ]
1310 );
1311 }
1312 $formSettings = [
1313 'formSettings' => $settingsContent,
1314 ];
1315 $data = [
1316 'id' => $formID,
1317 'form_name' => $formManager->getFormName(),
1318 'form_content' => $form_content_arr,
1319 'breakpointSize' => $helper_states->breakpointSize,
1320 'style' => $helper_states->style,
1321 'themeVars' => $helper_states->themeVars,
1322 'themeColors' => $helper_states->themeColors,
1323 'builderSettings' => $helper_states->builderSettings,
1324 'customCode' => FrontEndScriptGenerator::getCustomCodes($formID),
1325 'additional' => empty($form_content->additional) ? [
1326 'enabled' => [
1327 'blocked_ip' => false,
1328 'restrict_form' => false,
1329 'onePerIp' => false,
1330 ],
1331 'settings' => [
1332 'restrict_form' => [
1333 'day' => [],
1334 'date' => [
1335 'from' => null,
1336 'to' => null,
1337 ],
1338 'time' => [
1339 'from' => null,
1340 'to' => null,
1341 ],
1342 ],
1343 'entry_limit' => null,
1344 'blocked_ip' => [],
1345 ],
1346 ] : $form_content->additional,
1347 'created_at' => $formManager->getFormMetaData()['created_at'],
1348 'views' => $formManager->getFormMetaData()['views'],
1349 'entries' => $formManager->getFormMetaData()['entries'],
1350 'status' => $formManager->getFormMetaData()['status'],
1351 ];
1352 $data = array_merge($data, $formSettings);
1353 $workFlowHandler = new WorkFlowHandler($formID);
1354 $workFlows = ['workFlows' => $workFlowHandler->getAllworkFlow()];
1355 $data = array_merge($data, $workFlows);
1356 $reportsModel = new ReportsModel();
1357 $returnedReportData = $reportsModel->get(
1358 [
1359 'id',
1360 'details',
1361 'isDefault',
1362 'type',
1363 ],
1364 [
1365 'category' => 'form',
1366 'context' => $formID,
1367 ]
1368 );
1369
1370 if (!is_wp_error($returnedReportData)) {
1371 $fieldNames = [];
1372 foreach ($formManager->getFieldLabel() as $key => $field) {
1373 $fieldNames[$field['key']] = isset($field->lbl) ? $field->lbl : '';
1374 }
1375 if ($formManager->isGCLIDEnabled()) {
1376 $fieldNames['GCLID'] = 'GCLID';
1377 }
1378 foreach ($returnedReportData as $reportKey => $reportData) {
1379 $reportDetails = $reportsModel->validateReportFields($reportData, $fieldNames);
1380 if (!empty($reportDetails) && is_string($reportDetails)) {
1381 $returnedReportData[$reportKey]->details = json_decode($reportDetails);
1382 } elseif (!empty($reportDetails)) {
1383 $returnedReportData[$reportKey]->details = $reportDetails;
1384 } else {
1385 $returnedReportData[$reportKey]->details = [];
1386 }
1387 if ('1' === (string) $reportData->isDefault) {
1388 $returnedReportData[$reportKey]->details->report_name = __('All Entries', 'bit-form');
1389 }
1390 }
1391 $reports = ['reports' => $returnedReportData];
1392 $data = array_merge($data, $reports);
1393 }
1394
1395 $formFields = $formManager->getFieldLabel();
1396 $data = array_merge($data, ['Labels' => $formFields]);
1397
1398 return $data;
1399 }
1400 }
1401
1402 public function getAFormV1($Request, $post)
1403 {
1404 if (!empty($Request['id'])) {
1405 $formID = absint(wp_unslash($Request['id']));
1406 } else {
1407 $formID = wp_unslash($post->id);
1408 }
1409 // return $post->fields;
1410 if (is_null($formID)) {
1411 return new WP_Error('empty_form', __('Form id is empty.', 'bit-form'));
1412 }
1413 $formManager = new AdminFormManager($formID);
1414 if (!$formManager->isExist()) {
1415 return new WP_Error('not_exists', __('Form is not exists.', 'bit-form'));
1416 }
1417 $form_content = $formManager->getFormContent();
1418 if ($formManager->isExist()) {
1419 $form_content_arr = [
1420 'layout' => $form_content->layout,
1421 'fields' => $form_content->fields,
1422 'form_name' => $formManager->getFormName(),
1423 'workFlowExist' => isset($form_content->workFlowExist) ? $form_content->workFlowExist : [],
1424 'report_id' => isset($form_content->report_id) ? $form_content->report_id : null
1425 ];
1426 $successMessageHandler
1427 = new SuccessMessageHandler($formID);
1428 $successMessages = $successMessageHandler->getAllMessage();
1429 if (!is_wp_error($successMessages)) {
1430 foreach ($successMessages as $sucessMessagekey => $sucessMessagevalue) {
1431 $allConfirmation['type']['successMsg'][$sucessMessagekey] =
1432 [
1433 'id' => $sucessMessagevalue->id,
1434 'title' => $sucessMessagevalue->message_title,
1435 'msg' => $sucessMessagevalue->message_content,
1436 'config' => !empty($sucessMessagevalue->message_config) ? json_decode($sucessMessagevalue->message_config) : (object) [],
1437 ];
1438 }
1439 }
1440 $emailTemplateHandler
1441 = new EmailTemplateHandler($formID);
1442 $emailTemplates = $emailTemplateHandler->getAllTemplate();
1443 if (!is_wp_error($emailTemplates)) {
1444 foreach ($emailTemplates as $emailTemplatekey => $emailTemplatevalue) {
1445 $mailTem[] =
1446 [
1447 'id' => $emailTemplatevalue->id,
1448 'title' => $emailTemplatevalue->title,
1449 'sub' => $emailTemplatevalue->sub,
1450 'body' => $emailTemplatevalue->body,
1451 'status' => isset($emailTemplatevalue->status) ? (int) $emailTemplatevalue->status : 1,
1452 'config' => !empty($emailTemplatevalue->config) ? json_decode($emailTemplatevalue->config) : (object) [],
1453 ];
1454 }
1455 }
1456 $integrationHandler = new IntegrationHandler($formID);
1457 $formIntegrations = $integrationHandler->getAllIntegration('form');
1458 if (!is_wp_error($formIntegrations)) {
1459 foreach ($formIntegrations as $integrationkey => $integrationValue) {
1460 if ('redirectPage' === $integrationValue->integration_type || 'webHooks' === $integrationValue->integration_type) {
1461 $integrationData = [
1462 'id' => $integrationValue->id,
1463 'title' => $integrationValue->integration_name,
1464 'status' => isset($integrationValue->status) ? (int) $integrationValue->status : 1,
1465 ];
1466 if (!empty($integrationValue->integration_details)) {
1467 // var_dump(json_decode($integrationValue->integration_details));
1468 $integration_details = (array) json_decode($integrationValue->integration_details);
1469 $integrationData = array_merge($integration_details, $integrationData);
1470 } else {
1471 $integration_details = [
1472 'url' => '',
1473 ];
1474 $integrationData = array_merge($integrationData, $integration_details);
1475 }
1476 $allConfirmation['type'][$integrationValue->integration_type][]
1477 = $integrationData;
1478 } else {
1479 $integrationData = [
1480 'id' => $integrationValue->id,
1481 'name' => $integrationValue->integration_name,
1482 'type' => $integrationValue->integration_type,
1483 ];
1484 $integrations[] = array_merge(
1485 $integrationData,
1486 is_string($integrationValue->integration_details) ?
1487 (array) json_decode($integrationValue->integration_details) :
1488 $integrationValue->integration_details
1489 );
1490 }
1491 }
1492 }
1493 $settingsContent = [
1494 'formName' => $formManager->getFormName(),
1495 'theme' => $form_content->theme,
1496 // 'submitBtn' => $form_content->buttons,
1497 ];
1498
1499 if (!empty($allConfirmation)) {
1500 $confirmation = [
1501 'confirmation' => $allConfirmation,
1502 ];
1503 } else {
1504 $confirmation = [
1505 'confirmation' => ['type' => []],
1506 ];
1507 }
1508 $settingsContent = array_merge($settingsContent, $confirmation);
1509 if (!empty($integrations)) {
1510 $settingsContent = array_merge(
1511 $settingsContent,
1512 [
1513 'integrations' => $integrations,
1514 ]
1515 );
1516 } else {
1517 $settingsContent = array_merge(
1518 $settingsContent,
1519 [
1520 'integrations' => []
1521 ]
1522 );
1523 }
1524 if (!empty($mailTem)) {
1525 $settingsContent = array_merge(
1526 $settingsContent,
1527 [
1528 'mailTem' => $mailTem,
1529 ]
1530 );
1531 } else {
1532 $settingsContent = array_merge(
1533 $settingsContent,
1534 [
1535 'mailTem' => []
1536 ]
1537 );
1538 }
1539 $formSettings = [
1540 'formSettings' => $settingsContent,
1541 ];
1542 $data = [
1543 'id' => $formID,
1544 'form_name' => $formManager->getFormName(),
1545 'form_content' => $form_content_arr,
1546 'additional' => empty($form_content->additional) ? [
1547 'enabled' => [
1548 'blocked_ip' => false,
1549 'restrict_form' => false,
1550 'onePerIp' => false,
1551 ],
1552 'settings' => [
1553 'restrict_form' => [
1554 'day' => [],
1555 'date' => [
1556 'from' => null,
1557 'to' => null,
1558 ],
1559 'time' => [
1560 'from' => null,
1561 'to' => null,
1562 ],
1563 ],
1564 'entry_limit' => null,
1565 'blocked_ip' => [],
1566 ],
1567 ] : $form_content->additional,
1568 'created_at' => $formManager->getFormMetaData()['created_at'],
1569 'views' => $formManager->getFormMetaData()['views'],
1570 'entries' => $formManager->getFormMetaData()['entries'],
1571 'status' => $formManager->getFormMetaData()['status'],
1572 ];
1573 $data = array_merge($data, $formSettings);
1574 $workFlowHandler = new WorkFlowHandler($formID);
1575 $workFlows = ['workFlows' => $workFlowHandler->getAllworkFlowV1()];
1576 $data = array_merge($data, $workFlows);
1577 $reportsModel = new ReportsModel();
1578 $returnedReportData = $reportsModel->get(
1579 [
1580 'id',
1581 'details',
1582 'isDefault',
1583 'type',
1584 ],
1585 [
1586 'category' => 'form',
1587 'context' => $formID,
1588 ]
1589 );
1590
1591 if (!is_wp_error($returnedReportData)) {
1592 $fieldNames = [];
1593 foreach ($formManager->getFieldLabel() as $key => $field) {
1594 $fieldNames[$field['key']] = isset($field->lbl) ? $field->lbl : '';
1595 }
1596 if ($formManager->isGCLIDEnabled()) {
1597 $fieldNames['GCLID'] = 'GCLID';
1598 }
1599 foreach ($returnedReportData as $reportKey => $reportData) {
1600 $reportDetails = $reportsModel->validateReportFields($reportData, $fieldNames);
1601 if (!empty($reportDetails) && is_string($reportDetails)) {
1602 $returnedReportData[$reportKey]->details = json_decode($reportDetails);
1603 } elseif (!empty($reportDetails)) {
1604 $returnedReportData[$reportKey]->details = $reportDetails;
1605 } else {
1606 $returnedReportData[$reportKey]->details = [];
1607 }
1608 if ('1' === (string) $reportData->isDefault) {
1609 $returnedReportData[$reportKey]->details->report_name = __('All Entries', 'bit-form');
1610 }
1611 }
1612 $reports = ['reports' => $returnedReportData];
1613 $data = array_merge($data, $reports);
1614 }
1615
1616 $formFields = $formManager->getFieldLabel();
1617 $data = array_merge($data, ['Labels' => $formFields]);
1618
1619 return $data;
1620 }
1621 }
1622
1623 public function deleteAForm($Request, $post)
1624 {
1625 if (!empty($Request['id'])) {
1626 $formID = absint(wp_unslash($Request['id']));
1627 } else {
1628 $formID = wp_unslash($post->id);
1629 }
1630 if (is_null($formID)) {
1631 return new WP_Error('empty_form', __('Form id is empty.', 'bit-form'));
1632 }
1633
1634 if (!filter_var($formID, FILTER_VALIDATE_INT)) {
1635 return new WP_Error('invalid_form', __('Form id is invalid.', 'bit-form'));
1636 }
1637
1638 $delete_status = static::$formModel->delete(
1639 [
1640 'id' => $formID,
1641 ]
1642 );
1643 do_action('bitform_admin_form_changed');
1644
1645 $successMessageModel = new SuccessMessageModel();
1646 $deleteMsgStatus = $successMessageModel->delete(['form_id' => $formID]);
1647
1648 $emailTemplateModel = new EmailTemplateModel();
1649 $deleteTemplateStatus = $emailTemplateModel->delete(['form_id' => $formID]);
1650
1651 if (class_exists('\BitCode\BitFormPro\Core\Database\PdfTemplateModel')) {
1652 $pdfTemplateModel = new \BitCode\BitFormPro\Core\Database\PdfTemplateModel();
1653 $deletePdfTemplateStatus = $pdfTemplateModel->delete(['form_id' => $formID]);
1654 }
1655
1656 $integrationModel = new IntegrationModel();
1657 $deleteIntegrationStatus = $integrationModel->delete(['form_id' => $formID]);
1658
1659 $workFlowModel = new WorkFlowModel();
1660 $deleteworkFlowStatus = $workFlowModel->delete(['form_id' => $formID]);
1661
1662 $reportsModel = new ReportsModel();
1663 $deleteReportStatus = $reportsModel->delete(['context' => $formID]);
1664
1665 $formEntryModel = new FormEntryModel();
1666 $returnedEntries = $formEntryModel->get('id', ['form_id' => $formID]);
1667 $entries = [];
1668
1669 // checked namespace exist
1670 if (class_exists('\BitCode\BitFormPro\Admin\BfTable\Table')) {
1671 \BitCode\BitFormPro\Admin\BfTable\Table::deleteTableByFormId($formID);
1672 }
1673
1674 $fileHandler = new FileHandler();
1675 if (file_exists(BITFORMS_UPLOAD_DIR . DIRECTORY_SEPARATOR . $formID)) {
1676 $fileHandler->rmrf(BITFORMS_UPLOAD_DIR . DIRECTORY_SEPARATOR . $formID);
1677 }
1678 if (file_exists(BITFORMS_UPLOAD_DIR . DIRECTORY_SEPARATOR . $formID)) {
1679 $fileHandler->rmrf(BITFORMS_UPLOAD_DIR . DIRECTORY_SEPARATOR . $formID);
1680 }
1681 $formStylePath = BITFORMS_CONTENT_DIR . DIRECTORY_SEPARATOR . 'form-styles';
1682
1683 $formCssPath = $formStylePath . DIRECTORY_SEPARATOR . 'bitform-' . $formID . '.css';
1684 FileHandler::deleteIsFileExists($formCssPath);
1685
1686 $layoutCssPath = $formStylePath . DIRECTORY_SEPARATOR . 'bitform-layout-' . $formID . '.css';
1687 FileHandler::deleteIsFileExists($layoutCssPath);
1688
1689 $customCssPath = $formStylePath . DIRECTORY_SEPARATOR . 'bitform-custom-' . $formID . '.css';
1690 FileHandler::deleteIsFileExists($customCssPath);
1691
1692 $customJSPath = BITFORMS_CONTENT_DIR . DIRECTORY_SEPARATOR . 'form-scripts' . DIRECTORY_SEPARATOR . 'bitform-custom-' . $formID . '.js';
1693 FileHandler::deleteIsFileExists($customJSPath);
1694
1695 $conversationCssPath = $formStylePath . DIRECTORY_SEPARATOR . 'bitform-conversational-' . $formID . '.css';
1696 FileHandler::deleteIsFileExists($conversationCssPath);
1697
1698 return is_wp_error($delete_status) ? $delete_status : __('Form deleted successfully.', 'bit-form');
1699 }
1700
1701 public function deleteBlukForm($Request, $post)
1702 {
1703 if (!empty($Request['formID'])) {
1704 $formID = array_map('absint', wp_unslash($Request['formID']));
1705 } else {
1706 $formID = wp_unslash($post->formID);
1707 }
1708
1709 if (is_null($formID) || !is_array($formID)) {
1710 return new WP_Error('empty_form', __('Form id is empty.', 'bit-form'));
1711 }
1712
1713 if (!Helpers::checkIsIntArr($formID)) {
1714 return new WP_Error('invalid_form', __('Form id is invalid', 'bit-form'));
1715 }
1716
1717 $cssPath = BITFORMS_CONTENT_DIR . DIRECTORY_SEPARATOR . 'form-styles' . DIRECTORY_SEPARATOR;
1718 foreach ($formID as $id) {
1719 $formCssPath = $cssPath . 'bitform-' . $id . '.css';
1720 FileHandler::deleteIsFileExists($formCssPath);
1721
1722 $layoutPath = $cssPath . 'bitform-layout-' . $id . '.css';
1723 FileHandler::deleteIsFileExists($layoutPath);
1724
1725 $bitformCustomPath = $cssPath . 'bitform-' . $id . '-formid' . '.css';
1726 FileHandler::deleteIsFileExists($bitformCustomPath);
1727 }
1728 $delete_status = static::$formModel->bulkDelete(
1729 [
1730 'id' => $formID,
1731 ]
1732 );
1733 do_action('bitform_admin_form_changed');
1734
1735 if (is_wp_error($delete_status)) {
1736 wp_send_json_error($delete_status->get_error_message(), 400);
1737 }
1738
1739 $successMessageModel
1740 = new SuccessMessageModel();
1741 $deleteMsgStatus = $successMessageModel->bulkDelete(['form_id' => $formID]);
1742
1743 $emailTemplateModel = new EmailTemplateModel();
1744 $deleteTemplateStatus = $emailTemplateModel->bulkDelete(['form_id' => $formID]);
1745
1746 if (class_exists('\BitCode\BitFormPro\Core\Database\PdfTemplateModel')) {
1747 $pdfTemplateModel = new \BitCode\BitFormPro\Core\Database\PdfTemplateModel();
1748 $deletePdfTemplateStatus = $pdfTemplateModel->bulkDelete(['form_id' => $formID]);
1749 }
1750
1751 $integrationModel = new IntegrationModel();
1752 $deleteIntegrationStatus = $integrationModel->bulkDelete(['form_id' => $formID]);
1753
1754 $workFlowModel = new WorkFlowModel();
1755 $deleteworkFlowStatus = $workFlowModel->bulkDelete(['form_id' => $formID]);
1756
1757 $reportsModel = new ReportsModel();
1758 $deleteReportStatus = $reportsModel->bulkDelete(['context' => $formID]);
1759
1760 $formEntryModel = new FormEntryModel();
1761 $returnedEntries = $formEntryModel->get('id', ['form_id' => $formID]);
1762
1763 if (class_exists('\BitCode\BitFormPro\Admin\BfTable\Table')) {
1764 \BitCode\BitFormPro\Admin\BfTable\Table::deleteTableByBulkFormId($formID);
1765 }
1766
1767 $entries = [];
1768 foreach ($returnedEntries as $entryKey => $entryInfo) {
1769 if (!empty($entryInfo->id)) {
1770 $entries[] = $entryInfo->id;
1771 }
1772 }
1773 global $wpdb;
1774 $prefix = $wpdb->prefix;
1775 if (count($entries) > 0) {
1776 $deleteEntriesStatus = $formEntryModel->bulkDelete(
1777 [
1778 "`{$prefix}bitforms_form_entries`.`id`" => $entries,
1779 "`{$prefix}bitforms_form_entries`.`form_id`" => $formID,
1780 ]
1781 );
1782 }
1783
1784 // delete entry log and details; table name interpolation only — $wpdb->prepare() parameterizes the form_id value.
1785 $wpdb->query($wpdb->prepare(
1786 "DELETE em, e FROM `{$prefix}bitforms_form_log_details` AS em JOIN `{$prefix}bitforms_form_entry_log` AS e ON em.log_id = e.id WHERE e.form_id = %d",
1787 $formID
1788 ));
1789
1790 $fileHandler = new FileHandler();
1791 foreach ($formID as $fId) {
1792 if (file_exists(BITFORMS_UPLOAD_DIR . DIRECTORY_SEPARATOR . $fId)) {
1793 $fileHandler->rmrf(BITFORMS_UPLOAD_DIR . DIRECTORY_SEPARATOR . $fId);
1794 }
1795 }
1796
1797 return is_wp_error($delete_status) ? $delete_status : __('Forms deleted successfully.', 'bit-form');
1798 }
1799
1800 public function genarateNewLayoutNField($layout, $fields, $oldId, $newId)
1801 {
1802 $newField = (object) [];
1803 foreach ($layout->lg as $ind => $itm) {
1804 $fld_tmp = $fields->{$layout->lg[$ind]->i};
1805 $layout->lg[$ind]->i = str_replace("bf$oldId-", "bf$newId-", $layout->lg[$ind]->i);
1806 $layout->md[$ind]->i = str_replace("bf$oldId-", "bf$newId-", $layout->md[$ind]->i);
1807 $layout->sm[$ind]->i = str_replace("bf$oldId-", "bf$newId-", $layout->sm[$ind]->i);
1808 $newField->{$layout->lg[$ind]->i} = $fld_tmp;
1809 }
1810 return ['layout' => $layout, 'fields' => $newField];
1811 }
1812
1813 public function duplicateAForm($Request, $post)
1814 {
1815 $oldFormId = intval($post->id);
1816 $newFormId = intval($post->newFormId);
1817 if ($oldFormId < 1) {
1818 return new WP_Error('empty_form', __('Form id is empty.', 'bit-form'));
1819 }
1820
1821 $formManager = new AdminFormManager($oldFormId);
1822 if (!$formManager->isExist()) {
1823 return new WP_Error('empty_form', __('Form does not exists.', 'bit-form'));
1824 }
1825
1826 $duplicatedForm = $this->getAForm($Request, $post);
1827 $duplicatedForm['form_name'] = 'Duplicate of ' . $duplicatedForm['form_name'];
1828 $formData = FormDuplicateHelper::createReplica($duplicatedForm, $oldFormId, $newFormId);
1829
1830 /* echo wp_json_encode($formData);
1831 \wp_die(); */
1832 $duplicateResponse = $this->createNewForm(null, $formData);
1833
1834 if (!is_wp_error($duplicateResponse) || (is_wp_error($duplicateResponse) && 'result_empty' === $duplicateResponse->get_error_code())) {
1835 // duplicate stylesheet
1836 $style_dir = BITFORMS_CONTENT_DIR . DIRECTORY_SEPARATOR . 'form-styles' . DIRECTORY_SEPARATOR;
1837 // layout style copy
1838 $styleStr = FileHandler::readFile($style_dir . 'bitform-layout-' . $oldFormId . '.css');
1839 $newStyle = str_replace(".bf$oldFormId-", ".bf$newFormId-", $styleStr);
1840 FileHandler::writeFile($style_dir . "bitform-layout-$newFormId.css", $newStyle);
1841 // style copy
1842 $styleStr = FileHandler::readFile($style_dir . 'bitform-' . $oldFormId . '.css');
1843 $newStyle = str_replace("-$oldFormId", "-$newFormId", $styleStr);
1844 FileHandler::writeFile($style_dir . "bitform-$newFormId.css", $newStyle);
1845 $duplicatedForm = $this->getAForm(null, (object) ['id' => $newFormId]);
1846 $duplicatedForm['message'] = __('Form duplicated successfully', 'bit-form');
1847 return $duplicatedForm;
1848 }
1849 return $duplicateResponse;
1850 }
1851
1852 public function importAForm($post)
1853 {
1854 $oldFormId = !empty($post->formDetail->form_id) ? $post->formDetail->form_id : null;
1855 $newFormId = intval($post->newFormId);
1856 if (!$oldFormId || empty($post->formDetail->fields) || empty($post->formDetail->layout)) {
1857 return new WP_Error('invalid_form', __('Please import a valid json.', 'bit-form'));
1858 }
1859 $importtedForm = (array) $post->formDetail;
1860 $importtedForm['form_content']['fields'] = $importtedForm['fields'];
1861 $importtedForm['form_content']['layout'] = $importtedForm['layout'];
1862 $importtedForm['form_content']['nestedLayout'] = $importtedForm['nestedLayouts'];
1863 $importtedForm['form_content']['formInfo'] = $importtedForm['formInfo'];
1864 unset($importtedForm['fields'], $importtedForm['layout'], $importtedForm['nestedLayout'], $importtedForm['formInfo']);
1865 $formData = FormDuplicateHelper::createReplica((array) $importtedForm, $oldFormId, $newFormId);
1866
1867 if (!empty($importtedForm['rowHeight'])) {
1868 $formData->rowHeight = $importtedForm['rowHeight'];
1869 }
1870
1871 if (!empty($importtedForm['formStyle'])) {
1872 $formData->formStyle = str_replace("-$oldFormId", "-$newFormId", $importtedForm['formStyle']);
1873 $formData->layoutChanged = '-';
1874 }
1875 $importResponse = $this->createNewForm(null, $formData);
1876
1877 $customCode = [];
1878 // add custom js
1879 if (!empty($formData->customCode->customJs)) {
1880 $customJsPath = 'form-scripts';
1881 $fileName = 'bitform-custom-' . $newFormId . '.js';
1882 $customCode['JavaScript'] = $formData->customCode->customJs;
1883 Helpers::saveFile($customJsPath, $fileName, $formData->customCode->customJs, 'w');
1884 }
1885 // add custom css
1886 if (!empty($formData->customCode->customCss)) {
1887 $customCssPath = 'form-styles';
1888 $fileName = 'bitform-custom-' . $newFormId . '.css';
1889 $customCode['CSS'] = $formData->customCode->customCss;
1890 Helpers::saveFile($customCssPath, $fileName, $formData->customCode->customCss, 'w');
1891 }
1892 if (!is_wp_error($importResponse)) {
1893 $importResponse['customCode'] = $customCode;
1894 }
1895 if (!is_wp_error($importResponse) || (is_wp_error($importResponse) && 'result_empty' === $importResponse->get_error_code())) {
1896 $responseData = $this->getAForm(null, (object) ['id' => $newFormId]);
1897 $responseData['customCode'] = $customCode;
1898 $responseData['message'] = __('Form imported successfully.', 'bit-form');
1899 return $responseData;
1900 }
1901 return $importResponse;
1902 }
1903
1904 // public function exportAForm($Request) {
1905 // $oldFormId = intval($Request['id']);
1906 // if ($oldFormId < 1) {
1907 // return new WP_Error('empty_form', __('Form id is empty.', 'bit-form'));
1908 // }
1909 // $formManager = new AdminFormManager($oldFormId);
1910 // if (!$formManager->isExist()) {
1911 // return new WP_Error('empty_form', __('Form does not exists.', 'bit-form'));
1912 // }
1913
1914 // $newFormId = $oldFormId;
1915 // $duplicatedForm = $this->getAForm($Request, (object)['id' => $oldFormId]);
1916 // $formData = FormDuplicateHelper::createReplica($duplicatedForm, $oldFormId, $newFormId);
1917
1918 // $style_dir = BITFORMS_CONTENT_DIR . DIRECTORY_SEPARATOR . 'form-styles' . DIRECTORY_SEPARATOR;
1919 // $mainFormStyle = fopen($style_dir . 'bitform-' . $oldFormId . '.css', 'r');
1920 // $styleStr = fread($mainFormStyle, filesize($style_dir . 'bitform-' . $oldFormId . '.css'));
1921
1922 // $formData->formStyle = str_replace("-$oldFormId", "-$newFormId", $styleStr);
1923 // $formData->layoutChanged = '-';
1924 // $formData->rowHeight = FormDuplicateHelper::calcRowHeight($styleStr, $oldFormId);
1925
1926 // $formJson = wp_json_encode($formData);
1927 // header('Content-Type: application/force-download');
1928 // header('Content-Type: application/octet-stream');
1929 // header('Content-Type: application/download');
1930 // header('Content-Disposition: attachment; filename="bitform_export_' . $oldFormId . '.json"');
1931 // header('Content-Description: File Transfer');
1932 // header('Expires: 0');
1933 // header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
1934 // header('Pragma: public');
1935 // header('Content-Length: ' . strlen($formJson));
1936 // header('Content-Transfer-Encoding: binary ');
1937 // flush();
1938 // echo $formJson;
1939 // die();
1940 // }
1941
1942 public function exportAForm($Request, $post)
1943 {
1944 $oldFormId = intval($post->id);
1945 if ($oldFormId < 1) {
1946 return new WP_Error('empty_form', __('Form id is empty.', 'bit-form'));
1947 }
1948 $formManager = new AdminFormManager($oldFormId);
1949 if (!$formManager->isExist()) {
1950 return new WP_Error('empty_form', __('Form does not exists.', 'bit-form'));
1951 }
1952
1953 $newFormId = $oldFormId;
1954 $duplicatedForm = $this->getAForm($Request, (object) ['id' => $oldFormId]);
1955 $formData = FormDuplicateHelper::createReplica($duplicatedForm, $oldFormId, $newFormId);
1956 // for custom css
1957 $customCssPath = 'form-styles/bitform-custom-' . $newFormId . '.css';
1958 $cssPath = Helpers::generatePathDirOrFile($customCssPath);
1959 $customCssContain = Helpers::fileRead($cssPath);
1960 $formData->customCode = [];
1961 if ('' !== $customCssContain) {
1962 $formData->customCode['customCss'] = $customCssContain;
1963 }
1964 // for custom js
1965 $customJsPath = 'form-scripts/bitform-custom-' . $newFormId . '.js';
1966 $jsPath = Helpers::generatePathDirOrFile($customJsPath);
1967 $customJsContain = Helpers::fileRead($jsPath);
1968 if ('' !== $customJsContain) {
1969 $formData->customCode['customJs'] = $customJsContain;
1970 }
1971 return $formData;
1972 }
1973
1974 public function getFormEntryLabelAndCount($Request, $post)
1975 {
1976 if (!empty($Request['id'])) {
1977 $id = absint(wp_unslash($Request['id']));
1978 } else {
1979 $id = wp_unslash($post->id);
1980 }
1981 if (is_null($id)) {
1982 return new WP_Error('empty_form', __('Form id is empty.', 'bit-form'));
1983 }
1984 $formManager = new AdminFormManager($id);
1985 if (!$formManager->isExist()) {
1986 return new WP_Error('empty_form', __('Form does not exists.', 'bit-form'));
1987 }
1988 $formFields = $formManager->getFieldLabel();
1989 $formEntry = new FormEntryModel();
1990 $count = $formEntry->count(
1991 [
1992 'form_id' => $id,
1993 ]
1994 );
1995 $reportsModel = new ReportsModel();
1996 $returnedReportData = $reportsModel->get(
1997 [
1998 'id',
1999 'details',
2000 'isDefault',
2001 'type',
2002 ],
2003 [
2004 'category' => 'form',
2005 'context' => $id,
2006 ]
2007 );
2008 $labels = [];
2009 if (!is_wp_error($returnedReportData)) {
2010 $fieldNames = [];
2011 foreach ($formFields as $field) {
2012 $fieldNames[$field['key']] = $field['name'];
2013 $labels[$field['key']] = $field;
2014 }
2015 foreach ($returnedReportData as $reportKey => $reportData) {
2016 $reportDetails = $reportsModel->validateReportFields($reportData, $fieldNames);
2017 if (!empty($reportDetails) && is_string($reportDetails)) {
2018 $returnedReportData[$reportKey]->details = json_decode($reportDetails);
2019 } elseif (!empty($reportDetails)) {
2020 $returnedReportData[$reportKey]->details = $reportDetails;
2021 }
2022 }
2023 $response['reports'] = empty($returnedReportData) ? [] : $returnedReportData;
2024 }
2025
2026 $response['count'] = intval($count[0]->count);
2027 $response['Labels'] = $formFields;
2028 $response['fieldDetails'] = $labels;
2029 return $response;
2030 }
2031
2032 /**
2033 * Sanitize a request-supplied entry query condition before it reaches the Model
2034 * layer. Only known entry-table columns are allowed as condition keys, operators
2035 * are restricted to a safe allow-list ['form_id' => $id] when nothing valid remains.
2036 *
2037 * @param mixed $queryCondition
2038 * @param int $id
2039 * @return array
2040 */
2041 private function sanitizeEntryQueryCondition($queryCondition, $id)
2042 {
2043 $allowedColumns = [
2044 'id', 'form_id', 'status', 'created_at', 'updated_at',
2045 'user_id', 'user_ip', 'user_device', 'user_location', 'referer',
2046 ];
2047 $allowedOperators = ['=', '!=', '<>', '<', '>', '<=', '>=', 'LIKE', 'IN'];
2048
2049 if (!is_array($queryCondition)) {
2050 return ['form_id' => $id];
2051 }
2052
2053 $safe = [];
2054 foreach ($queryCondition as $key => $value) {
2055 if (!in_array($key, $allowedColumns, true)) {
2056 continue;
2057 }
2058
2059 if (is_array($value)) {
2060 // Never honour a request-supplied raw SQL fragment.
2061 unset($value['raw']);
2062
2063 if (array_key_exists('operator', $value) || array_key_exists('value', $value)) {
2064 $operator = isset($value['operator']) && is_string($value['operator'])
2065 ? strtoupper(trim($value['operator']))
2066 : '=';
2067 if (!in_array($operator, $allowedOperators, true)) {
2068 $operator = '=';
2069 }
2070 $condValue = isset($value['value']) ? $value['value'] : '';
2071 if (is_scalar($condValue)) {
2072 $safe[$key] = ['operator' => $operator, 'value' => $condValue];
2073 }
2074 } else {
2075 // IN-style list: keep scalar members only (bound by the Model).
2076 $list = array_values(array_filter($value, 'is_scalar'));
2077 if (!empty($list)) {
2078 $safe[$key] = $list;
2079 }
2080 }
2081 } elseif (is_scalar($value)) {
2082 $safe[$key] = $value;
2083 }
2084 }
2085
2086 return empty($safe) ? ['form_id' => $id] : $safe;
2087 }
2088
2089 public function getFormEntry($Request, $post)
2090 {
2091 if (!empty($Request['id'])) {
2092 $id = absint(wp_unslash($Request['id']));
2093 $offset = isset($Request['offset']) ?
2094 wp_unslash($Request['offset']) : 0;
2095 $pageSize = isset($Request['pageSize']) ?
2096 wp_unslash($Request['pageSize']) : 10;
2097 $queryCondition = isset($Request['queryCondition']) ? wp_unslash($Request['queryCondition']) : ['form_id' => $id];
2098 } else {
2099 $id = wp_unslash($post->id);
2100 $conditions = isset($post->conditions) ? wp_unslash($post->conditions) : [];
2101 $dateBetweenFilter = isset($post->entriesFilterByDate) ? wp_unslash($post->entriesFilterByDate) : [];
2102 $offset = isset($post->offset) ? wp_unslash($post->offset) : 0;
2103 $sortBy = isset($post->sortBy) ? wp_unslash($post->sortBy) : null;
2104 $filters = isset($post->filters) ? wp_unslash($post->filters) : null;
2105 $globalFilter = isset($post->globalFilter) ? wp_unslash($post->globalFilter) : null;
2106 $pageSize = isset($post->pageSize) ?
2107 wp_unslash($post->pageSize) : 10;
2108 $queryCondition = isset($post->queryCondition) ? wp_unslash($post->queryCondition) : ['form_id' => $id];
2109 }
2110 $queryCondition = $this->sanitizeEntryQueryCondition($queryCondition, $id);
2111 if (is_null($id)) {
2112 return new WP_Error('empty_form', __('Form id is empty.', 'bit-form'));
2113 }
2114 $formManager = new AdminFormManager($id);
2115 if (!$formManager->isExist()) {
2116 return new WP_Error('empty_form', __('Form does not exists', 'bit-form'));
2117 }
2118 $formEntry = new FormEntryModel();
2119 $entries = $formEntry->get(
2120 'id',
2121 $queryCondition,
2122 null,
2123 null,
2124 'created_at',
2125 'DESC'
2126 );
2127 if (is_wp_error($entries)) {
2128 if ('result_empty' === $entries->get_error_code()) {
2129 return [
2130 'count' => 0,
2131 'entries' => [],
2132 ];
2133 }
2134 return $entries;
2135 }
2136 $filter['field'] = $filters;
2137 $filter['global'] = $globalFilter;
2138
2139 $formFields = $formManager->getFieldLabel(true);
2140 $fieldDetails = $formManager->getFields();
2141
2142 $entryMeta = new FormEntryMetaModel();
2143 $formEntries = $entryMeta->getEntryMeta($formFields, $entries, $pageSize, $offset, $filter, $sortBy, $conditions, $dateBetweenFilter);
2144 $customFieldHandler = new CustomFieldHandler();
2145 $formEntries = $customFieldHandler->updatedEntries($formEntries, $fieldDetails);
2146 return $formEntries;
2147 }
2148
2149 public function getSingleEntry($formId, $entryId)
2150 {
2151 $formManager = new AdminFormManager($formId);
2152 if (!$formManager->isExist()) {
2153 return new WP_Error('empty_form', __('Form does not exists', 'bit-form'));
2154 }
2155
2156 $formFields = $formManager->getFieldLabel(true);
2157 $fieldDetails = $formManager->getFields();
2158 $entryMeta = new FormEntryMetaModel();
2159 // $formEntry = new FormEntryModel();
2160
2161 $entries = $entryMeta->getSingleEntryMeta($formFields, $entryId);
2162
2163 if (!is_wp_error($entries)) {
2164 return $entries[0];
2165 }
2166 return new WP_Error('entry_not_fonud', __('Entry Not Found!', 'bit-form'));
2167
2168 // $customFieldHandler = new CustomFieldHandler();
2169 // $formEntries = $customFieldHandler->updatedEntries($formEntries, $fieldDetails);
2170 // return $formEntries;
2171 }
2172
2173 public function getEntriesForReport($Request, $post)
2174 {
2175 if (!empty($Request['id'])) {
2176 $id = absint(wp_unslash($Request['id']));
2177 $offset = isset($Request['offset']) ?
2178 wp_unslash($Request['offset']) : null;
2179 $pageSize = isset($Request['pageSize']) ?
2180 wp_unslash($Request['pageSize']) : null;
2181 } else {
2182 $id = wp_unslash($post->id);
2183 $conditions = isset($post->conditions) ? wp_unslash($post->conditions) : [];
2184 $dateBetweenFilter = isset($post->entriesFilterByDate) ? wp_unslash($post->entriesFilterByDate) : [];
2185 $offset = isset($post->offset) ? wp_unslash($post->offset) : null;
2186 $sortBy = isset($post->sortBy) ? wp_unslash($post->sortBy) : null;
2187 $filters = isset($post->filters) ? wp_unslash($post->filters) : null;
2188 $globalFilter = isset($post->globalFilter) ? wp_unslash($post->globalFilter) : null;
2189 $pageSize = isset($post->pageSize) ?
2190 wp_unslash($post->pageSize) : null;
2191 }
2192 if (is_null($id)) {
2193 return new WP_Error('empty_form', __('Form id is empty.', 'bit-form'));
2194 }
2195 $formManager = new AdminFormManager($id);
2196 if (!$formManager->isExist()) {
2197 return new WP_Error('empty_form', __('Form does not exists', 'bit-form'));
2198 }
2199
2200 $formEntry = new FormEntryModel();
2201 $entries = $formEntry->get(
2202 'id',
2203 [
2204 'form_id' => $id,
2205 ],
2206 null,
2207 null,
2208 'created_at',
2209 'DESC'
2210 );
2211 if (is_wp_error($entries)) {
2212 if ('result_empty' === $entries->get_error_code()) {
2213 return [
2214 'count' => 0,
2215 'entries' => [],
2216 ];
2217 }
2218 return $entries;
2219 }
2220 $filter['field'] = $filters;
2221 $filter['global'] = $globalFilter;
2222
2223 $formFields = $formManager->getFieldLabel(true);
2224 $fieldDetails = $formManager->getFields();
2225
2226 $entryMeta = new FormEntryMetaModel();
2227 $formEntries = $entryMeta->getEntryMeta($formFields, $entries, $pageSize, $offset, $filter, $sortBy, $conditions, $dateBetweenFilter);
2228 $customFieldHandler = new CustomFieldHandler();
2229 $formEntries = $customFieldHandler->updatedEntries($formEntries, $fieldDetails);
2230 $formEntries['entries'] = Helpers::filterNullEntries($formEntries['entries']);
2231 return $formEntries;
2232 }
2233
2234 public function getExportEntry($post)
2235 {
2236 $formId = wp_unslash($post->formId);
2237 $fileFormate = isset($post->fileFormate) ? wp_unslash($post->fileFormate) : null;
2238 $limit = isset($post->limit) ? wp_unslash($post->limit) : null;
2239 $entryCondition = isset($post->filter) ? wp_unslash($post->filter) : null;
2240 $sortBy = isset($post->sort) ? wp_unslash($post->sort) : 'ASC';
2241 $sortByField = isset($post->sortField) ? wp_unslash($post->sortField) : 'bitforms_form_entry_id';
2242 $formFields = json_decode($post->selectedField);
2243 if (is_null($formId)) {
2244 return new WP_Error('empty_form', __('Form id is empty.', 'bit-form'));
2245 }
2246 $formManager = new AdminFormManager($formId);
2247 $fieldLabels = $formManager->getFieldLabel(true);
2248 if (!$formManager->isExist()) {
2249 return new WP_Error('empty_form', __('Form does not exists', 'bit-form'));
2250 }
2251
2252 $formEntry = new FormEntryModel();
2253 $entries = $formEntry->get(
2254 'id',
2255 [
2256 'form_id' => $formId,
2257 ],
2258 null,
2259 null,
2260 'created_at',
2261 'DESC'
2262 );
2263 if (is_wp_error($entries)) {
2264 if ('result_empty' === $entries->get_error_code()) {
2265 return [
2266 'count' => 0,
2267 'entries' => [],
2268 ];
2269 }
2270 return $entries;
2271 }
2272 $entryMeta = new FormEntryMetaModel();
2273 $filter = [];
2274 $formEntries = $entryMeta->getExportEntry($formFields, $entries, $formId, $fieldLabels, $limit, $sortBy, $sortByField, $offset, $entryCondition);
2275 return $formEntries;
2276 }
2277
2278 public function deleteBlukFormEntries($Request, $post)
2279 {
2280 if (!empty($Request['formID'])) {
2281 $formID = absint(wp_unslash($Request['formID']));
2282 $entries = array_map('absint', wp_unslash($Request['entries']));
2283 } else {
2284 $formID = wp_unslash($post->formID);
2285 $entries = wp_unslash($post->entries);
2286 }
2287 if (is_null($formID) || !is_array($entries) || 0 === count($entries)) {
2288 return new WP_Error('empty_form', __('Invalid Form ID or Entries ID.', 'bit-form'));
2289 }
2290
2291 if (!filter_var($formID, FILTER_VALIDATE_INT)) {
2292 return new WP_Error('invalid_form', __('Form id is invalid.', 'bit-form'));
2293 }
2294
2295 if (!Helpers::checkIsIntArr($entries)) {
2296 return new WP_Error('invalid_entries', __('Entries id is invalid', 'bit-form'));
2297 }
2298
2299 $formManager = new AdminFormManager($formID);
2300 if (!$formManager->isExist()) {
2301 return new WP_Error('empty_form', __('Form does not exist.', 'bit-form'));
2302 }
2303 $workFlowRunHelper = new WorkFlow($formID);
2304
2305 $workFlowreturnedOnDelete = $workFlowRunHelper->executeOnDelete(
2306 $formManager,
2307 $formID,
2308 $entries
2309 );
2310
2311 if (isset($workFlowreturnedOnDelete['entries'])) {
2312 if (0 === count($workFlowreturnedOnDelete['entries'])) {
2313 return ['message' => __('Entry Deletetion prevented by workflow', 'bit-form')];
2314 } elseif (count($workFlowreturnedOnDelete['entries']) === count($entries)) {
2315 $message = __('Entry Deleted successfully', 'bit-form');
2316 } else {
2317 $result['prevented'] = array_diff($entries, $workFlowreturnedOnDelete['entries']);
2318 $entries = $workFlowreturnedOnDelete['entries'];
2319 $message = __('Entry Deleted successfully, Some prevented by workflow', 'bit-form');
2320 }
2321 } else {
2322 $message = __('Entry Deleted successfully', 'bit-form');
2323 }
2324 global $wpdb;
2325 $prefix = $wpdb->prefix;
2326 $formEntryModel = new FormEntryModel();
2327 $delete_status = $formEntryModel->bulkDelete(
2328 [
2329 "`{$prefix}bitforms_form_entries`.`id`" => $entries,
2330 "`{$prefix}bitforms_form_entries`.`form_id`" => $formID,
2331 ]
2332 );
2333 if (file_exists(BITFORMS_UPLOAD_DIR . DIRECTORY_SEPARATOR . $formID)) {
2334 $fileHandler = new FileHandler();
2335 foreach ($entries as $enrtyKey => $entryID) {
2336 $fileEntries = $fileHandler->getEntriesFileUploadDir($formID, $entryID);
2337 if (file_exists($fileEntries)) {
2338 $fileHandler->rmrf($fileEntries);
2339 }
2340 }
2341 }
2342 $count = $formEntryModel->count(
2343 [
2344 'form_id' => $formID,
2345 ]
2346 );
2347 $formManager->resetSubmissionCount(intval($count[0]->count));
2348 if (is_wp_error($delete_status)) {
2349 return new WP_Error('entry_not_exists', __('Form entry deletion failed.', 'bit-form'));
2350 }
2351 $result['message'] = $message;
2352 return $result;
2353 }
2354
2355 public function duplicateFormEntry($Request, $post)
2356 {
2357 if (!empty($Request['formID'])) {
2358 $formID = absint(wp_unslash($Request['formID']));
2359 $entries = array_map('absint', wp_unslash($Request['entries']));
2360 } else {
2361 $formID = wp_unslash($post->formID);
2362 $entries = wp_unslash($post->entries);
2363 }
2364 if (is_null($formID) || !is_array($entries) || empty($entries)) {
2365 return new WP_Error('empty_form', __('Form id or entries id is invalid', 'bit-form'));
2366 }
2367
2368 if (!filter_var($formID, FILTER_VALIDATE_INT)) {
2369 return new WP_Error('invalid_form', __('Form id is invalid', 'bit-form'));
2370 }
2371
2372 if (!Helpers::checkIsIntArr($entries)) {
2373 return new WP_Error('invalid_entries', __('Entries id is invalid', 'bit-form'));
2374 }
2375
2376 $formManager = new AdminFormManager($formID);
2377 if (!$formManager->isExist()) {
2378 return new WP_Error('empty_form', __('Form does not exist', 'bit-form'));
2379 }
2380 $formEntryModel = new FormEntryModel();
2381 $entryMeta = new FormEntryMetaModel();
2382 $user_details = static::$ipTool->getUserDetail();
2383 $total_entries = count($entries);
2384 $duplicate_count = 0;
2385 $test = '';
2386 $fileHandler = new FileHandler();
2387 $result = [];
2388 foreach ($entries as $entryIndex => $entryID) {
2389 $duplicatedEntryId = $formEntryModel->insert(
2390 [
2391 'form_id' => $formID,
2392 'user_id' => $user_details['id'],
2393 'user_ip' => $user_details['ip'],
2394 'user_device' => $user_details['device'],
2395 'referer' => 'duplicate of #' . $entryID,
2396 'status' => 1,
2397 'created_at' => $user_details['time'],
2398 ]
2399 );
2400 if ($duplicatedEntryId) {
2401 $duplicate_status = $entryMeta->duplicateEntryMeta(
2402 [
2403 'duplicateID' => $duplicatedEntryId,
2404 'entryID' => $entryID,
2405 ]
2406 );
2407 if ($duplicate_status) {
2408 $result['details'][$entryID] = $duplicatedEntryId;
2409 $duplicate_count = $duplicate_count + 1;
2410 if (file_exists(FileHandler::getEntriesFileUploadDir($formID, $entryID))) {
2411 $fileHandler->cpyr(
2412 FileHandler::getEntriesFileUploadDir($formID, $entryID),
2413 FileHandler::getEntriesFileUploadDir($formID, $duplicatedEntryId)
2414 );
2415 }
2416 }
2417 }
2418 }
2419
2420 $count = $formEntryModel->count(
2421 [
2422 'form_id' => $formID,
2423 ]
2424 );
2425 $formManager->resetSubmissionCount(intval($count[0]->count));
2426 $result['message'] = 1 === count($entries) ? __('Entry Duplicated successfully', 'bit-form') : __('Entries Duplicated successfully', 'bit-form');
2427 return ($total_entries === $duplicate_count) ? $result : false;
2428 }
2429
2430 public function editFormEntry($Request, $post)
2431 {
2432 if (!empty($Request['formID'])) {
2433 $formID = absint(wp_unslash($Request['formID']));
2434 $entryID = absint(wp_unslash($Request['entryID']));
2435 } else {
2436 $formID = wp_unslash($post->formID);
2437 $entryID = wp_unslash($post->entryID);
2438 }
2439 if (is_null($formID) || is_null($entryID)) {
2440 return new WP_Error('empty_form', __('Form id or entries id is invalid', 'bit-form'));
2441 }
2442
2443 $formManager = new AdminFormManager($formID);
2444 if (!$formManager->isExist()) {
2445 return new WP_Error('empty_form', __('Form does not exist', 'bit-form'));
2446 }
2447 $formEntryModel = new FormEntryModel();
2448 $entryMeta = new FormEntryMetaModel();
2449
2450 $formEntry = $formEntryModel->get(
2451 '*',
2452 [
2453 'form_id' => $formID,
2454 'id' => $entryID,
2455 ]
2456 );
2457
2458 if (!$formEntry) {
2459 return new WP_Error('empty_form', __('Form entries does not exist.', 'bit-form'));
2460 }
2461 $formEntryMeta = $entryMeta->get(
2462 [
2463 'meta_key',
2464 'meta_value',
2465 ],
2466 [
2467 'bitforms_form_entry_id' => $entryID,
2468 ]
2469 );
2470 $entries = [];
2471 foreach ($formEntryMeta as $key => $value) {
2472 $entries[$value->meta_key] = $value->meta_value;
2473 }
2474 $formContent = $formManager->getFormContent();
2475 $fieldsKey = $formManager->getFieldsKey();
2476 $form_fields = $formContent->fields;
2477 $layout = $formContent->layout;
2478 foreach ($form_fields as $key => $value) {
2479 // $field_name = preg_replace('/[\`\~\!\@\#\$\'\.\s\?\+\-\*\&\|\/\\!]/', '_', $value->lbl);
2480 if (isset($entries[$key])) {
2481 $form_fields->{$key}->val = $entries[$key];
2482 $form_fields->{$key}->name = $key;
2483 }
2484 }
2485 $workFlowRunHelper = new WorkFlow($formID);
2486 $workFlowreturnedOnLoad = $workFlowRunHelper->executeOnLoad(
2487 'edit',
2488 $form_fields
2489 );
2490 $workFlowreturnedOnUserInput = $workFlowRunHelper->executeOnUserInput(
2491 'edit',
2492 $form_fields
2493 );
2494 if (!empty($workFlowreturnedOnLoad['fields'])) {
2495 $form_fields = $workFlowreturnedOnLoad['fields'];
2496 }
2497 $formData = [
2498 'layout' => $layout,
2499 'fields' => $form_fields,
2500 'conditional' => !empty($workFlowreturnedOnUserInput['conditional']) ? $workFlowreturnedOnUserInput['conditional'] : false,
2501 'fieldToCheck' => !empty($workFlowreturnedOnUserInput['fieldToCheck']) ? $workFlowreturnedOnUserInput['fieldToCheck'] : false,
2502 'fieldToChange' => !empty($workFlowreturnedOnUserInput['fieldToChange']) ? $workFlowreturnedOnUserInput['fieldToChange'] : false,
2503 'fieldsKey' => $fieldsKey,
2504 ];
2505 return $formData;
2506 }
2507
2508 public function updateFormEntry($Request, $post)
2509 {
2510 if (isset($Request['formID'], $Request['entryID'])) {
2511 $formID = absint(wp_unslash($Request['formID']));
2512 $entryID = absint(wp_unslash($Request['entryID']));
2513 unset($Request['action'], $Request['formID'], $Request['entryID']);
2514 }
2515 $formManager = new AdminFormManager($formID);
2516 $formManager->fieldNameReplaceOfPost();
2517 // Called from AdminAjax handler; nonce already verified at AJAX entry before dispatch.
2518 $updatedValue = is_array($post) ? $post : wp_unslash($_POST);
2519
2520 if (is_null($updatedValue) || !is_array($updatedValue)) {
2521 return new WP_Error('empty_data', __('Failed to update, Data is empty.', 'bit-form'));
2522 }
2523
2524 if (is_null($formID) || is_null($entryID)) {
2525 return new WP_Error('empty_data', __('Invalid Form ID or entries ID.', 'bit-form'));
2526 }
2527
2528 if (!$formManager->isExist()) {
2529 return new WP_Error('empty_data', __('Form does not exist.', 'bit-form'));
2530 }
2531 return $formManager->updateFormEntry($updatedValue, $formID, $entryID);
2532 }
2533
2534 public function getLogHistory($Request, $post)
2535 {
2536 if (!empty($Request['formID'])) {
2537 $formID = absint(wp_unslash($Request['formID']));
2538 $entryID = absint(wp_unslash($Request['entryID']));
2539 } else {
2540 $formID = wp_unslash($post->formID);
2541 $entryID = wp_unslash($post->entryID);
2542 }
2543
2544 if (is_null($formID) || is_null($entryID)) {
2545 return new WP_Error('empty_form', __('Invalid Form ID or Entries ID.', 'bit-form'));
2546 }
2547
2548 $formManager = new AdminFormManager($formID);
2549 if (!$formManager->isExist()) {
2550 return new WP_Error('empty_form', __('Form does not exist.', 'bit-form'));
2551 }
2552 $formLogModel = new FormEntryLogModel();
2553
2554 $log_history = $formLogModel->geLogHistory($formID, $entryID);
2555 return $log_history;
2556 }
2557
2558 public function importDataStore($Request, $post)
2559 {
2560 if (!empty($Request['formID'])) {
2561 $formID = absint(wp_unslash($Request['formID']));
2562 } else {
2563 $formID = wp_unslash($post->formID);
2564 }
2565 if (is_null($formID)) {
2566 return new WP_Error('empty_form', __('Invalid Form id or entries id.', 'bit-form'));
2567 }
2568 }
2569
2570 public function getAllWPPages($Request, $post)
2571 {
2572 $pages = get_pages(['post_status' => 'publish', 'sort_column' => 'post_date', 'sort_order' => 'desc']);
2573 $allPages = [];
2574 foreach ($pages as $pageKey => $pageDetails) {
2575 // $allPages[$pageKey]['title'] = $pageDetails->post_title;
2576 // $allPages[$pageKey]['url'] = get_page_link($pageDetails->ID);
2577 $allPages[] = (object) [
2578 'title' => $pageDetails->post_title,
2579 'url' => get_page_link($pageDetails->ID)
2580 ];
2581 }
2582 return $allPages;
2583 }
2584
2585 public function deleteAIntegration($Request, $post)
2586 {
2587 if (!empty($Request['formID']) && !empty($Request['id'])) {
2588 $formID = absint(json_decode(wp_unslash($Request['formID'])));
2589 $id = absint(wp_unslash($Request['id']));
2590 } else {
2591 $formID = wp_unslash($post->formID);
2592 $id = wp_unslash($post->id);
2593 }
2594 if ($formID < 0 || empty($id)) {
2595 return new WP_Error('empty_form', 'Invalid Form ID or Integration ID.');
2596 }
2597
2598 $integrationHandler = new IntegrationHandler($formID);
2599 $delete_status = $integrationHandler->deleteIntegration($id);
2600 if (is_wp_error($delete_status)) {
2601 return $delete_status;
2602 }
2603
2604 return [
2605 'message' => __('Integration deleted', 'bit-form'),
2606 ];
2607 }
2608
2609 public function deleteSuccessMessage($Request, $post)
2610 {
2611 if (!empty($Request['formID']) && !empty($Request['id'])) {
2612 $formID = absint(json_decode(wp_unslash($Request['formID'])));
2613 $id = absint(wp_unslash($Request['id']));
2614 } else {
2615 $formID = wp_unslash($post->formID);
2616 $id = wp_unslash($post->id);
2617 }
2618 if (empty($formID) || empty($id)) {
2619 return new WP_Error('empty_form', 'Invalid Form ID or Message ID.');
2620 }
2621 $successMessageHandler
2622 = new SuccessMessageHandler($formID);
2623 $delete_status = $successMessageHandler->deleteMessage($id);
2624 if (is_wp_error($delete_status)) {
2625 return $delete_status;
2626 }
2627 return [
2628 'message' => __('Message deleted', 'bit-form'),
2629 ];
2630 }
2631
2632 public function deleteAWorkflow($Request, $post)
2633 {
2634 if (!empty($Request['formID']) && !empty($Request['id'])) {
2635 $formID = absint(json_decode(wp_unslash($Request['formID'])));
2636 $id = absint(wp_unslash($Request['id']));
2637 } else {
2638 $formID = wp_unslash($post->formID);
2639 $id = wp_unslash($post->id);
2640 }
2641 if (empty($formID) || empty($id)) {
2642 return new WP_Error('empty_form', 'Invalid Form ID or Workflow ID.');
2643 }
2644 $workFlowHandler = new WorkFlowHandler($formID);
2645 $delete_status = $workFlowHandler->deleteworkFlow($id);
2646 if (is_wp_error($delete_status)) {
2647 return $delete_status;
2648 }
2649 return [
2650 'message' => __('workflow deleted', 'bit-form'),
2651 ];
2652 }
2653
2654 public function deleteAMailTemplate($Request, $post)
2655 {
2656 if (!empty($Request['formID']) && !empty($Request['id'])) {
2657 $formID = absint(json_decode(wp_unslash($Request['formID'])));
2658 $id = absint(wp_unslash($Request['id']));
2659 } else {
2660 $formID = wp_unslash($post->formID);
2661 $id = wp_unslash($post->id);
2662 }
2663 if (empty($formID) || empty($id)) {
2664 return new WP_Error('empty_form', 'Invalid Form ID or Email Template ID.');
2665 }
2666 $emailTemplateHandler = new EmailTemplateHandler($formID);
2667 $delete_status = $emailTemplateHandler->deleteTemplate($id);
2668 if (is_wp_error($delete_status)) {
2669 return $delete_status;
2670 }
2671 return [
2672 'message' => __('Email Template deleted', 'bit-form'),
2673 ];
2674 }
2675
2676 public function duplicateAMailTemplate($Request, $post)
2677 {
2678 if (!empty($Request['formID']) && !empty($Request['id'])) {
2679 $formID = absint(json_decode(wp_unslash($Request['formID'])));
2680 $id = absint(wp_unslash($Request['id']));
2681 } else {
2682 $formID = wp_unslash($post->formID);
2683 $id = wp_unslash($post->id);
2684 }
2685 if (empty($formID) || empty($id)) {
2686 return new WP_Error('empty_form', 'Invalid Form ID or Email Template ID.');
2687 }
2688
2689 if (false === filter_var($id, FILTER_VALIDATE_INT)) {
2690 return new WP_Error('empty_form', 'Invalid Email Template ID.');
2691 }
2692
2693 if (false === filter_var($formID, FILTER_VALIDATE_INT)) {
2694 return new WP_Error('empty_form', 'Invalid Form ID.');
2695 }
2696
2697 $emailTemplateHandler = new EmailTemplateHandler($formID);
2698 $duplicate_status = $emailTemplateHandler->duplicateTemplate($id);
2699 if (is_wp_error($duplicate_status)) {
2700 return $duplicate_status;
2701 }
2702 return [
2703 'message' => __('Email Template duplicated', 'bit-form'),
2704 ];
2705 }
2706
2707 public function setAllFormsReport($Request, $post)
2708 {
2709 $reports = empty($post->reports) ? null : wp_unslash($post->reports);
2710 if (empty($reports)) {
2711 return new WP_Error('empty_report_prefs', 'Report data is Empty, nothing to save or update.');
2712 }
2713 if (!empty($reports)) {
2714 $reportsModel = new ReportsModel();
2715 $user_details = static::$ipTool->getUserDetail();
2716 foreach ($reports as $reportIndex => $report) {
2717 if (empty($report->id)) {
2718 $reportSaveSatus = $reportsModel->insert(
2719 [
2720 'type' => 'table',
2721 'category' => 'app',
2722 'context' => 'allForm',
2723 'details' => is_string($report->details) ? $report->details : wp_json_encode($report->details),
2724 'isDefault' => 1,
2725 'user_id' => $user_details['id'],
2726 'user_ip' => $user_details['ip'],
2727 'user_device' => $user_details['device'],
2728 'created_at' => $user_details['time'],
2729 'updated_at' => $user_details['time'],
2730 ]
2731 );
2732 $newData['reports'] = 1;
2733 } else {
2734 $reportSaveSatus = $reportsModel->update(
2735 [
2736 'type' => 'table',
2737 'category' => 'app',
2738 'context' => 'allForm',
2739 'details' => is_string($report->details) ? $report->details : wp_json_encode($report->details),
2740 'isDefault' => 1,
2741 'user_id' => $user_details['id'],
2742 'user_ip' => $user_details['ip'],
2743 'user_device' => $user_details['device'],
2744 'updated_at' => $user_details['time'],
2745 ],
2746 [
2747 'id' => $report->id,
2748 ]
2749 );
2750 }
2751 }
2752 }
2753 if (is_wp_error($reportSaveSatus)) {
2754 if ('result_empty' === $reportSaveSatus->get_error_code()) {
2755 return new WP_Error('empty_report_prefs', 'Nothing to save or update');
2756 }
2757 return new WP_Error('error_report_prefs', 'Error occured in saving reports');
2758 }
2759 $returnedReportData = $reportsModel->get(
2760 [
2761 'id',
2762 'details',
2763 'isDefault',
2764 'category',
2765 'context',
2766 ],
2767 [
2768 'category' => 'app',
2769 'context' => 'allForm',
2770 ]
2771 );
2772 if (!is_wp_error($returnedReportData)) {
2773 foreach ($returnedReportData as $reportKey => $reportData) {
2774 if (isset($reportData->details) && is_string($reportData->details)) {
2775 $returnedReportData[$reportKey]->details = json_decode($reportData->details);
2776 }
2777 }
2778 $reports = $returnedReportData;
2779 }
2780 return [
2781 'message' => __('Report preferrences saved successfully', 'bit-form'),
2782 'reports' => empty($reports) ? [] : $reports,
2783 ];
2784 }
2785
2786 public function savegReCaptcha($Request, $post)
2787 {
2788 $reCaptcha = $post->reCaptcha;
2789
2790 if (is_null($reCaptcha)) {
2791 return new WP_Error('empty_gcaptchdetails', __('g-ReCAPTCHA details is empty', 'bit-form'));
2792 }
2793 if (is_string($reCaptcha) && !empty(json_decode($reCaptcha)->id)) {
2794 $reCaptcha = json_decode($reCaptcha);
2795 $integrationID = $reCaptcha->id;
2796 unset($reCaptcha->id);
2797 } else {
2798 $integrationID = $reCaptcha->id;
2799 unset($reCaptcha->id);
2800 }
2801 $reCaptcha = wp_json_encode($reCaptcha);
2802
2803 // $integrationName = 'google reCaptcha';
2804 $integrationName = $post->integrationName;
2805
2806 // $integrationType = 'v2' === $post->version ? 'gReCaptcha' : 'gReCaptchaV3';
2807 $integrationType = $post->integrationType;
2808
2809 $integrationDetails = $reCaptcha;
2810 $user_details = static::$ipTool->getUserDetail();
2811 $integrationHandler = new IntegrationHandler(0, $user_details);
2812 $response = [];
2813 if (empty($integrationID)) {
2814 $captchaSaveStatus = $integrationHandler->saveIntegration($integrationName, $integrationType, $integrationDetails, 'app');
2815 $response['id'] = $captchaSaveStatus;
2816 $response['message'] = __('reCAPTCHA saved successfully', 'bit-form');
2817 } else {
2818 $captchaSaveStatus = $integrationHandler->updateIntegration($integrationID, $integrationName, $integrationType, $integrationDetails, 'app');
2819 $response['message'] = __('reCAPTCHA updated successfully', 'bit-form');
2820 }
2821
2822 if (is_wp_error($captchaSaveStatus)) {
2823 return $captchaSaveStatus;
2824 }
2825 return $response;
2826 }
2827
2828 public function savePaymentSetting($Request, $post)
2829 {
2830 if (isset($post->paySetting)) {
2831 $paySetting = $post->paySetting;
2832 }
2833 if (is_null($paySetting)) {
2834 return new WP_Error('empty_gcaptchdetails', __('Setting details is empty', 'bit-form'));
2835 }
2836 if (is_string($paySetting)) {
2837 $paySetting = json_decode($paySetting);
2838 }
2839
2840 $canSave = null;
2841 switch ($paySetting->type) {
2842 case 'PayPal':
2843 $canSave = $this->addWebhookToPaypal($paySetting);
2844 break;
2845 case 'Razorpay':
2846 $canSave = true;
2847 break;
2848 case 'Stripe':
2849 $canSave = $this->addWebhookToStripe($paySetting);
2850 break;
2851 case 'Mollie':
2852 $canSave = true;
2853 break;
2854 default:
2855 $canSave = null;
2856 }
2857 if (is_null($canSave)) {
2858 return new WP_Error('stripe', __('Please re-check your Client ID & Secret', 'bit-form'));
2859 }
2860 $integrationID = null;
2861 if (isset($paySetting->id)) {
2862 $integrationID = $paySetting->id;
2863 unset($paySetting->id);
2864 }
2865 $integrationName = $paySetting->name;
2866 $integrationType = 'payments';
2867 $paySetting = wp_json_encode($paySetting);
2868 $integrationDetails = $paySetting;
2869 $user_details = static::$ipTool->getUserDetail();
2870 $integrationHandler = new IntegrationHandler(0, $user_details);
2871 $response = [];
2872 if (empty($integrationID)) {
2873 $paymentSaveStatus = $integrationHandler->saveIntegration($integrationName, $integrationType, $integrationDetails, 'app');
2874 $response['id'] = $paymentSaveStatus;
2875 $response['message'] = __('Payment setting saved successfully', 'bit-form');
2876 } else {
2877 $paymentSaveStatus = $integrationHandler->updateIntegration($integrationID, $integrationName, $integrationType, $integrationDetails, 'app');
2878 $response['message'] = __('Payment setting updated successfully', 'bit-form');
2879 }
2880
2881 if (is_wp_error($paymentSaveStatus)) {
2882 return $paymentSaveStatus;
2883 }
2884 return $response;
2885 }
2886
2887 private function addWebhookToPaypal($paySetting)
2888 {
2889 $transaction_mode = $paySetting->mode;
2890 $clientId = $paySetting->clientID;
2891 $clientSecret = $paySetting->clientSecret;
2892 $base_url = 'sandbox' === $transaction_mode ? 'https://api-m.sandbox.paypal.com' : 'https://api.paypal.com';
2893 // get all webhooks
2894 $webhooks_url = $base_url . '/v1/notifications/webhooks';
2895 $webhooks_headers = [
2896 'Content-Type' => 'application/json',
2897 'Authorization' => 'Basic ' . base64_encode($clientId . ':' . $clientSecret)
2898 ];
2899 $webhook_url = get_rest_url() . 'bitform/v1/payments/paypal';
2900 // adding webhook
2901 $data = [
2902 'url' => $webhook_url,
2903 'event_types' => [
2904 [
2905 'name' => 'CHECKOUT.ORDER.APPROVED'
2906 ]
2907 ]
2908 ];
2909 $webhook_response = HttpHelper::post($webhooks_url, wp_json_encode($data), $webhooks_headers);
2910 if (is_wp_error($webhook_response) || $webhook_response->error) {
2911 return null;
2912 }
2913 return true;
2914 }
2915
2916 private function addWebhookToStripe($paySetting)
2917 {
2918 $clientSecret = $paySetting->clientSecret;
2919
2920 $create_webhook_url = 'https://api.stripe.com/v1/webhook_endpoints';
2921 $headers = [
2922 'Content-Type' => 'application/x-www-form-urlencoded',
2923 'Authorization' => "Bearer $clientSecret",
2924 ];
2925
2926 $webhook_url = get_rest_url() . 'bitform/v1/payments/stripe';
2927
2928 $apiResponse = HttpHelper::get($create_webhook_url, '', $headers);
2929
2930 if (isset($apiResponse->error)) {
2931 return null;
2932 }
2933 $webhookList = $apiResponse->data;
2934 $webhook_already_exist = false;
2935
2936 foreach ($webhookList as $webhook) {
2937 if ($webhook->url === $webhook_url) {
2938 $webhook_already_exist = true;
2939 break;
2940 }
2941 }
2942
2943 $data = [
2944 'enabled_events[]' => 'payment_intent.succeeded',
2945 'url' => $webhook_url,
2946 ];
2947
2948 if (!$webhook_already_exist) {
2949 $webhook_response = HttpHelper::post($create_webhook_url, $data, $headers);
2950 if (is_wp_error($webhook_response) || (isset($webhook_response->error) && $webhook_response->error)) {
2951 Log::debug_log(['Stripe webhook creation failed' => $webhook_response]);
2952 return null;
2953 }
2954 }
2955 return true;
2956 }
2957
2958 public function builerHelperState($formId)
2959 {
2960 $data = static::$formModel->get(
2961 ['id', 'builder_helper_state'],
2962 ['id' => $formId]
2963 );
2964
2965 if (!is_wp_error($data)) {
2966 foreach ($data as $key => $value) {
2967 if (isset($value->builder_helper_state) && is_string($value->builder_helper_state)) {
2968 $data[$key]->builder_helper_state = json_decode($value->builder_helper_state);
2969 }
2970 }
2971 }
2972
2973 return $data;
2974 }
2975
2976 public function updateGeneratedScriptPageIds()
2977 {
2978 $updateData = [
2979 'generated_script_page_ids' => \wp_json_encode((object) []),
2980 ];
2981 $update_status = static::$formModel->update(
2982 $updateData,
2983 [
2984 'status' => 1
2985 ]
2986 );
2987 if (is_wp_error($update_status)) {
2988 return $update_status;
2989 } elseif (!$update_status) {
2990 return new WP_Error('empty_form', __('Form update failed.', 'bit-form'));
2991 } else {
2992 return true;
2993 }
2994 }
2995
2996 public function replaceAllFormsErrorMessagesByGlobalMessages()
2997 {
2998 try {
2999 $formModel = new FormModel();
3000 $allForms = $formModel->get(['id', 'form_content']);
3001
3002 foreach ($allForms as $form) {
3003 // Decode form_content JSON to stdClass
3004 $formContent = \json_decode($form->form_content);
3005 $fields = $formContent->fields ?? null;
3006 // If decode fails, skip to next
3007 if (!$fields) {
3008 Log::debug_log("Form ID {$form->id}: invalid JSON in form_content");
3009 continue;
3010 }
3011
3012 // Replace default error messages using your helper
3013 $updatedFields = Helpers::replaceFieldsDefaultErrorMsg($fields);
3014
3015 $formContent->fields = $updatedFields;
3016 // Encode back to JSON
3017 $updatedContent = \json_encode($formContent);
3018
3019 if (false === $updatedContent) {
3020 Log::debug_log("Form ID {$form->id}: JSON encoding failed");
3021 continue;
3022 }
3023 // Update form content in DB
3024 $formModel->update(
3025 ['form_content' => $updatedContent], // data to update
3026 ['id' => $form->id] // condition for update
3027 );
3028 }
3029 } catch (\Exception $e) {
3030 Log::debug_log([
3031 'message' => 'Error in updateAllFormsErrorMessagesWithGlobalMessages',
3032 'error' => $e->getMessage(),
3033 ]);
3034 }
3035 }
3036
3037 public function updateSuccessMessageClassName($str, $msgIdx, $msgId)
3038 {
3039 $TEMP_CONF_ID = '_tmp_' . $msgIdx . '_conf_id';
3040 return str_replace($TEMP_CONF_ID, $msgId, $str);
3041 }
3042
3043 public function startMigrationProcess()
3044 {
3045 Utilities::duplicateDbTable('form', 'form_v1');
3046 Utilities::duplicateDbTable('workflows', 'workflows_v1');
3047 Utilities::duplicateDbTable('success_messages', 'success_messages_v1');
3048 MigrationHelper::duplicateV1StyleFiles();
3049 $all_forms = $this->getAllForm();
3050 $v1FormContents = [];
3051 $defaultStyleClass = MigrationHelper::getBitformDefaultStyleClass();
3052 foreach ($all_forms as $form) {
3053 $formContents = $this->getAFormV1(['id' => $form->id], ['id' => $form->id]);
3054 $v1FormContents[] = $formContents;
3055 FrontEndScriptGenerator::saveCssFile("{$form->id}", $defaultStyleClass);
3056 FrontEndScriptGenerator::saveCssFile("{$form->id}-formid", $defaultStyleClass);
3057 }
3058 set_transient('bitforms_v1_form_contents', $v1FormContents);
3059 update_option('bitforms_migrating_to_v2', true);
3060 }
3061 }
3062