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 -226 3.6.316.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,90 +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 - $query = wpFluent()->table('fluentform_forms')
69 - ->orderBy('id', 'DESC');
70 -
71 - if ($status && $status != 'all') {
72 - $query->where('status', $status);
73 - }
74 -
75 - if ($search) {
76 - $query->where(function ($q) use ($search) {
77 - $q->where('id', 'LIKE', '%' . $search . '%');
78 - $q->orWhere('title', 'LIKE', '%' . $search . '%');
79 - });
80 - }
81 -
82 - $forms = $query->paginate();
83 -
84 - foreach ($forms['data'] as $form) {
85 - $form->preview_url = site_url('?fluentform_pages=1&preview_id=' . $form->id) . '#ff_preview';;
86 - $form->edit_url = $this->getAdminPermalink('editor', $form);
87 - $form->settings_url = $this->getSettingsUrl($form);
88 - $form->entries_url = $this->getAdminPermalink('entries', $form);
89 - $form->analytics_url = $this->getAdminPermalink('analytics', $form);
90 - $form->total_views = $this->getFormViewCount($form->id);
91 - $form->total_views = $this->getFormViewCount($form->id);
92 - $form->total_Submissions = $this->getSubmissionCount($form->id);
93 - $form->unread_count = $this->getUnreadCount($form->id);
94 - $form->conversion = $this->getConversionRate($form);
95 - unset($form->form_fields);
96 - }
97 -
98 79 wp_send_json($forms, 200);
99 80 }
100 81
101 - private function getFormViewCount($formId)
102 - {
103 - $hasCount = wpFluent()
104 - ->table('fluentform_form_meta')
105 - ->where('meta_key', '_total_views')
106 - ->where('form_id', $formId)
107 - ->first();
108 -
109 - if ($hasCount) {
110 - return intval($hasCount->value);
111 - }
112 -
113 - return 0;
114 - }
115 -
116 - private function getSubmissionCount($formID)
117 - {
118 - return wpFluent()
119 - ->table('fluentform_submissions')
120 - ->where('form_id', $formID)
121 - ->where('status', '!=', 'trashed')
122 - ->count();
123 - }
124 -
125 - private function getConversionRate($form)
126 - {
127 - if (!$form->total_Submissions)
128 - return 0;
129 -
130 - if (!$form->total_views)
131 - return 0;
132 -
133 - return ceil(($form->total_Submissions / $form->total_views) * 100);
134 - }
135 -
136 82 /**
137 83 * Create a form from backend/editor
138 - * @return void
84 + *
85 + * @return void|array
139 86 */
140 - public function store()
87 + public function store($returnJSON = true)
141 88 {
142 89 $type = $this->request->get('type', $this->formType);
143 90 $title = $this->request->get('title', 'My New Form');
144 91 $status = $this->request->get('status', 'published');
@@ -146,14 +93,14 @@
146 93
147 94 $now = current_time('mysql');
148 95
149 96 $insertData = [
150 - 'title' => $title,
151 - 'type' => $type,
152 - 'status' => $status,
97 + 'title' => $title,
98 + 'type' => $type,
99 + 'status' => $status,
153 100 'created_by' => $createdBy,
154 101 'created_at' => $now,
155 - 'updated_at' => $now
102 + 'updated_at' => $now,
156 103 ];
157 104
158 105 if ($this->formFields) {
159 106 $insertData['form_fields'] = $this->formFields;
@@ -158,104 +105,132 @@
158 105 if ($this->formFields) {
159 106 $insertData['form_fields'] = $this->formFields;
160 107 }
161 108
162 - if($this->hasPayment) {
109 + if ($this->hasPayment) {
163 110 $insertData['has_payment'] = $this->hasPayment;
164 111 }
165 112
166 - $formId = $this->model->insert($insertData);
113 + $formId = $this->model->insertGetId($insertData);
167 114
168 115 // Rename the form name here
169 - wpFluent()->table('fluentform_forms')->where('id', $formId)->update(array(
170 - 'title' => $title . ' (#' . $formId . ')'
171 - ));
116 + wpFluent()->table('fluentform_forms')->where('id', $formId)->update([
117 + 'title' => $title . ' (#' . $formId . ')',
118 + ]);
172 119
173 - if($this->metas && is_array($this->metas)) {
120 + if ($this->metas && is_array($this->metas)) {
174 121 foreach ($this->metas as $meta) {
175 122 $meta['value'] = trim(preg_replace('/\s+/', ' ', $meta['value']));
176 123
177 124 wpFluent()->table('fluentform_form_meta')
178 - ->insert(array(
179 - 'form_id' => $formId,
125 + ->insert([
126 + 'form_id' => $formId,
180 127 'meta_key' => $meta['meta_key'],
181 - 'value' => $meta['value']
182 - ));
128 + 'value' => $meta['value'],
129 + ]);
183 130 }
184 131 } else {
185 132 // add default form settings now
186 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 + );
187 144
188 - $defaultSettings = apply_filters('fluentform_create_default_settings', $defaultSettings);
145 + $defaultSettings = apply_filters('fluentform/create_default_settings', $defaultSettings);
189 146
190 147 wpFluent()->table('fluentform_form_meta')
191 - ->insert(array(
192 - 'form_id' => $formId,
148 + ->insert([
149 + 'form_id' => $formId,
193 150 'meta_key' => 'formSettings',
194 - 'value' => json_encode($defaultSettings)
195 - ));
151 + 'value' => json_encode($defaultSettings),
152 + ]);
196 153
197 154 if ($this->defaultNotifications) {
198 155 wpFluent()->table('fluentform_form_meta')
199 - ->insert(array(
200 - 'form_id' => $formId,
156 + ->insert([
157 + 'form_id' => $formId,
201 158 'meta_key' => 'notifications',
202 - 'value' => json_encode($this->defaultNotifications)
203 - ));
159 + 'value' => json_encode($this->defaultNotifications),
160 + ]);
204 161 }
205 162 }
206 163
207 - 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 + );
208 174
209 - wp_send_json_success(array(
210 - 'formId' => $formId,
175 + do_action('fluentform/inserted_new_form', $formId, $insertData);
176 +
177 + $data = [
178 + 'formId' => $formId,
211 179 'redirect_url' => admin_url('admin.php?page=fluent_forms&form_id=' . $formId . '&route=editor'),
212 - 'message' => __('Successfully created a form.', 'fluentform')
213 - ), 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;
214 188 }
215 189
216 190 public function getFormsDefaultSettings($formId = false)
217 191 {
218 - $defaultSettings = array(
219 - 'confirmation' => array(
220 - 'redirectTo' => 'samePage',
221 - 'messageToShow' => __('Thank you for your message. We will get in touch with you shortly', 'fluentform'),
222 - '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,
223 197 'samePageFormBehavior' => 'hide_form',
224 - 'customUrl' => null
225 - ),
226 - 'restrictions' => array(
227 - 'limitNumberOfEntries' => array(
228 - 'enabled' => false,
198 + 'customUrl' => null,
199 + ],
200 + 'restrictions' => [
201 + 'limitNumberOfEntries' => [
202 + 'enabled' => false,
229 203 'numberOfEntries' => null,
230 - 'period' => 'total',
231 - 'limitReachedMsg' => 'Maximum number of entries exceeded.'
232 - ),
233 - 'scheduleForm' => array(
234 - 'enabled' => false,
235 - 'start' => null,
236 - 'end' => null,
237 - 'pendingMsg' => __("Form submission is not started yet.", 'fluentform'),
238 - 'expiredMsg' => __("Form submission is now closed.", 'fluentform')
239 - ),
240 - 'requireLogin' => array(
241 - '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,
242 217 'requireLoginMsg' => 'You must be logged in to submit the form.',
243 - ),
218 + ],
244 219 'denyEmptySubmission' => [
245 220 'enabled' => false,
246 221 'message' => __('Sorry, you cannot submit an empty form. Let\'s hear what you wanna say.', 'fluentform'),
247 - ]
248 - ),
249 - 'layout' => array(
250 - 'labelPlacement' => 'top',
251 - 'helpMessagePlacement' => 'with_label',
222 + ],
223 + ],
224 + 'layout' => [
225 + 'labelPlacement' => 'top',
226 + 'helpMessagePlacement' => 'with_label',
252 227 'errorMessagePlacement' => 'inline',
253 - 'cssClassName' => '',
254 - 'asteriskPlacement' => 'asterisk-right'
255 - ),
256 - 'delete_entry_on_submission' => 'no'
257 - );
228 + 'cssClassName' => '',
229 + 'asteriskPlacement' => 'asterisk-right'
230 + ],
231 + 'delete_entry_on_submission' => 'no',
232 + ];
258 233
259 234 if ($formId) {
260 235 $value = $this->getMeta($formId, 'formSettings', true);
261 236 if ($value) {
@@ -273,24 +248,24 @@
273 248
274 249 public function getAdvancedValidationSettings($formId)
275 250 {
276 251 $settings = [
277 - 'status' => false,
278 - 'type' => 'all',
252 + 'status' => false,
253 + 'type' => 'all',
279 254 'conditions' => [
280 255 [
281 - 'field' => '',
256 + 'field' => '',
282 257 'operator' => '=',
283 - 'value' => ''
284 - ]
258 + 'value' => '',
259 + ],
285 260 ],
286 - 'error_message' => '',
287 - 'validation_type' => 'fail_on_condition_met'
261 + 'error_message' => '',
262 + 'validation_type' => 'fail_on_condition_met',
288 263 ];
289 264
290 265 $metaSettings = $this->getMeta($formId, 'advancedValidationSettings', true);
291 266
292 - if($metaSettings && is_array($metaSettings)) {
267 + if ($metaSettings && is_array($metaSettings)) {
293 268 $settings = wp_parse_args($metaSettings, $settings);
294 269 }
295 270
296 271 return $settings;
@@ -302,9 +277,9 @@
302 277 ->where('form_id', $formId)
303 278 ->where('meta_key', $metaKey)
304 279 ->first();
305 280 if ($settingsMeta) {
306 - if($isJson) {
281 + if ($isJson) {
307 282 return \json_decode($settingsMeta->value, true);
308 283 } else {
309 284 return $settingsMeta->value;
310 285 }
@@ -318,30 +293,37 @@
318 293 ->where('form_id', $formId)
319 294 ->where('meta_key', $metaKey)
320 295 ->first();
321 296
322 - if(is_array($metaValue) || is_object($metaValue)) {
297 + if (is_array($metaValue) || is_object($metaValue)) {
323 298 $metaValue = \json_encode($metaValue);
324 299 }
325 300
326 - if($exist) {
301 + if ($exist) {
327 302 return wpFluent()->table('fluentform_form_meta')
328 303 ->where('id', $exist->id)
329 304 ->update([
330 - 'value' => $metaValue
305 + 'value' => $metaValue,
331 306 ]);
332 307 }
333 308
334 - return wpFluent()->table('fluentform_form_meta')->insert([
335 - 'form_id' => $formId,
309 + return wpFluent()->table('fluentform_form_meta')->insertGetId([
310 + 'form_id' => $formId,
336 311 'meta_key' => $metaKey,
337 - 'value' => $metaValue
312 + 'value' => $metaValue,
338 313 ]);
339 314 }
340 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 +
341 324 /**
342 325 * Find/Read a from from the database
343 - * @return void
344 326 */
345 327 public function find()
346 328 {
347 329 $form = $this->fetchForm($this->request->get('formId'));
@@ -350,8 +332,9 @@
350 332
351 333 /**
352 334 * Fetch a from from the database
353 335 * Note: required for ninja-tables
336 + *
354 337 * @return mixed
355 338 */
356 339 public function fetchForm($formId)
357 340 {
@@ -359,28 +342,36 @@
359 342 }
360 343
361 344 /**
362 345 * Save/update a form from backend/editor
363 - * @return void
364 - * @throws \WpFluent\Exception
365 346 */
366 347 public function update()
367 348 {
368 349 $formId = $this->request->get('formId');
369 - $title = $this->request->get('title');
350 + $title = sanitize_text_field($this->request->get('title'));
370 351 $status = $this->request->get('status', 'published');
371 352
372 353 $this->validate();
373 354
374 355 $data = [
375 - 'title' => $title,
376 - 'status' => $status,
377 - 'updated_at' => current_time('mysql')
356 + 'title' => $title,
357 + 'status' => $status,
358 + 'updated_at' => current_time('mysql'),
378 359 ];
379 360
380 -
381 361 if ($formFields = $this->request->get('formFields')) {
382 - $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);
383 374 $data['form_fields'] = $formFields;
384 375 }
385 376
386 377 $this->model->where('id', $formId)->update($data);
@@ -388,25 +379,141 @@
388 379 $form = $this->fetchForm($formId);
389 380
390 381 if (FormFieldsParser::hasPaymentFields($form)) {
391 382 $this->model->where('id', $formId)->update([
392 - 'has_payment' => 1
383 + 'has_payment' => 1,
393 384 ]);
394 - } else if ($form->has_payment) {
385 + } elseif ($form->has_payment) {
395 386 $this->model->where('id', $formId)->update([
396 - 'has_payment' => 0
387 + 'has_payment' => 0,
397 388 ]);
398 389 }
399 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 +
400 400 wp_send_json([
401 - 'message' => __('The form is successfully updated.', 'fluentform')
401 + 'message' => __('The form is successfully updated.', 'fluentform'),
402 402 ], 200);
403 403 }
404 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 +
405 514 /**
406 515 * Delete a from from database
407 - * @return void
408 - * @throws \WpFluent\Exception
409 516 */
410 517 public function delete()
411 518 {
412 519 $formId = $this->request->get('formId');
@@ -412,9 +519,18 @@
412 519 $formId = $this->request->get('formId');
413 520
414 521 $this->model->where('id', $formId)->delete();
415 522
523 + $maybeErrors = $this->deleteFormAssests($formId);
416 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 + {
417 533 // Now Let's delete associate items
418 534 wpFluent()->table('fluentform_submissions')
419 535 ->where('form_id', $formId)
420 536 ->delete();
@@ -426,8 +542,12 @@
426 542 wpFluent()->table('fluentform_entry_details')
427 543 ->where('form_id', $formId)
428 544 ->delete();
429 545
546 + wpFluent()->table('fluentform_form_meta')
547 + ->where('form_id', $formId)
548 + ->delete();
549 +
430 550 wpFluent()->table('fluentform_form_analytics')
431 551 ->where('form_id', $formId)
432 552 ->delete();
433 553
@@ -432,39 +552,26 @@
432 552 ->delete();
433 553
434 554 wpFluent()->table('fluentform_logs')
435 555 ->where('parent_source_id', $formId)
436 - ->whereIn('source_type', ['submission_item', 'form_item'])
556 + ->whereIn('source_type', ['submission_item', 'form_item', 'draft_submission_meta'])
437 557 ->delete();
438 558
439 559 ob_start();
440 - if (defined('FLUENTFORMPRO')) {
560 + if (PaymentHelper::hasPaymentSettings()) {
441 561 try {
442 - wpFluent()->table('fluentform_order_items')
443 - ->where('form_id', $formId)
444 - ->delete();
445 - wpFluent()->table('fluentform_subscriptions')
446 - ->where('form_id', $formId)
447 - ->delete();
448 - wpFluent()->table('fluentform_transactions')
449 - ->where('form_id', $formId)
450 - ->delete();
562 + \FluentForm\App\Models\OrderItem::where('form_id', $formId)->delete();
563 + \FluentForm\App\Models\Transaction::where('form_id', $formId)->delete();
451 564 } catch (\Exception $exception) {
452 -
453 565 }
454 566 }
567 +
455 568 $errors = ob_get_clean();
456 -
457 - wp_send_json([
458 - 'message' => __('Successfully deleted the form.', 'fluentform'),
459 - 'errors' => $errors
460 - ], 200);
569 + return $errors;
461 570 }
462 571
463 572 /**
464 573 * Duplicate a from
465 - * @return void
466 - * @throws \WpFluent\Exception
467 574 */
468 575 public function duplicate()
469 576 {
470 577 $formId = absint($this->request->get('formId'));
@@ -469,29 +576,29 @@
469 576 {
470 577 $formId = absint($this->request->get('formId'));
471 578 $form = $this->model->where('id', $formId)->first();
472 579
473 - $data = array(
474 - 'title' => $form->title,
475 - 'status' => $form->status,
580 + $data = [
581 + 'title' => $form->title,
582 + 'status' => $form->status,
476 583 'appearance_settings' => $form->appearance_settings,
477 - 'form_fields' => $form->form_fields,
478 - 'type' => $form->type,
479 - 'has_payment' => $form->has_payment,
480 - 'conditions' => $form->conditions,
481 - 'created_by' => get_current_user_id(),
482 - 'created_at' => current_time('mysql'),
483 - 'updated_at' => current_time('mysql')
484 - );
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 + ];
485 592
486 - $newFormId = $this->model->insert($data);
593 + $newFormId = $this->model->insertGetId($data);
487 594
488 - // Ranme the form name here
595 + // Rename the form name here
489 596 wpFluent()->table('fluentform_forms')
490 597 ->where('id', $newFormId)
491 - ->update(array(
492 - 'title' => $form->title . ' (#' . $newFormId . ')'
493 - ));
598 + ->update([
599 + 'title' => $form->title . ' (#' . $newFormId . ')',
600 + ]);
494 601
495 602 $formMetas = wpFluent()->table('fluentform_form_meta')
496 603 ->where('form_id', $formId)
497 604 ->whereNot('meta_key', ['_total_views'])
@@ -496,40 +603,126 @@
496 603 ->where('form_id', $formId)
497 604 ->whereNot('meta_key', ['_total_views'])
498 605 ->get();
499 606
607 + // Required for duplicating PDF feeds
608 + $extras = [];
609 +
500 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 + }
501 618 $metaData = [
502 619 'meta_key' => $meta->meta_key,
503 - 'value' => $meta->value,
504 - 'form_id' => $newFormId
620 + 'value' => $meta->value,
621 + 'form_id' => $newFormId,
505 622 ];
506 623
507 624 wpFluent()->table('fluentform_form_meta')->insert($metaData);
508 625 }
509 626
510 - 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 + }
511 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 +
512 652 wp_send_json([
513 - 'message' => __('Form has been successfully duplicated.', 'fluentform'),
514 - 'form_id' => $newFormId,
515 - '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),
516 656 ], 200);
517 657 }
518 658
519 659 /**
520 - * Validate a form only by form title
521 - * @return void
660 + * Validate a form by form title & for duplicate name attributes
522 661 */
523 662 private function validate()
524 663 {
525 - 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'))) {
526 687 wp_send_json([
527 - 'title' => 'The title field is required.'
688 + 'title' => 'The title field is required.',
528 689 ], 422);
529 690 }
530 691 }
531 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 +
532 725 private function getAdminPermalink($route, $form)
533 726 {
534 727 $baseUrl = admin_url('admin.php?page=fluent_forms');
535 728 return $baseUrl . '&route=' . $route . '&form_id=' . $form->id;
@@ -539,28 +732,156 @@
539 732 {
540 733 $baseUrl = admin_url('admin.php?page=fluent_forms');
541 734 return $baseUrl . '&form_id=' . $form->id . '&route=settings&sub_route=form_settings#basic_settings';
542 735 }
736 +
543 737
544 - 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)
545 747 {
546 - $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 + }
547 761
548 - if ($fields) {
549 - $forms = $this->model
550 - ->select($fields)
551 - ->orderBy('created_at', 'DESC')->get();
552 - } else {
553 - $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;
554 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 + );
555 817
556 - 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 +
557 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 + }
558 862
559 - private function getUnreadCount($formId)
560 - {
561 - return wpFluent()->table('fluentform_submissions')
562 - ->where('status', 'unread')
563 - ->where('form_id', $formId)
564 - ->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;
565 886 }
566 887 }