PluginProbe
Bit Form – Contact Form, Payment Forms, Multi Step Forms, Calculator & Custom Form Builder / trunk
Bit Form – Contact Form, Payment Forms, Multi Step Forms, Calculator & Custom Form Builder vtrunk
V-3.3.0 3.2.2 3.2.1 3.2.0 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 V3.0.3 V3.0.2 -3.0.1 V_3.0.0 1.1.1 1.1.8 1.2 1.3 1.4 1.4.18 1.5.2 1.9 2.0 2.10.0 2.10.1 2.10.2 All 137 releases
bit-form / includes / Admin / Form / AdminFormHandler.php

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

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