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 +547 -229 3.6.516.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,30 +293,37 @@
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
316 + public function deleteMeta($formId, $metaKey)
317 + {
318 + return wpFluent()->table('fluentform_form_meta')
319 + ->where('form_id', $formId)
320 + ->where('meta_key', $metaKey)
321 + ->delete();
322 + }
323 +
344 324 /**
345 325 * Find/Read a from from the database
346 - * @return void
347 326 */
348 327 public function find()
349 328 {
350 329 $form = $this->fetchForm($this->request->get('formId'));
@@ -353,8 +332,9 @@
353 332
354 333 /**
355 334 * Fetch a from from the database
356 335 * Note: required for ninja-tables
336 + *
357 337 * @return mixed
358 338 */
359 339 public function fetchForm($formId)
360 340 {
@@ -362,28 +342,36 @@
362 342 }
363 343
364 344 /**
365 345 * Save/update a form from backend/editor
366 - * @return void
367 - * @throws \WpFluent\Exception
368 346 */
369 347 public function update()
370 348 {
371 349 $formId = $this->request->get('formId');
372 - $title = $this->request->get('title');
350 + $title = sanitize_text_field($this->request->get('title'));
373 351 $status = $this->request->get('status', 'published');
374 352
375 353 $this->validate();
376 354
377 355 $data = [
378 - 'title' => $title,
379 - 'status' => $status,
380 - 'updated_at' => current_time('mysql')
356 + 'title' => $title,
357 + 'status' => $status,
358 + 'updated_at' => current_time('mysql'),
381 359 ];
382 360
383 -
384 361 if ($formFields = $this->request->get('formFields')) {
385 - $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);
386 374 $data['form_fields'] = $formFields;
387 375 }
388 376
389 377 $this->model->where('id', $formId)->update($data);
@@ -391,25 +379,141 @@
391 379 $form = $this->fetchForm($formId);
392 380
393 381 if (FormFieldsParser::hasPaymentFields($form)) {
394 382 $this->model->where('id', $formId)->update([
395 - 'has_payment' => 1
383 + 'has_payment' => 1,
396 384 ]);
397 - } else if ($form->has_payment) {
385 + } elseif ($form->has_payment) {
398 386 $this->model->where('id', $formId)->update([
399 - 'has_payment' => 0
387 + 'has_payment' => 0,
400 388 ]);
401 389 }
402 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 +
403 400 wp_send_json([
404 - 'message' => __('The form is successfully updated.', 'fluentform')
401 + 'message' => __('The form is successfully updated.', 'fluentform'),
405 402 ], 200);
406 403 }
407 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 +
408 514 /**
409 515 * Delete a from from database
410 - * @return void
411 - * @throws \WpFluent\Exception
412 516 */
413 517 public function delete()
414 518 {
415 519 $formId = $this->request->get('formId');
@@ -415,9 +519,18 @@
415 519 $formId = $this->request->get('formId');
416 520
417 521 $this->model->where('id', $formId)->delete();
418 522
523 + $maybeErrors = $this->deleteFormAssests($formId);
419 524
525 + wp_send_json([
526 + 'message' => __('Successfully deleted the form.', 'fluentform'),
527 + 'errors' => $maybeErrors,
528 + ], 200);
529 + }
530 +
531 + protected function deleteFormAssests($formId)
532 + {
420 533 // Now Let's delete associate items
421 534 wpFluent()->table('fluentform_submissions')
422 535 ->where('form_id', $formId)
423 536 ->delete();
@@ -429,8 +542,12 @@
429 542 wpFluent()->table('fluentform_entry_details')
430 543 ->where('form_id', $formId)
431 544 ->delete();
432 545
546 + wpFluent()->table('fluentform_form_meta')
547 + ->where('form_id', $formId)
548 + ->delete();
549 +
433 550 wpFluent()->table('fluentform_form_analytics')
434 551 ->where('form_id', $formId)
435 552 ->delete();
436 553
@@ -435,39 +552,26 @@
435 552 ->delete();
436 553
437 554 wpFluent()->table('fluentform_logs')
438 555 ->where('parent_source_id', $formId)
439 - ->whereIn('source_type', ['submission_item', 'form_item'])
556 + ->whereIn('source_type', ['submission_item', 'form_item', 'draft_submission_meta'])
440 557 ->delete();
441 558
442 559 ob_start();
443 - if (defined('FLUENTFORMPRO')) {
560 + if (PaymentHelper::hasPaymentSettings()) {
444 561 try {
445 - wpFluent()->table('fluentform_order_items')
446 - ->where('form_id', $formId)
447 - ->delete();
448 - wpFluent()->table('fluentform_subscriptions')
449 - ->where('form_id', $formId)
450 - ->delete();
451 - wpFluent()->table('fluentform_transactions')
452 - ->where('form_id', $formId)
453 - ->delete();
562 + \FluentForm\App\Models\OrderItem::where('form_id', $formId)->delete();
563 + \FluentForm\App\Models\Transaction::where('form_id', $formId)->delete();
454 564 } catch (\Exception $exception) {
455 -
456 565 }
457 566 }
567 +
458 568 $errors = ob_get_clean();
459 -
460 - wp_send_json([
461 - 'message' => __('Successfully deleted the form.', 'fluentform'),
462 - 'errors' => $errors
463 - ], 200);
569 + return $errors;
464 570 }
465 571
466 572 /**
467 573 * Duplicate a from
468 - * @return void
469 - * @throws \WpFluent\Exception
470 574 */
471 575 public function duplicate()
472 576 {
473 577 $formId = absint($this->request->get('formId'));
@@ -472,29 +576,29 @@
472 576 {
473 577 $formId = absint($this->request->get('formId'));
474 578 $form = $this->model->where('id', $formId)->first();
475 579
476 - $data = array(
477 - 'title' => $form->title,
478 - 'status' => $form->status,
580 + $data = [
581 + 'title' => $form->title,
582 + 'status' => $form->status,
479 583 'appearance_settings' => $form->appearance_settings,
480 - 'form_fields' => $form->form_fields,
481 - 'type' => $form->type,
482 - 'has_payment' => $form->has_payment,
483 - 'conditions' => $form->conditions,
484 - 'created_by' => get_current_user_id(),
485 - 'created_at' => current_time('mysql'),
486 - 'updated_at' => current_time('mysql')
487 - );
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 + ];
488 592
489 - $newFormId = $this->model->insert($data);
593 + $newFormId = $this->model->insertGetId($data);
490 594
491 - // Ranme the form name here
595 + // Rename the form name here
492 596 wpFluent()->table('fluentform_forms')
493 597 ->where('id', $newFormId)
494 - ->update(array(
495 - 'title' => $form->title . ' (#' . $newFormId . ')'
496 - ));
598 + ->update([
599 + 'title' => $form->title . ' (#' . $newFormId . ')',
600 + ]);
497 601
498 602 $formMetas = wpFluent()->table('fluentform_form_meta')
499 603 ->where('form_id', $formId)
500 604 ->whereNot('meta_key', ['_total_views'])
@@ -499,40 +603,126 @@
499 603 ->where('form_id', $formId)
500 604 ->whereNot('meta_key', ['_total_views'])
501 605 ->get();
502 606
607 + // Required for duplicating PDF feeds
608 + $extras = [];
609 +
503 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 + }
504 618 $metaData = [
505 619 'meta_key' => $meta->meta_key,
506 - 'value' => $meta->value,
507 - 'form_id' => $newFormId
620 + 'value' => $meta->value,
621 + 'form_id' => $newFormId,
508 622 ];
509 623
510 624 wpFluent()->table('fluentform_form_meta')->insert($metaData);
511 625 }
512 626
513 - 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 + }
514 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 +
515 652 wp_send_json([
516 - 'message' => __('Form has been successfully duplicated.', 'fluentform'),
517 - 'form_id' => $newFormId,
518 - '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),
519 656 ], 200);
520 657 }
521 658
522 659 /**
523 - * Validate a form only by form title
524 - * @return void
660 + * Validate a form by form title & for duplicate name attributes
525 661 */
526 662 private function validate()
527 663 {
528 - 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'))) {
529 687 wp_send_json([
530 - 'title' => 'The title field is required.'
688 + 'title' => 'The title field is required.',
531 689 ], 422);
532 690 }
533 691 }
534 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 +
535 725 private function getAdminPermalink($route, $form)
536 726 {
537 727 $baseUrl = admin_url('admin.php?page=fluent_forms');
538 728 return $baseUrl . '&route=' . $route . '&form_id=' . $form->id;
@@ -542,28 +732,156 @@
542 732 {
543 733 $baseUrl = admin_url('admin.php?page=fluent_forms');
544 734 return $baseUrl . '&form_id=' . $form->id . '&route=settings&sub_route=form_settings#basic_settings';
545 735 }
736 +
546 737
547 - 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)
548 747 {
549 - $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 + }
550 761
551 - if ($fields) {
552 - $forms = $this->model
553 - ->select($fields)
554 - ->orderBy('created_at', 'DESC')->get();
555 - } else {
556 - $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;
557 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 + );
558 817
559 - 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 +
560 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 + }
561 862
562 - private function getUnreadCount($formId)
563 - {
564 - return wpFluent()->table('fluentform_submissions')
565 - ->where('status', 'unread')
566 - ->where('form_id', $formId)
567 - ->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;
568 886 }
569 887 }