PluginProbe
Bit Form – Contact Form, Payment Forms, Multi Step Forms, Calculator & Custom Form Builder / V3.3.2
Bit Form – Contact Form, Payment Forms, Multi Step Forms, Calculator & Custom Form Builder vV3.3.2
V3.3.2 3.3.1 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 All 139 releases
bit-form / includes / Admin / Form / AdminFormHandler.php

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

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