PluginProbe
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder / 4.3.13
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder v4.3.13
6.2.13 6.2.12 6.2.10 6.2.11 6.2.9 6.2.8 6.2.7 6.2.6 6.2.5 6.2.4 6.2.3 6.2.2 3.6.22 3.6.31 3.6.40 3.6.41 3.6.42 3.6.50 3.6.51 3.6.60 3.6.61 3.6.62 3.6.64 3.6.65 3.6.66 All 195 releases
fluentform / app / Modules / Form / Form.php

Form.php in Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder 4.3.13, at app/Modules/Form/Form.php

735 lines 24.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentForm\App\Modules\Form;
4
5 use FluentForm\App\Helpers\Helper;
6 use FluentForm\App\Modules\Acl\Acl;
7 use FluentForm\Framework\Foundation\Application;
8 use FluentForm\Framework\Helpers\ArrayHelper;
9
10 class Form
11 {
12 /**
13 * @var \FluentForm\Framework\Request\Request $request
14 */
15 protected $request;
16
17 /**
18 * Set this value when we need predefined default settings.
19 *
20 * @var array $defaultSettings
21 */
22 protected $defaultSettings;
23
24
25 /**
26 * Set this value when we need predefined default notifications.
27 *
28 * @var array $defaultNotifications
29 */
30 protected $defaultNotifications;
31
32 /**
33 * Set this value when we need predefined form fields.
34 *
35 * @var array $formFields
36 */
37 protected $formFields;
38
39 protected $metas = [];
40
41 protected $formType = 'form';
42
43 protected $hasPayment = 0;
44
45 /**
46 * Form constructor.
47 *
48 * @param \FluentForm\Framework\Foundation\Application $application
49 *
50 * @throws \Exception
51 */
52 public function __construct(Application $application)
53 {
54 $this->request = $application->request;
55 $this->model = wpFluent()->table('fluentform_forms');
56 }
57
58 /**
59 * Get all forms from database
60 *
61 * @return void
62 * @throws \Exception
63 */
64 public function index()
65 {
66 $forms = fluentFormApi('forms')->forms([
67 'search' => $this->request->get('search'),
68 'status' => $this->request->get('status'),
69 'filter_by' => $this->request->get('filter_by', 'all'),
70 'date_range' => $this->request->get('date_range', []),
71 'sort_column' => $this->request->get('sort_column', 'id'),
72 'sort_by' => $this->request->get('sort_by', 'DESC'),
73 'per_page' => $this->request->get('per_page', 10),
74 'page' => $this->request->get('page', 1),
75 ]);
76
77 wp_send_json($forms, 200);
78 }
79
80
81 /**
82 * Create a form from backend/editor
83 * @return void|array
84 */
85 public function store($returnJSON = true)
86 {
87 $type = $this->request->get('type', $this->formType);
88 $title = $this->request->get('title', 'My New Form');
89 $status = $this->request->get('status', 'published');
90 $createdBy = get_current_user_id();
91
92 $now = current_time('mysql');
93
94 $insertData = [
95 'title' => $title,
96 'type' => $type,
97 'status' => $status,
98 'created_by' => $createdBy,
99 'created_at' => $now,
100 'updated_at' => $now
101 ];
102
103 if ($this->formFields) {
104 $insertData['form_fields'] = $this->formFields;
105 }
106
107 if ($this->hasPayment) {
108 $insertData['has_payment'] = $this->hasPayment;
109 }
110
111 $formId = $this->model->insert($insertData);
112
113 // Rename the form name here
114 wpFluent()->table('fluentform_forms')->where('id', $formId)->update(array(
115 'title' => $title . ' (#' . $formId . ')'
116 ));
117
118 if ($this->metas && is_array($this->metas)) {
119 foreach ($this->metas as $meta) {
120 $meta['value'] = trim(preg_replace('/\s+/', ' ', $meta['value']));
121
122 wpFluent()->table('fluentform_form_meta')
123 ->insert(array(
124 'form_id' => $formId,
125 'meta_key' => $meta['meta_key'],
126 'value' => $meta['value']
127 ));
128 }
129 } else {
130 // add default form settings now
131 $defaultSettings = $this->defaultSettings ?: $this->getFormsDefaultSettings($formId);
132
133 $defaultSettings = apply_filters('fluentform_create_default_settings', $defaultSettings);
134
135 wpFluent()->table('fluentform_form_meta')
136 ->insert(array(
137 'form_id' => $formId,
138 'meta_key' => 'formSettings',
139 'value' => json_encode($defaultSettings)
140 ));
141
142 if ($this->defaultNotifications) {
143 wpFluent()->table('fluentform_form_meta')
144 ->insert(array(
145 'form_id' => $formId,
146 'meta_key' => 'notifications',
147 'value' => json_encode($this->defaultNotifications)
148 ));
149 }
150 }
151
152 do_action('fluentform_inserted_new_form', $formId, $insertData);
153
154 $data = array(
155 'formId' => $formId,
156 'redirect_url' => admin_url('admin.php?page=fluent_forms&form_id=' . $formId . '&route=editor'),
157 'message' => __('Successfully created a form.', 'fluentform')
158 );
159
160 if ($returnJSON) {
161 wp_send_json_success($data, 200);
162 }
163
164 return $data;
165 }
166
167 public function getFormsDefaultSettings($formId = false)
168 {
169 $defaultSettings = array(
170 'confirmation' => array(
171 'redirectTo' => 'samePage',
172 'messageToShow' => __('Thank you for your message. We will get in touch with you shortly', 'fluentform'),
173 'customPage' => null,
174 'samePageFormBehavior' => 'hide_form',
175 'customUrl' => null
176 ),
177 'restrictions' => array(
178 'limitNumberOfEntries' => array(
179 'enabled' => false,
180 'numberOfEntries' => null,
181 'period' => 'total',
182 'limitReachedMsg' => 'Maximum number of entries exceeded.'
183 ),
184 'scheduleForm' => array(
185 'enabled' => false,
186 'start' => null,
187 'end' => null,
188 'selectedDays' => null,
189 'pendingMsg' => __("Form submission is not started yet.", 'fluentform'),
190 'expiredMsg' => __("Form submission is now closed.", 'fluentform')
191 ),
192 'requireLogin' => array(
193 'enabled' => false,
194 'requireLoginMsg' => 'You must be logged in to submit the form.',
195 ),
196 'denyEmptySubmission' => [
197 'enabled' => false,
198 'message' => __('Sorry, you cannot submit an empty form. Let\'s hear what you wanna say.', 'fluentform'),
199 ]
200 ),
201 'layout' => array(
202 'labelPlacement' => 'top',
203 'helpMessagePlacement' => 'with_label',
204 'errorMessagePlacement' => 'inline',
205 'cssClassName' => '',
206 'asteriskPlacement' => 'asterisk-right'
207 ),
208 'delete_entry_on_submission' => 'no'
209 );
210
211 if ($formId) {
212 $value = $this->getMeta($formId, 'formSettings', true);
213 if ($value) {
214 $defaultSettings = wp_parse_args($value, $defaultSettings);
215 }
216 } else {
217 $globalSettings = get_option('_fluentform_global_form_settings');
218 if (isset($globalSettings['layout'])) {
219 $defaultSettings['layout'] = $globalSettings['layout'];
220 }
221 }
222
223 return $defaultSettings;
224 }
225
226 public function getAdvancedValidationSettings($formId)
227 {
228 $settings = [
229 'status' => false,
230 'type' => 'all',
231 'conditions' => [
232 [
233 'field' => '',
234 'operator' => '=',
235 'value' => ''
236 ]
237 ],
238 'error_message' => '',
239 'validation_type' => 'fail_on_condition_met'
240 ];
241
242 $metaSettings = $this->getMeta($formId, 'advancedValidationSettings', true);
243
244 if ($metaSettings && is_array($metaSettings)) {
245 $settings = wp_parse_args($metaSettings, $settings);
246 }
247
248 return $settings;
249 }
250
251 public function getMeta($formId, $metaKey, $isJson = true)
252 {
253 $settingsMeta = wpFluent()->table('fluentform_form_meta')
254 ->where('form_id', $formId)
255 ->where('meta_key', $metaKey)
256 ->first();
257 if ($settingsMeta) {
258 if ($isJson) {
259 return \json_decode($settingsMeta->value, true);
260 } else {
261 return $settingsMeta->value;
262 }
263 }
264 return false;
265 }
266
267 public function updateMeta($formId, $metaKey, $metaValue)
268 {
269 $exist = wpFluent()->table('fluentform_form_meta')
270 ->where('form_id', $formId)
271 ->where('meta_key', $metaKey)
272 ->first();
273
274 if (is_array($metaValue) || is_object($metaValue)) {
275 $metaValue = \json_encode($metaValue);
276 }
277
278 if ($exist) {
279 return wpFluent()->table('fluentform_form_meta')
280 ->where('id', $exist->id)
281 ->update([
282 'value' => $metaValue
283 ]);
284 }
285
286 return wpFluent()->table('fluentform_form_meta')->insert([
287 'form_id' => $formId,
288 'meta_key' => $metaKey,
289 'value' => $metaValue
290 ]);
291 }
292
293 public function deleteMeta($formId, $metaKey)
294 {
295 return wpFluent()->table('fluentform_form_meta')
296 ->where('form_id', $formId)
297 ->where('meta_key', $metaKey)
298 ->delete();
299 }
300
301 /**
302 * Find/Read a from from the database
303 * @return void
304 */
305 public function find()
306 {
307 $form = $this->fetchForm($this->request->get('formId'));
308 wp_send_json(['form' => $form, 'metas' => []], 200);
309 }
310
311 /**
312 * Fetch a from from the database
313 * Note: required for ninja-tables
314 * @return mixed
315 */
316 public function fetchForm($formId)
317 {
318 return $this->model->find($formId);
319 }
320
321 /**
322 * Save/update a form from backend/editor
323 * @return void
324 * @throws \WpFluent\Exception
325 */
326 public function update()
327 {
328 $formId = $this->request->get('formId');
329 $title = sanitize_text_field($this->request->get('title'));
330 $status = $this->request->get('status', 'published');
331
332 $this->validate();
333
334 $data = [
335 'title' => $title,
336 'status' => $status,
337 'updated_at' => current_time('mysql')
338 ];
339
340
341 if ($formFields = $this->request->get('formFields')) {
342 $formFields = apply_filters('fluentform_form_fields_update', $formFields, $formId);
343 $formFields = $this->sanitizeFields($formFields);
344 $data['form_fields'] = $formFields;
345 }
346
347 $this->model->where('id', $formId)->update($data);
348
349 $form = $this->fetchForm($formId);
350
351 if (FormFieldsParser::hasPaymentFields($form)) {
352 $this->model->where('id', $formId)->update([
353 'has_payment' => 1
354 ]);
355 } elseif ($form->has_payment) {
356 $this->model->where('id', $formId)->update([
357 'has_payment' => 0
358 ]);
359 }
360
361 $emailInputs = FormFieldsParser::getElement($form, ['input_email'], ['element', 'attributes']);
362 if ($emailInputs) {
363 $emailInput = array_shift($emailInputs);
364 $emailInputName = ArrayHelper::get($emailInput, 'attributes.name');
365 $this->updateMeta($formId, '_primary_email_field', $emailInputName);
366 } else {
367 $this->updateMeta($formId, '_primary_email_field', '');
368 }
369
370 wp_send_json([
371 'message' => __('The form is successfully updated.', 'fluentform')
372 ], 200);
373 }
374
375
376 private function sanitizeFields($formFields)
377 {
378 if (current_user_can('unfiltered_html') || apply_filters('fluent_form_disable_fields_sanitize', false)) {
379 return $formFields;
380 }
381
382 $fieldsArray = json_decode($formFields, true);
383
384 if (isset($fieldsArray['submitButton'])) {
385 $fieldsArray['submitButton']['settings']['button_ui']['text'] = fluentform_sanitize_html($fieldsArray['submitButton']['settings']['button_ui']['text']);
386 if (!empty($fieldsArray['submitButton']['settings']['button_ui']['img_url'])) {
387 $fieldsArray['submitButton']['settings']['button_ui']['img_url'] = sanitize_url($fieldsArray['submitButton']['settings']['button_ui']['img_url']);
388 }
389 }
390
391 $fieldsArray['fields'] = $this->sanitizeFieldMaps($fieldsArray['fields']);
392
393 return json_encode($fieldsArray);
394 }
395
396 private function sanitizeFieldMaps($fields)
397 {
398 if (!is_array($fields)) {
399 return $fields;
400 }
401
402 $attributesMap = [
403 'name' => 'sanitize_key',
404 'value' => 'sanitize_textarea_field',
405 'id' => 'sanitize_key',
406 'class' => 'sanitize_text_field',
407 'placeholder' => 'sanitize_text_field'
408 ];
409 $attributesKeys = array_keys($attributesMap);
410 $settingsMap = [
411 'container_class' => 'sanitize_text_field',
412 'label' => 'wp_kses_post',
413 'label_placement' => 'sanitize_text_field',
414 'help_message' => 'wp_kses_post',
415 'admin_field_label' => 'sanitize_text_field',
416 'prefix_label' => 'sanitize_text_field',
417 'suffix_label' => 'sanitize_text_field',
418 'unique_validation_message' => 'sanitize_text_field',
419 'advanced_options' => 'fluentform_options_sanitize',
420 'html_codes' => 'fluentform_sanitize_html'
421 ];
422 $settingsKeys = array_keys($settingsMap);
423 $stylePrefMap = [
424 'layout' => 'sanitize_key',
425 'media' => 'sanitize_url',
426 'alt_text' => 'sanitize_text_field'
427 ];
428 $stylePrefKeys = array_keys($stylePrefMap);
429
430 foreach ($fields as $fieldIndex => $field) {
431 $element = ArrayHelper::get($field, 'element');
432
433 if ($element == 'container') {
434 $columns = $field['columns'];
435 foreach ($columns as $columnIndex => $column) {
436 $fields[$fieldIndex]['columns'][$columnIndex]['fields'] = $this->sanitizeFieldMaps($column['fields']);
437 }
438 return $fields;
439 }
440
441 /*
442 * Handle Name or address fields
443 */
444 if (!empty($field['fields'])) {
445 $fields[$fieldIndex]['fields'] = $this->sanitizeFieldMaps($field['fields']);
446 return $fields;
447 }
448
449 if (!empty($field['attributes'])) {
450 $attributes = array_filter(\FluentForm\Framework\Helpers\ArrayHelper::only($field['attributes'], $attributesKeys));
451 foreach ($attributes as $key => $value) {
452 $fields[$fieldIndex]['attributes'][$key] = call_user_func($attributesMap[$key], $value);
453 }
454 }
455
456 if (!empty($field['settings'])) {
457 $settings = array_filter(\FluentForm\Framework\Helpers\ArrayHelper::only($field['settings'], $settingsKeys));
458 foreach ($settings as $key => $value) {
459 $fields[$fieldIndex]['settings'][$key] = call_user_func($settingsMap[$key], $value);
460 }
461 }
462
463 if (!empty($field['style_pref'])) {
464 $settings = array_filter(\FluentForm\Framework\Helpers\ArrayHelper::only($field['style_pref'], $stylePrefKeys));
465 foreach ($settings as $key => $value) {
466 $fields[$fieldIndex]['style_pref'][$key] = call_user_func($stylePrefMap[$key], $value);
467 }
468 }
469 }
470
471 return $fields;
472 }
473
474
475 /**
476 * Delete a from from database
477 * @return void
478 * @throws \WpFluent\Exception
479 */
480 public function delete()
481 {
482 $formId = $this->request->get('formId');
483
484 $this->model->where('id', $formId)->delete();
485
486 $maybeErrors = $this->deleteFormAssests($formId);
487
488 wp_send_json([
489 'message' => __('Successfully deleted the form.', 'fluentform'),
490 'errors' => $maybeErrors
491 ], 200);
492 }
493
494
495 protected function deleteFormAssests($formId)
496 {
497 // Now Let's delete associate items
498 wpFluent()->table('fluentform_submissions')
499 ->where('form_id', $formId)
500 ->delete();
501
502 wpFluent()->table('fluentform_submission_meta')
503 ->where('form_id', $formId)
504 ->delete();
505
506 wpFluent()->table('fluentform_entry_details')
507 ->where('form_id', $formId)
508 ->delete();
509
510 wpFluent()->table('fluentform_form_meta')
511 ->where('form_id', $formId)
512 ->delete();
513
514 wpFluent()->table('fluentform_form_analytics')
515 ->where('form_id', $formId)
516 ->delete();
517
518 wpFluent()->table('fluentform_logs')
519 ->where('parent_source_id', $formId)
520 ->whereIn('source_type', ['submission_item', 'form_item', 'draft_submission_meta'])
521 ->delete();
522
523 ob_start();
524 if (defined('FLUENTFORMPRO')) {
525 try {
526 wpFluent()->table('fluentform_order_items')
527 ->where('form_id', $formId)
528 ->delete();
529
530 wpFluent()->table('fluentform_transactions')
531 ->where('form_id', $formId)
532 ->delete();
533 } catch (\Exception $exception) {
534 }
535 }
536 $errors = ob_get_clean();
537 return $errors;
538 }
539
540 /**
541 * Duplicate a from
542 * @return void
543 * @throws \WpFluent\Exception
544 */
545 public function duplicate()
546 {
547 $formId = absint($this->request->get('formId'));
548 $form = $this->model->where('id', $formId)->first();
549
550 $data = array(
551 'title' => $form->title,
552 'status' => $form->status,
553 'appearance_settings' => $form->appearance_settings,
554 'form_fields' => $form->form_fields,
555 'type' => $form->type,
556 'has_payment' => $form->has_payment,
557 'conditions' => $form->conditions,
558 'created_by' => get_current_user_id(),
559 'created_at' => current_time('mysql'),
560 'updated_at' => current_time('mysql')
561 );
562
563 $newFormId = $this->model->insert($data);
564
565 // Rename the form name here
566 wpFluent()->table('fluentform_forms')
567 ->where('id', $newFormId)
568 ->update(array(
569 'title' => $form->title . ' (#' . $newFormId . ')'
570 ));
571
572 $formMetas = wpFluent()->table('fluentform_form_meta')
573 ->where('form_id', $formId)
574 ->whereNot('meta_key', ['_total_views'])
575 ->get();
576
577 // Required for duplicating PDF feeds
578 $extras = [];
579
580 foreach ($formMetas as $meta) {
581 if ($meta->meta_key == 'notifications' || $meta->meta_key == '_pdf_feeds') {
582 $extras[$meta->meta_key][] = $meta;
583 continue;
584 }
585 $metaData = [
586 'meta_key' => $meta->meta_key,
587 'value' => $meta->value,
588 'form_id' => $newFormId
589 ];
590
591 wpFluent()->table('fluentform_form_meta')->insert($metaData);
592 }
593
594 $pdfFeedMap = $this->getPdfFeedMap($extras, $newFormId);
595 if (array_key_exists('notifications', $extras)) {
596 $extras = $this->notificationWithPdfMap($extras, $pdfFeedMap);
597 foreach ($extras['notifications'] as $notify) {
598 $notifyData = [
599 'meta_key' => $notify->meta_key,
600 'value' => $notify->value,
601 'form_id' => $newFormId
602 ];
603 wpFluent()->table('fluentform_form_meta')->insert($notifyData);
604 }
605 }
606
607 do_action('flentform_form_duplicated', $newFormId);
608
609 wp_send_json([
610 'message' => __('Form has been successfully duplicated.', 'fluentform'),
611 'form_id' => $newFormId,
612 'redirect' => admin_url('admin.php?page=fluent_forms&route=editor&form_id=' . $newFormId)
613 ], 200);
614 }
615
616 /**
617 * Validate a form by form title & for duplicate name attributes
618 * @return void
619 */
620 private function validate()
621 {
622 $fields = $this->request->get('formFields');
623 if ($fields) {
624 $duplicates = Helper::getDuplicateFieldNames($fields);
625 if ($duplicates) {
626 $duplicateString = implode(', ', $duplicates);
627 wp_send_json([
628 'title' => sprintf(__('Name attribute %s has duplicate value.', 'fluentform'), $duplicateString)
629 ], 422);
630 }
631 }
632
633 if (!sanitize_text_field($this->request->get('title'))) {
634 wp_send_json([
635 'title' => 'The title field is required.'
636 ], 422);
637 }
638 }
639
640 public function convertToConversational()
641 {
642 $formId = $this->request->get('form_id');
643 $form = $this->fetchForm($formId);
644
645
646 if (!$form) {
647 wp_send_json([
648 'message' => __('Form Not Found! Try Again.', 'fluentform')
649 ], 422);
650 }
651 $formConverted['form_fields'] = \FluentForm\App\Services\FluentConversational\Classes\Converter\Converter::convertExistingForm($form);
652
653 $this->model->where('id', $formId)->update($formConverted);
654
655
656 $this->updateMeta($formId, 'is_conversion_form', 'yes');
657 wp_send_json_success([
658 'message' => __('Form has been successfully converted to conversational form.', 'fluentform'),
659 ], 200);
660 }
661
662 private function getAdminPermalink($route, $form)
663 {
664 $baseUrl = admin_url('admin.php?page=fluent_forms');
665 return $baseUrl . '&route=' . $route . '&form_id=' . $form->id;
666 }
667
668 private function getSettingsUrl($form)
669 {
670 $baseUrl = admin_url('admin.php?page=fluent_forms');
671 return $baseUrl . '&form_id=' . $form->id . '&route=settings&sub_route=form_settings#basic_settings';
672 }
673
674 public function getAllForms()
675 {
676 $fields = $this->request->get('fields');
677
678 if ($fields) {
679 $forms = $this->model
680 ->select($fields)
681 ->orderBy('created_at', 'DESC')->get();
682 } else {
683 $forms = $this->model->orderBy('created_at', 'DESC')->get();
684 }
685
686 wp_send_json($forms, 200);
687 }
688
689 /**
690 * Map pdf feed ID to replace with duplicated PDF feed ID when duplicating form
691 * @param array $extras
692 * @param array $newFormId
693 * @return array
694 */
695 private function getPdfFeedMap($extras, $newFormId)
696 {
697 $pdfFeedMap = [];
698 if (array_key_exists('_pdf_feeds', $extras)) {
699 foreach ($extras['_pdf_feeds'] as $pdf_feed) {
700 $pdfData = [
701 'meta_key' => $pdf_feed->meta_key,
702 'value' => $pdf_feed->value,
703 'form_id' => $newFormId
704 ];
705 $pdfFeedMap[$pdf_feed->id] = wpFluent()->table('fluentform_form_meta')->insert($pdfData);
706 }
707 }
708 return $pdfFeedMap;
709 }
710
711 /**
712 * Map notification data with PDF feed map
713 * @param array $extras
714 * @param array $pdfFeedMap
715 * @return array
716 */
717 private function notificationWithPdfMap($extras, $pdfFeedMap)
718 {
719 foreach ($extras['notifications'] as $key => $notification) {
720 $notificationValue = json_decode($notification->value);
721 $pdf_attachments = [];
722 if (isset($notificationValue->pdf_attachments) && count($notificationValue->pdf_attachments)) {
723 foreach ($notificationValue->pdf_attachments as $attachment) {
724 $pdf_attachments[] = json_encode($pdfFeedMap[$attachment]);
725 }
726 }
727 $notificationValue->pdf_attachments = $pdf_attachments;
728 $notification->value = json_encode($notificationValue);
729
730 $extras['notifications'][$key] = $notification;
731 }
732 return $extras;
733 }
734 }
735