PluginProbe
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder / 6.2.14
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder v6.2.14
6.2.14 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 All 196 releases
← All changes | app/Modules/Form/Form.php +530 -225 3.6.626.2.14 View file →
@@ -3,13 +3,18 @@
3 3 namespace FluentForm\App\Modules\Form;
4 4
5 5 use FluentForm\App\Helpers\Helper;
6 6 use FluentForm\App\Modules\Acl\Acl;
7 +use FluentForm\App\Modules\Payments\PaymentHelper;
8 +use FluentForm\App\Services\FormBuilder\RatingIcon;
7 9 use FluentForm\Framework\Foundation\Application;
10 +use FluentForm\Framework\Helpers\ArrayHelper;
8 11
9 12 class Form
10 13 {
11 14 /**
15 + * Request object
16 + *
12 17 * @var \FluentForm\Framework\Request\Request $request
13 18 */
14 19 protected $request;
15 20
@@ -19,9 +24,8 @@
19 24 * @var array $defaultSettings
20 25 */
21 26 protected $defaultSettings;
22 27
23 -
24 28 /**
25 29 * Set this value when we need predefined default notifications.
26 30 *
27 31 * @var array $defaultNotifications
@@ -39,15 +43,17 @@
39 43
40 44 protected $formType = 'form';
41 45
42 46 protected $hasPayment = 0;
47 + /**
48 + * @var \FluentForm\Framework\Database\Query\Builder
49 + */
50 + protected $model = null;
43 51
44 52 /**
45 53 * Form constructor.
46 54 *
47 55 * @param \FluentForm\Framework\Foundation\Application $application
48 - *
49 - * @throws \Exception
50 56 */
51 57 public function __construct(Application $application)
52 58 {
53 59 $this->request = $application->request;
@@ -55,93 +61,31 @@
55 61 }
56 62
57 63 /**
58 64 * Get all forms from database
59 - *
60 - * @return void
61 - * @throws \Exception
62 65 */
63 66 public function index()
64 67 {
65 - $search = $this->request->get('search');
66 - $status = $this->request->get('status');
68 + $forms = fluentFormApi('forms')->forms([
69 + 'search' => $this->request->get('search'),
70 + 'status' => $this->request->get('status'),
71 + 'filter_by' => $this->request->get('filter_by', 'all'),
72 + 'date_range' => $this->request->get('date_range', []),
73 + 'sort_column' => $this->request->get('sort_column', 'id'),
74 + 'sort_by' => $this->request->get('sort_by', 'DESC'),
75 + 'per_page' => $this->request->get('per_page', 10),
76 + 'page' => $this->request->get('page', 1),
77 + ]);
67 78
68 - $shortColumn = $this->request->get('sort_column', 'id');
69 - $sortBy = $this->request->get('sort_by', 'DESC');
70 -
71 - $query = wpFluent()->table('fluentform_forms')
72 - ->orderBy($shortColumn, $sortBy);
73 -
74 - if ($status && $status != 'all') {
75 - $query->where('status', $status);
76 - }
77 -
78 - if ($search) {
79 - $query->where(function ($q) use ($search) {
80 - $q->where('id', 'LIKE', '%' . $search . '%');
81 - $q->orWhere('title', 'LIKE', '%' . $search . '%');
82 - });
83 - }
84 -
85 - $forms = $query->paginate();
86 -
87 - foreach ($forms['data'] as $form) {
88 - $form->preview_url = site_url('?fluentform_pages=1&preview_id=' . $form->id) . '#ff_preview';;
89 - $form->edit_url = $this->getAdminPermalink('editor', $form);
90 - $form->settings_url = $this->getSettingsUrl($form);
91 - $form->entries_url = $this->getAdminPermalink('entries', $form);
92 - $form->analytics_url = $this->getAdminPermalink('analytics', $form);
93 - $form->total_views = $this->getFormViewCount($form->id);
94 - $form->total_views = $this->getFormViewCount($form->id);
95 - $form->total_Submissions = $this->getSubmissionCount($form->id);
96 - $form->unread_count = $this->getUnreadCount($form->id);
97 - $form->conversion = $this->getConversionRate($form);
98 - unset($form->form_fields);
99 - }
100 -
101 79 wp_send_json($forms, 200);
102 80 }
103 81
104 - private function getFormViewCount($formId)
105 - {
106 - $hasCount = wpFluent()
107 - ->table('fluentform_form_meta')
108 - ->where('meta_key', '_total_views')
109 - ->where('form_id', $formId)
110 - ->first();
111 -
112 - if ($hasCount) {
113 - return intval($hasCount->value);
114 - }
115 -
116 - return 0;
117 - }
118 -
119 - private function getSubmissionCount($formID)
120 - {
121 - return wpFluent()
122 - ->table('fluentform_submissions')
123 - ->where('form_id', $formID)
124 - ->where('status', '!=', 'trashed')
125 - ->count();
126 - }
127 -
128 - private function getConversionRate($form)
129 - {
130 - if (!$form->total_Submissions)
131 - return 0;
132 -
133 - if (!$form->total_views)
134 - return 0;
135 -
136 - return ceil(($form->total_Submissions / $form->total_views) * 100);
137 - }
138 -
139 82 /**
140 83 * Create a form from backend/editor
141 - * @return void
84 + *
85 + * @return void|array
142 86 */
143 - public function store()
87 + public function store($returnJSON = true)
144 88 {
145 89 $type = $this->request->get('type', $this->formType);
146 90 $title = $this->request->get('title', 'My New Form');
147 91 $status = $this->request->get('status', 'published');
@@ -149,14 +93,14 @@
149 93
150 94 $now = current_time('mysql');
151 95
152 96 $insertData = [
153 - 'title' => $title,
154 - 'type' => $type,
155 - 'status' => $status,
97 + 'title' => $title,
98 + 'type' => $type,
99 + 'status' => $status,
156 100 'created_by' => $createdBy,
157 101 'created_at' => $now,
158 - 'updated_at' => $now
102 + 'updated_at' => $now,
159 103 ];
160 104
161 105 if ($this->formFields) {
162 106 $insertData['form_fields'] = $this->formFields;
@@ -161,104 +105,132 @@
161 105 if ($this->formFields) {
162 106 $insertData['form_fields'] = $this->formFields;
163 107 }
164 108
165 - if($this->hasPayment) {
109 + if ($this->hasPayment) {
166 110 $insertData['has_payment'] = $this->hasPayment;
167 111 }
168 112
169 - $formId = $this->model->insert($insertData);
113 + $formId = $this->model->insertGetId($insertData);
170 114
171 115 // Rename the form name here
172 - wpFluent()->table('fluentform_forms')->where('id', $formId)->update(array(
173 - 'title' => $title . ' (#' . $formId . ')'
174 - ));
116 + wpFluent()->table('fluentform_forms')->where('id', $formId)->update([
117 + 'title' => $title . ' (#' . $formId . ')',
118 + ]);
175 119
176 - if($this->metas && is_array($this->metas)) {
120 + if ($this->metas && is_array($this->metas)) {
177 121 foreach ($this->metas as $meta) {
178 122 $meta['value'] = trim(preg_replace('/\s+/', ' ', $meta['value']));
179 123
180 124 wpFluent()->table('fluentform_form_meta')
181 - ->insert(array(
182 - 'form_id' => $formId,
125 + ->insert([
126 + 'form_id' => $formId,
183 127 'meta_key' => $meta['meta_key'],
184 - 'value' => $meta['value']
185 - ));
128 + 'value' => $meta['value'],
129 + ]);
186 130 }
187 131 } else {
188 132 // add default form settings now
189 133 $defaultSettings = $this->defaultSettings ?: $this->getFormsDefaultSettings($formId);
134 +
135 + $defaultSettings = apply_filters_deprecated(
136 + 'fluentform_create_default_settings',
137 + [
138 + $defaultSettings
139 + ],
140 + FLUENTFORM_FRAMEWORK_UPGRADE,
141 + 'fluentform/create_default_settings',
142 + 'Use fluentform/create_default_settings instead of fluentform_create_default_settings.'
143 + );
190 144
191 - $defaultSettings = apply_filters('fluentform_create_default_settings', $defaultSettings);
145 + $defaultSettings = apply_filters('fluentform/create_default_settings', $defaultSettings);
192 146
193 147 wpFluent()->table('fluentform_form_meta')
194 - ->insert(array(
195 - 'form_id' => $formId,
148 + ->insert([
149 + 'form_id' => $formId,
196 150 'meta_key' => 'formSettings',
197 - 'value' => json_encode($defaultSettings)
198 - ));
151 + 'value' => json_encode($defaultSettings),
152 + ]);
199 153
200 154 if ($this->defaultNotifications) {
201 155 wpFluent()->table('fluentform_form_meta')
202 - ->insert(array(
203 - 'form_id' => $formId,
156 + ->insert([
157 + 'form_id' => $formId,
204 158 'meta_key' => 'notifications',
205 - 'value' => json_encode($this->defaultNotifications)
206 - ));
159 + 'value' => json_encode($this->defaultNotifications),
160 + ]);
207 161 }
208 162 }
209 163
210 - do_action('fluentform_inserted_new_form', $formId, $insertData);
164 + do_action_deprecated(
165 + 'fluentform_inserted_new_form',
166 + [
167 + $formId,
168 + $insertData
169 + ],
170 + FLUENTFORM_FRAMEWORK_UPGRADE,
171 + 'fluentform/inserted_new_form',
172 + 'Use fluentform/inserted_new_form instead of fluentform_inserted_new_form.'
173 + );
211 174
212 - wp_send_json_success(array(
213 - 'formId' => $formId,
175 + do_action('fluentform/inserted_new_form', $formId, $insertData);
176 +
177 + $data = [
178 + 'formId' => $formId,
214 179 'redirect_url' => admin_url('admin.php?page=fluent_forms&form_id=' . $formId . '&route=editor'),
215 - 'message' => __('Successfully created a form.', 'fluentform')
216 - ), 200);
180 + 'message' => __('Successfully created a form.', 'fluentform'),
181 + ];
182 +
183 + if ($returnJSON) {
184 + wp_send_json_success($data, 200);
185 + }
186 +
187 + return $data;
217 188 }
218 189
219 190 public function getFormsDefaultSettings($formId = false)
220 191 {
221 - $defaultSettings = array(
222 - 'confirmation' => array(
223 - 'redirectTo' => 'samePage',
224 - 'messageToShow' => __('Thank you for your message. We will get in touch with you shortly', 'fluentform'),
225 - 'customPage' => null,
192 + $defaultSettings = [
193 + 'confirmation' => [
194 + 'redirectTo' => 'samePage',
195 + 'messageToShow' => __('Thank you for your message. We will get in touch with you shortly.', 'fluentform'),
196 + 'customPage' => null,
226 197 'samePageFormBehavior' => 'hide_form',
227 - 'customUrl' => null
228 - ),
229 - 'restrictions' => array(
230 - 'limitNumberOfEntries' => array(
231 - 'enabled' => false,
198 + 'customUrl' => null,
199 + ],
200 + 'restrictions' => [
201 + 'limitNumberOfEntries' => [
202 + 'enabled' => false,
232 203 'numberOfEntries' => null,
233 - 'period' => 'total',
234 - 'limitReachedMsg' => 'Maximum number of entries exceeded.'
235 - ),
236 - 'scheduleForm' => array(
237 - 'enabled' => false,
238 - 'start' => null,
239 - 'end' => null,
240 - 'pendingMsg' => __("Form submission is not started yet.", 'fluentform'),
241 - 'expiredMsg' => __("Form submission is now closed.", 'fluentform')
242 - ),
243 - 'requireLogin' => array(
244 - 'enabled' => false,
204 + 'period' => 'total',
205 + 'limitReachedMsg' => 'Maximum number of entries exceeded.',
206 + ],
207 + 'scheduleForm' => [
208 + 'enabled' => false,
209 + 'start' => null,
210 + 'end' => null,
211 + 'selectedDays' => null,
212 + 'pendingMsg' => __('Form submission is not started yet.', 'fluentform'),
213 + 'expiredMsg' => __('Form submission is now closed.', 'fluentform'),
214 + ],
215 + 'requireLogin' => [
216 + 'enabled' => false,
245 217 'requireLoginMsg' => 'You must be logged in to submit the form.',
246 - ),
218 + ],
247 219 'denyEmptySubmission' => [
248 220 'enabled' => false,
249 221 'message' => __('Sorry, you cannot submit an empty form. Let\'s hear what you wanna say.', 'fluentform'),
250 - ]
251 - ),
252 - 'layout' => array(
253 - 'labelPlacement' => 'top',
254 - 'helpMessagePlacement' => 'with_label',
222 + ],
223 + ],
224 + 'layout' => [
225 + 'labelPlacement' => 'top',
226 + 'helpMessagePlacement' => 'with_label',
255 227 'errorMessagePlacement' => 'inline',
256 - 'cssClassName' => '',
257 - 'asteriskPlacement' => 'asterisk-right'
258 - ),
259 - 'delete_entry_on_submission' => 'no'
260 - );
228 + 'cssClassName' => '',
229 + 'asteriskPlacement' => 'asterisk-right'
230 + ],
231 + 'delete_entry_on_submission' => 'no',
232 + ];
261 233
262 234 if ($formId) {
263 235 $value = $this->getMeta($formId, 'formSettings', true);
264 236 if ($value) {
@@ -276,24 +248,24 @@
276 248
277 249 public function getAdvancedValidationSettings($formId)
278 250 {
279 251 $settings = [
280 - 'status' => false,
281 - 'type' => 'all',
252 + 'status' => false,
253 + 'type' => 'all',
282 254 'conditions' => [
283 255 [
284 - 'field' => '',
256 + 'field' => '',
285 257 'operator' => '=',
286 - 'value' => ''
287 - ]
258 + 'value' => '',
259 + ],
288 260 ],
289 - 'error_message' => '',
290 - 'validation_type' => 'fail_on_condition_met'
261 + 'error_message' => '',
262 + 'validation_type' => 'fail_on_condition_met',
291 263 ];
292 264
293 265 $metaSettings = $this->getMeta($formId, 'advancedValidationSettings', true);
294 266
295 - if($metaSettings && is_array($metaSettings)) {
267 + if ($metaSettings && is_array($metaSettings)) {
296 268 $settings = wp_parse_args($metaSettings, $settings);
297 269 }
298 270
299 271 return $settings;
@@ -305,9 +277,9 @@
305 277 ->where('form_id', $formId)
306 278 ->where('meta_key', $metaKey)
307 279 ->first();
308 280 if ($settingsMeta) {
309 - if($isJson) {
281 + if ($isJson) {
310 282 return \json_decode($settingsMeta->value, true);
311 283 } else {
312 284 return $settingsMeta->value;
313 285 }
@@ -321,24 +293,24 @@
321 293 ->where('form_id', $formId)
322 294 ->where('meta_key', $metaKey)
323 295 ->first();
324 296
325 - if(is_array($metaValue) || is_object($metaValue)) {
297 + if (is_array($metaValue) || is_object($metaValue)) {
326 298 $metaValue = \json_encode($metaValue);
327 299 }
328 300
329 - if($exist) {
301 + if ($exist) {
330 302 return wpFluent()->table('fluentform_form_meta')
331 303 ->where('id', $exist->id)
332 304 ->update([
333 - 'value' => $metaValue
305 + 'value' => $metaValue,
334 306 ]);
335 307 }
336 308
337 - return wpFluent()->table('fluentform_form_meta')->insert([
338 - 'form_id' => $formId,
309 + return wpFluent()->table('fluentform_form_meta')->insertGetId([
310 + 'form_id' => $formId,
339 311 'meta_key' => $metaKey,
340 - 'value' => $metaValue
312 + 'value' => $metaValue,
341 313 ]);
342 314 }
343 315
344 316 public function deleteMeta($formId, $metaKey)
@@ -350,9 +322,8 @@
350 322 }
351 323
352 324 /**
353 325 * Find/Read a from from the database
354 - * @return void
355 326 */
356 327 public function find()
357 328 {
358 329 $form = $this->fetchForm($this->request->get('formId'));
@@ -361,8 +332,9 @@
361 332
362 333 /**
363 334 * Fetch a from from the database
364 335 * Note: required for ninja-tables
336 + *
365 337 * @return mixed
366 338 */
367 339 public function fetchForm($formId)
368 340 {
@@ -370,28 +342,36 @@
370 342 }
371 343
372 344 /**
373 345 * Save/update a form from backend/editor
374 - * @return void
375 - * @throws \WpFluent\Exception
376 346 */
377 347 public function update()
378 348 {
379 349 $formId = $this->request->get('formId');
380 - $title = $this->request->get('title');
350 + $title = sanitize_text_field($this->request->get('title'));
381 351 $status = $this->request->get('status', 'published');
382 352
383 353 $this->validate();
384 354
385 355 $data = [
386 - 'title' => $title,
387 - 'status' => $status,
388 - 'updated_at' => current_time('mysql')
356 + 'title' => $title,
357 + 'status' => $status,
358 + 'updated_at' => current_time('mysql'),
389 359 ];
390 360
391 -
392 361 if ($formFields = $this->request->get('formFields')) {
393 - $formFields = apply_filters('fluentform_form_fields_update', $formFields, $formId);
362 + $formFields = apply_filters_deprecated(
363 + 'fluentform_form_fields_update',
364 + [
365 + $formFields,
366 + $formId
367 + ],
368 + FLUENTFORM_FRAMEWORK_UPGRADE,
369 + 'fluentform/form_fields_update',
370 + 'Use fluentform/form_fields_update instead of fluentform_form_fields_update.'
371 + );
372 + $formFields = apply_filters('fluentform/form_fields_update', $formFields, $formId);
373 + $formFields = $this->sanitizeFields($formFields);
394 374 $data['form_fields'] = $formFields;
395 375 }
396 376
397 377 $this->model->where('id', $formId)->update($data);
@@ -399,25 +379,141 @@
399 379 $form = $this->fetchForm($formId);
400 380
401 381 if (FormFieldsParser::hasPaymentFields($form)) {
402 382 $this->model->where('id', $formId)->update([
403 - 'has_payment' => 1
383 + 'has_payment' => 1,
404 384 ]);
405 - } else if ($form->has_payment) {
385 + } elseif ($form->has_payment) {
406 386 $this->model->where('id', $formId)->update([
407 - 'has_payment' => 0
387 + 'has_payment' => 0,
408 388 ]);
409 389 }
410 390
391 + $emailInputs = FormFieldsParser::getElement($form, ['input_email'], ['element', 'attributes']);
392 + if ($emailInputs) {
393 + $emailInput = array_shift($emailInputs);
394 + $emailInputName = ArrayHelper::get($emailInput, 'attributes.name');
395 + $this->updateMeta($formId, '_primary_email_field', $emailInputName);
396 + } else {
397 + $this->updateMeta($formId, '_primary_email_field', '');
398 + }
399 +
411 400 wp_send_json([
412 - 'message' => __('The form is successfully updated.', 'fluentform')
401 + 'message' => __('The form is successfully updated.', 'fluentform'),
413 402 ], 200);
414 403 }
415 404
405 + private function sanitizeFields($formFields)
406 + {
407 + if (fluentformCanUnfilteredHTML()) {
408 + return $formFields;
409 + }
410 +
411 + $fieldsArray = json_decode($formFields, true);
412 +
413 + if (isset($fieldsArray['submitButton'])) {
414 + $fieldsArray['submitButton']['settings']['button_ui']['text'] = fluentform_sanitize_html($fieldsArray['submitButton']['settings']['button_ui']['text']);
415 + if (!empty($fieldsArray['submitButton']['settings']['button_ui']['img_url'])) {
416 + $fieldsArray['submitButton']['settings']['button_ui']['img_url'] = sanitize_url($fieldsArray['submitButton']['settings']['button_ui']['img_url']);
417 + }
418 + }
419 +
420 + $fieldsArray['fields'] = $this->sanitizeFieldMaps($fieldsArray['fields']);
421 +
422 + return json_encode($fieldsArray);
423 + }
424 +
425 + private function sanitizeFieldMaps($fields)
426 + {
427 + if (!is_array($fields)) {
428 + return $fields;
429 + }
430 +
431 + $attributesMap = [
432 + 'name' => 'sanitize_key',
433 + 'value' => 'sanitize_textarea_field',
434 + 'id' => 'sanitize_key',
435 + 'class' => 'sanitize_text_field',
436 + 'placeholder' => 'sanitize_text_field',
437 + ];
438 + $attributesKeys = array_keys($attributesMap);
439 + $settingsMap = [
440 + 'container_class' => 'sanitize_text_field',
441 + 'label' => 'wp_kses_post',
442 + 'label_placement' => 'sanitize_text_field',
443 + 'help_message' => 'wp_kses_post',
444 + 'admin_field_label' => 'sanitize_text_field',
445 + 'prefix_label' => 'sanitize_text_field',
446 + 'suffix_label' => 'sanitize_text_field',
447 + 'icon_source' => 'sanitize_key',
448 + 'icon_type' => 'sanitize_key',
449 + 'custom_icon_svg' => [RatingIcon::class, 'sanitizeCustomSvg'],
450 + 'inactive_color' => [RatingIcon::class, 'sanitizeColor'],
451 + 'active_color' => [RatingIcon::class, 'sanitizeColor'],
452 + 'unique_validation_message' => 'sanitize_text_field',
453 + 'advanced_options' => 'fluentform_options_sanitize',
454 + 'html_codes' => 'fluentform_sanitize_html',
455 + 'enable_crop' => 'sanitize_text_field',
456 + 'crop_mode' => 'sanitize_text_field',
457 + 'crop_ratio' => 'sanitize_text_field',
458 + 'crop_width' => 'absint',
459 + 'crop_height' => 'absint',
460 + 'enforce_image_dimensions' => 'sanitize_text_field',
461 + ];
462 + $settingsKeys = array_keys($settingsMap);
463 + $stylePrefMap = [
464 + 'layout' => 'sanitize_key',
465 + 'media' => 'sanitize_url',
466 + 'alt_text' => 'sanitize_text_field',
467 + ];
468 + $stylePrefKeys = array_keys($stylePrefMap);
469 +
470 + foreach ($fields as $fieldIndex => $field) {
471 + $element = ArrayHelper::get($field, 'element');
472 +
473 + if ('container' == $element) {
474 + $columns = $field['columns'];
475 + foreach ($columns as $columnIndex => $column) {
476 + $fields[$fieldIndex]['columns'][$columnIndex]['fields'] = $this->sanitizeFieldMaps($column['fields']);
477 + }
478 + return $fields;
479 + }
480 +
481 + /*
482 + * Handle Name or address fields
483 + */
484 + if (!empty($field['fields'])) {
485 + $fields[$fieldIndex]['fields'] = $this->sanitizeFieldMaps($field['fields']);
486 + return $fields;
487 + }
488 +
489 + if (!empty($field['attributes'])) {
490 + $attributes = array_filter(ArrayHelper::only($field['attributes'], $attributesKeys));
491 + foreach ($attributes as $key => $value) {
492 + $fields[$fieldIndex]['attributes'][$key] = call_user_func($attributesMap[$key], $value);
493 + }
494 + }
495 +
496 + if (!empty($field['settings'])) {
497 + $settings = array_filter(ArrayHelper::only($field['settings'], $settingsKeys));
498 + foreach ($settings as $key => $value) {
499 + $fields[$fieldIndex]['settings'][$key] = call_user_func($settingsMap[$key], $value);
500 + }
501 + }
502 +
503 + if (!empty($field['style_pref'])) {
504 + $settings = array_filter(ArrayHelper::only($field['style_pref'], $stylePrefKeys));
505 + foreach ($settings as $key => $value) {
506 + $fields[$fieldIndex]['style_pref'][$key] = call_user_func($stylePrefMap[$key], $value);
507 + }
508 + }
509 + }
510 +
511 + return $fields;
512 + }
513 +
416 514 /**
417 515 * Delete a from from database
418 - * @return void
419 - * @throws \WpFluent\Exception
420 516 */
421 517 public function delete()
422 518 {
423 519 $formId = $this->request->get('formId');
@@ -425,16 +521,14 @@
425 521 $this->model->where('id', $formId)->delete();
426 522
427 523 $maybeErrors = $this->deleteFormAssests($formId);
428 524
429 -
430 525 wp_send_json([
431 526 'message' => __('Successfully deleted the form.', 'fluentform'),
432 - 'errors' => $maybeErrors
527 + 'errors' => $maybeErrors,
433 528 ], 200);
434 529 }
435 530
436 -
437 531 protected function deleteFormAssests($formId)
438 532 {
439 533 // Now Let's delete associate items
440 534 wpFluent()->table('fluentform_submissions')
@@ -448,8 +542,12 @@
448 542 wpFluent()->table('fluentform_entry_details')
449 543 ->where('form_id', $formId)
450 544 ->delete();
451 545
546 + wpFluent()->table('fluentform_form_meta')
547 + ->where('form_id', $formId)
548 + ->delete();
549 +
452 550 wpFluent()->table('fluentform_form_analytics')
453 551 ->where('form_id', $formId)
454 552 ->delete();
455 553
@@ -454,25 +552,20 @@
454 552 ->delete();
455 553
456 554 wpFluent()->table('fluentform_logs')
457 555 ->where('parent_source_id', $formId)
458 - ->whereIn('source_type', ['submission_item', 'form_item'])
556 + ->whereIn('source_type', ['submission_item', 'form_item', 'draft_submission_meta'])
459 557 ->delete();
460 558
461 559 ob_start();
462 - if (defined('FLUENTFORMPRO')) {
560 + if (PaymentHelper::hasPaymentSettings()) {
463 561 try {
464 - wpFluent()->table('fluentform_order_items')
465 - ->where('form_id', $formId)
466 - ->delete();
467 -
468 - wpFluent()->table('fluentform_transactions')
469 - ->where('form_id', $formId)
470 - ->delete();
562 + \FluentForm\App\Models\OrderItem::where('form_id', $formId)->delete();
563 + \FluentForm\App\Models\Transaction::where('form_id', $formId)->delete();
471 564 } catch (\Exception $exception) {
472 -
473 565 }
474 566 }
567 +
475 568 $errors = ob_get_clean();
476 569 return $errors;
477 570 }
478 571
@@ -477,10 +570,8 @@
477 570 }
478 571
479 572 /**
480 573 * Duplicate a from
481 - * @return void
482 - * @throws \WpFluent\Exception
483 574 */
484 575 public function duplicate()
485 576 {
486 577 $formId = absint($this->request->get('formId'));
@@ -485,29 +576,29 @@
485 576 {
486 577 $formId = absint($this->request->get('formId'));
487 578 $form = $this->model->where('id', $formId)->first();
488 579
489 - $data = array(
490 - 'title' => $form->title,
491 - 'status' => $form->status,
580 + $data = [
581 + 'title' => $form->title,
582 + 'status' => $form->status,
492 583 'appearance_settings' => $form->appearance_settings,
493 - 'form_fields' => $form->form_fields,
494 - 'type' => $form->type,
495 - 'has_payment' => $form->has_payment,
496 - 'conditions' => $form->conditions,
497 - 'created_by' => get_current_user_id(),
498 - 'created_at' => current_time('mysql'),
499 - 'updated_at' => current_time('mysql')
500 - );
584 + 'form_fields' => $form->form_fields,
585 + 'type' => $form->type,
586 + 'has_payment' => $form->has_payment,
587 + 'conditions' => $form->conditions,
588 + 'created_by' => get_current_user_id(),
589 + 'created_at' => current_time('mysql'),
590 + 'updated_at' => current_time('mysql'),
591 + ];
501 592
502 - $newFormId = $this->model->insert($data);
593 + $newFormId = $this->model->insertGetId($data);
503 594
504 - // Ranme the form name here
595 + // Rename the form name here
505 596 wpFluent()->table('fluentform_forms')
506 597 ->where('id', $newFormId)
507 - ->update(array(
508 - 'title' => $form->title . ' (#' . $newFormId . ')'
509 - ));
598 + ->update([
599 + 'title' => $form->title . ' (#' . $newFormId . ')',
600 + ]);
510 601
511 602 $formMetas = wpFluent()->table('fluentform_form_meta')
512 603 ->where('form_id', $formId)
513 604 ->whereNot('meta_key', ['_total_views'])
@@ -512,40 +603,126 @@
512 603 ->where('form_id', $formId)
513 604 ->whereNot('meta_key', ['_total_views'])
514 605 ->get();
515 606
607 + // Required for duplicating PDF feeds
608 + $extras = [];
609 +
516 610 foreach ($formMetas as $meta) {
611 + if ('notifications' == $meta->meta_key || '_pdf_feeds' == $meta->meta_key) {
612 + $extras[$meta->meta_key][] = $meta;
613 + continue;
614 + }
615 + if ("ffc_form_settings_generated_css" == $meta->meta_key || "ffc_form_settings_meta" == $meta->meta_key) {
616 + $meta->value = str_replace('ff_conv_app_' . $formId, 'ff_conv_app_' . $newFormId, $meta->value);
617 + }
517 618 $metaData = [
518 619 'meta_key' => $meta->meta_key,
519 - 'value' => $meta->value,
520 - 'form_id' => $newFormId
620 + 'value' => $meta->value,
621 + 'form_id' => $newFormId,
521 622 ];
522 623
523 624 wpFluent()->table('fluentform_form_meta')->insert($metaData);
524 625 }
525 626
526 - do_action('flentform_form_duplicated', $newFormId);
627 + $pdfFeedMap = $this->getPdfFeedMap($extras, $newFormId);
628 + if (array_key_exists('notifications', $extras)) {
629 + $extras = $this->notificationWithPdfMap($extras, $pdfFeedMap);
630 + foreach ($extras['notifications'] as $notify) {
631 + $notifyData = [
632 + 'meta_key' => $notify->meta_key,
633 + 'value' => $notify->value,
634 + 'form_id' => $newFormId,
635 + ];
636 + wpFluent()->table('fluentform_form_meta')->insert($notifyData);
637 + }
638 + }
527 639
640 + do_action_deprecated(
641 + 'flentform_form_duplicated',
642 + [
643 + $newFormId
644 + ],
645 + FLUENTFORM_FRAMEWORK_UPGRADE,
646 + 'fluentform/form_duplicated',
647 + 'Use fluentform/form_duplicated instead of flentform_form_duplicated.'
648 + );
649 +
650 + do_action('fluentform/form_duplicated', $newFormId);
651 +
528 652 wp_send_json([
529 - 'message' => __('Form has been successfully duplicated.', 'fluentform'),
530 - 'form_id' => $newFormId,
531 - 'redirect' => admin_url('admin.php?page=fluent_forms&route=editor&form_id=' . $newFormId)
653 + 'message' => __('Form has been successfully duplicated.', 'fluentform'),
654 + 'form_id' => $newFormId,
655 + 'redirect' => admin_url('admin.php?page=fluent_forms&route=editor&form_id=' . $newFormId),
532 656 ], 200);
533 657 }
534 658
535 659 /**
536 - * Validate a form only by form title
537 - * @return void
660 + * Validate a form by form title & for duplicate name attributes
538 661 */
539 662 private function validate()
540 663 {
541 - if (!$this->request->get('title')) {
664 + $fields = $this->request->get('formFields');
665 + if ($fields) {
666 + $duplicates = Helper::getDuplicateFieldNames($fields);
667 + if ($duplicates) {
668 + $duplicateString = implode(', ', $duplicates);
669 + wp_send_json([
670 + 'title' => sprintf('Name attribute %s has duplicate value.', $duplicateString),
671 + ], 422);
672 + }
673 +
674 + $duplicateRankingFields = Helper::getRankingFieldsWithDuplicateOptionValues($fields);
675 + if ($duplicateRankingFields) {
676 + $duplicateRankingFields = implode(', ', array_unique($duplicateRankingFields));
677 + wp_send_json([
678 + 'title' => sprintf(
679 + __('Ranking field %s has duplicate option values. Please make each option value unique.', 'fluentform'),
680 + $duplicateRankingFields
681 + ),
682 + ], 422);
683 + }
684 + }
685 +
686 + if (!sanitize_text_field($this->request->get('title'))) {
542 687 wp_send_json([
543 - 'title' => 'The title field is required.'
688 + 'title' => 'The title field is required.',
544 689 ], 422);
545 690 }
546 691 }
547 692
693 + public function convertToConversational()
694 + {
695 + $formId = $this->request->get('form_id');
696 + $form = $this->fetchForm($formId);
697 +
698 + if (!$form) {
699 + wp_send_json([
700 + 'message' => __('Form Not Found! Try Again.', 'fluentform'),
701 + ], 422);
702 + }
703 +
704 + $conversationalMeta = $this->getMeta($formId, 'is_conversion_form', false);
705 +
706 + $shouldConvert = in_array($conversationalMeta, [false, 'no']);
707 +
708 + if ($shouldConvert) {
709 + $formConverted['form_fields'] = \FluentForm\App\Services\FluentConversational\Classes\Converter\Converter::convertExistingForm($form);
710 +
711 + $this->model->where('id', $formId)->update($formConverted);
712 +
713 + $conversationalMetaValue = 'yes';
714 + } else {
715 + $conversationalMetaValue = 'no';
716 + }
717 +
718 + $this->updateMeta($formId, 'is_conversion_form', $conversationalMetaValue);
719 +
720 + wp_send_json_success([
721 + 'message' => __('Form has been successfully converted.', 'fluentform'),
722 + ], 200);
723 + }
724 +
548 725 private function getAdminPermalink($route, $form)
549 726 {
550 727 $baseUrl = admin_url('admin.php?page=fluent_forms');
551 728 return $baseUrl . '&route=' . $route . '&form_id=' . $form->id;
@@ -555,28 +732,156 @@
555 732 {
556 733 $baseUrl = admin_url('admin.php?page=fluent_forms');
557 734 return $baseUrl . '&form_id=' . $form->id . '&route=settings&sub_route=form_settings#basic_settings';
558 735 }
736 +
559 737
560 - public function getAllForms()
738 + /**
739 + * Map pdf feed ID to replace with duplicated PDF feed ID when duplicating form
740 + *
741 + * @param array $extras
742 + * @param array $newFormId
743 + *
744 + * @return array
745 + */
746 + private function getPdfFeedMap($extras, $newFormId)
561 747 {
562 - $fields = $this->request->get('fields');
748 + $pdfFeedMap = [];
749 + if (array_key_exists('_pdf_feeds', $extras)) {
750 + foreach ($extras['_pdf_feeds'] as $pdf_feed) {
751 + $pdfData = [
752 + 'meta_key' => $pdf_feed->meta_key,
753 + 'value' => $pdf_feed->value,
754 + 'form_id' => $newFormId,
755 + ];
756 + $pdfFeedMap[$pdf_feed->id] = wpFluent()->table('fluentform_form_meta')->insertGetId($pdfData);
757 + }
758 + }
759 + return $pdfFeedMap;
760 + }
563 761
564 - if ($fields) {
565 - $forms = $this->model
566 - ->select($fields)
567 - ->orderBy('created_at', 'DESC')->get();
568 - } else {
569 - $forms = $this->model->orderBy('created_at', 'DESC')->get();
762 + /**
763 + * Map notification data with PDF feed map
764 + *
765 + * @param array $extras
766 + * @param array $pdfFeedMap
767 + *
768 + * @return array
769 + */
770 + private function notificationWithPdfMap($extras, $pdfFeedMap)
771 + {
772 + foreach ($extras['notifications'] as $key => $notification) {
773 + $notificationValue = json_decode($notification->value);
774 + $pdf_attachments = [];
775 + if (isset($notificationValue->pdf_attachments) && count($notificationValue->pdf_attachments)) {
776 + foreach ($notificationValue->pdf_attachments as $attachment) {
777 + $pdf_attachments[] = json_encode($pdfFeedMap[$attachment]);
778 + }
779 + }
780 + $notificationValue->pdf_attachments = $pdf_attachments;
781 + $notification->value = json_encode($notificationValue);
782 +
783 + $extras['notifications'][$key] = $notification;
570 784 }
785 + return $extras;
786 + }
787 +
788 + public function findFormLocations()
789 + {
790 + $formId = intval($this->request->get('form_id'));
791 +
792 + $excluded = ['attachment'];
793 + $post_types = get_post_types(['show_in_menu' => true], 'objects', 'or');
794 + $postTypes = [];
795 + foreach($post_types as $post_type) {
796 + $postTypeName = $post_type->name;
797 + if (in_array($postTypeName, $excluded)) {
798 + continue;
799 + }
800 + $postTypes[] = $postTypeName;
801 + }
802 +
803 + $params = array(
804 + 'post_type' => $postTypes,
805 + 'posts_per_page' => -1
806 + );
807 +
808 + $params = apply_filters_deprecated(
809 + 'fluentform_find_shortcode_params',
810 + [
811 + $params
812 + ],
813 + FLUENTFORM_FRAMEWORK_UPGRADE,
814 + 'fluentform/find_shortcode_params',
815 + 'Use fluentform/find_shortcode_params instead of fluentform_find_shortcode_params.'
816 + );
571 817
572 - wp_send_json($forms, 200);
818 + $params = apply_filters('fluentform/find_shortcode_params', $params);
819 +
820 + $formLocations = [];
821 + $posts = get_posts($params);
822 + foreach($posts as $post) {
823 +
824 + $formIds = self::getShortCodeIds($post->post_content);
825 + if(!empty($formIds) && in_array($formId,$formIds)) {
826 +
827 + $postType = get_post_type_object($post->post_type);
828 + $formLocations[] = [
829 + 'id' => $post->ID,
830 + 'name' => $postType->labels->singular_name,
831 + 'title' => (empty($post->post_title) ? $post->ID : $post->post_title),
832 + 'edit_link' => sprintf("%spost.php?post=%s&action=edit", admin_url(), $post->ID),
833 + ];
834 + }
835 + }
836 + $data = [
837 + 'locations' => $formLocations,
838 + 'status' => !empty($formLocations),
839 + ];
840 + wp_send_json($data, 200);
841 +
573 842 }
843 +
844 + public static function getShortCodeIds($content)
845 + {
846 + $ids = [];
847 + $tag = 'fluentform';
848 + $selector = 'id';
849 +
850 + if (function_exists('parse_blocks')) {
851 + $parsedBlocks = parse_blocks($content);
852 + foreach ($parsedBlocks as $block) {
853 + if (!ArrayHelper::exists($block, 'blockName') || ArrayHelper::exists($block, 'attrs.formId')) {
854 + continue;
855 + }
856 + $hasBlock = strpos($block['blockName'], 'fluentfom/guten-block') === 0;
857 + if ($hasBlock) {
858 + $ids[] = intval($block['attrs']['formId']);
859 + }
860 + }
861 + }
574 862
575 - private function getUnreadCount($formId)
576 - {
577 - return wpFluent()->table('fluentform_submissions')
578 - ->where('status', 'unread')
579 - ->where('form_id', $formId)
580 - ->count();
863 + $hasShortCode = has_shortcode($content, $tag);
864 + if(!$hasShortCode){
865 + return $ids;
866 + }
867 +
868 + preg_match_all('/' . get_shortcode_regex() . '/', $content, $matches, PREG_SET_ORDER);
869 + if (empty($matches)) {
870 + return $ids;
871 + }
872 +
873 +
874 + foreach ($matches as $shortcode) {
875 + if (count($shortcode) >= 2 && $tag === $shortcode[2]) {
876 + $parsedCode = str_replace(['[', ']', '[', ']'], '', $shortcode[0]);
877 +
878 + $result = shortcode_parse_atts($parsedCode);
879 +
880 + if (!empty($result[$selector])) {
881 + $ids[] = $result[$selector];
882 + }
883 + }
884 + }
885 + return $ids;
581 886 }
582 887 }